Futures visualizer - reorganize modules, expose formerly private stuff as public (and docs)
This commit is contained in:
parent
2b2070f7b2
commit
dbec8765e3
|
@ -1,14 +1,15 @@
|
|||
#lang racket
|
||||
(require rackunit)
|
||||
(require rackunit
|
||||
"constants.rkt")
|
||||
(provide (struct-out point)
|
||||
(struct-out node)
|
||||
(struct-out drawable-node)
|
||||
(struct-out graph-layout)
|
||||
(struct-out graph-layout)
|
||||
(struct-out attributed-node)
|
||||
draw-tree
|
||||
drawable-node-center)
|
||||
drawable-node-center
|
||||
build-attr-tree)
|
||||
|
||||
(define DEFAULT-WIDTH 10)
|
||||
(define PADDING 5)
|
||||
(define-struct/contract point ([x integer?] [y integer?]) #:transparent)
|
||||
(struct node (data children))
|
||||
(struct graph-layout (width height nodes) #:transparent)
|
||||
|
@ -169,8 +170,8 @@
|
|||
;;draw-tree : node [symbol] [uint] [uint] [uint] -> tree-layout
|
||||
(define (draw-tree root
|
||||
#:style [style 'standard]
|
||||
#:node-width [node-width DEFAULT-WIDTH]
|
||||
#:padding [padding PADDING]
|
||||
#:node-width [node-width CREATE-GRAPH-NODE-DIAMETER]
|
||||
#:padding [padding CREATE-GRAPH-PADDING]
|
||||
#:zoom [zoom-level 1])
|
||||
(let* ([scaled-node-w (* node-width zoom-level)]
|
||||
[scaled-padding (* padding zoom-level)]
|
||||
|
@ -193,248 +194,4 @@
|
|||
(error 'draw-tree "Invalid tree drawing style.")])])
|
||||
(graph-layout (+ (graph-layout-width layout) scaled-padding)
|
||||
(+ (graph-layout-height layout) scaled-padding)
|
||||
(graph-layout-nodes layout))))
|
||||
|
||||
|
||||
;Tests
|
||||
(let* ([nodea (drawable-node (node 'a '()) 5 5 10 0 0 '() 10)]
|
||||
[center (drawable-node-center nodea)])
|
||||
(check-equal? (point-x center) 10.0)
|
||||
(check-equal? (point-y center) 10.0))
|
||||
|
||||
|
||||
(define test-padding 5)
|
||||
(define test-width 10)
|
||||
|
||||
(define (tree root-data . children)
|
||||
(node root-data children))
|
||||
|
||||
(define (get-node data layout)
|
||||
(first (filter (λ (dn) (equal? (node-data (drawable-node-node dn)) data)) (graph-layout-nodes layout))))
|
||||
|
||||
#|
|
||||
a
|
||||
|
|
||||
b
|
||||
|#
|
||||
(define tree0 (tree 'a (tree 'b)))
|
||||
(let* ([layout (draw-tree tree0 #:node-width test-width #:padding test-padding)]
|
||||
[dnode-a (get-node 'a layout)]
|
||||
[dnode-b (get-node 'b layout)])
|
||||
(check-equal? (graph-layout-width layout) (+ (* test-padding 2) test-width))
|
||||
(check-equal? (graph-layout-height layout) (+ (* test-padding 3) (* test-width 2)))
|
||||
(check-equal? (drawable-node-x dnode-a) test-padding)
|
||||
(check-equal? (drawable-node-y dnode-a) test-padding)
|
||||
(check-equal? (drawable-node-x dnode-b) test-padding)
|
||||
(check-equal? (drawable-node-y dnode-b) (+ test-padding test-width test-padding)))
|
||||
(let ([atree (build-attr-tree tree0 0)])
|
||||
(check-equal? (attributed-node-num-leaves atree) 1))
|
||||
|
||||
#|
|
||||
a
|
||||
/ \
|
||||
b c
|
||||
|#
|
||||
(define tree1 (tree 'a
|
||||
(tree 'b)
|
||||
(tree 'c)))
|
||||
(define layout (draw-tree tree1 #:node-width test-width #:padding test-padding))
|
||||
(for ([dnode (in-list (graph-layout-nodes layout))])
|
||||
(check-equal? (drawable-node-width dnode) test-width))
|
||||
(define dnode-a (get-node 'a layout))
|
||||
(define dnode-b (get-node 'b layout))
|
||||
(define dnode-c (get-node 'c layout))
|
||||
|
||||
(define slot-one-pos (+ test-padding test-width test-padding))
|
||||
(define square-sz (+ (* test-padding 3) (* test-width 2)))
|
||||
(check-equal? (graph-layout-width layout) square-sz)
|
||||
(check-equal? (graph-layout-height layout) square-sz)
|
||||
(check-equal? (drawable-node-x dnode-b) test-padding)
|
||||
(check-equal? (drawable-node-y dnode-b) slot-one-pos)
|
||||
(check-equal? (drawable-node-x dnode-c) slot-one-pos)
|
||||
(check-equal? (drawable-node-y dnode-c) slot-one-pos)
|
||||
(check-equal? (drawable-node-x dnode-a) (/ 25 2))
|
||||
(check-equal? (drawable-node-y dnode-a) test-padding)
|
||||
(check-equal? (length (drawable-node-children dnode-a)) 2)
|
||||
(let ([atree (build-attr-tree tree1 0)])
|
||||
(check-equal? (attributed-node-num-leaves atree) 2))
|
||||
|
||||
#|
|
||||
a
|
||||
/ \
|
||||
b d
|
||||
| / \
|
||||
c e f
|
||||
|
|
||||
g
|
||||
|#
|
||||
(define tree2 (tree 'a
|
||||
(tree 'b
|
||||
(tree 'c))
|
||||
(tree 'd
|
||||
(tree 'e)
|
||||
(tree 'f
|
||||
(tree 'g)))))
|
||||
(let* ([layout (draw-tree tree2 #:node-width test-width #:padding test-padding)]
|
||||
[nodes (graph-layout-nodes layout)]
|
||||
[dnode-a (get-node 'a layout)]
|
||||
[dnode-b (get-node 'b layout)]
|
||||
[dnode-c (get-node 'c layout)]
|
||||
[dnode-d (get-node 'd layout)]
|
||||
[dnode-e (get-node 'e layout)]
|
||||
[dnode-f (get-node 'f layout)]
|
||||
[dnode-g (get-node 'g layout)])
|
||||
(check-equal? (node-data (drawable-node-node dnode-a)) 'a)
|
||||
(check-equal? (node-data (drawable-node-node dnode-b)) 'b)
|
||||
(check-equal? (node-data (drawable-node-node dnode-c)) 'c)
|
||||
(check-equal? (node-data (drawable-node-node dnode-d)) 'd)
|
||||
(check-equal? (node-data (drawable-node-node dnode-e)) 'e)
|
||||
(check-equal? (node-data (drawable-node-node dnode-f)) 'f)
|
||||
(check-equal? (node-data (drawable-node-node dnode-g)) 'g)
|
||||
(check-equal? (graph-layout-width layout) 50)
|
||||
(check-equal? (graph-layout-height layout) 65)
|
||||
(check-equal? (drawable-node-x dnode-a) (/ 65 4))
|
||||
(check-equal? (drawable-node-y dnode-a) test-padding)
|
||||
(check-equal? (drawable-node-x dnode-b) test-padding)
|
||||
(check-equal? (drawable-node-y dnode-b) (+ (* 2 test-padding) test-width))
|
||||
(check-equal? (drawable-node-x dnode-c) test-padding)
|
||||
(check-equal? (drawable-node-y dnode-c) (+ (drawable-node-y dnode-b) test-width test-padding))
|
||||
(check-equal? (drawable-node-x dnode-e) (+ (* 2 test-padding) test-width))
|
||||
(check-equal? (drawable-node-y dnode-e) (+ (drawable-node-y dnode-d) test-width test-padding))
|
||||
(check-equal? (drawable-node-x dnode-f) (+ (drawable-node-x dnode-e) test-width test-padding))
|
||||
(check-equal? (drawable-node-y dnode-f) (drawable-node-y dnode-e))
|
||||
(check-equal? (drawable-node-x dnode-g) (drawable-node-x dnode-f))
|
||||
(check-equal? (drawable-node-y dnode-g) (+ (drawable-node-y dnode-f) test-width test-padding)))
|
||||
(let ([atree (build-attr-tree tree2 0)])
|
||||
(check-equal? (attributed-node-num-leaves atree) 3))
|
||||
|
||||
#|
|
||||
a
|
||||
/|\
|
||||
b c e
|
||||
|
|
||||
d
|
||||
|#
|
||||
(define tree3 (tree 'a
|
||||
(tree 'b)
|
||||
(tree 'c
|
||||
(tree 'd))
|
||||
(tree 'e)))
|
||||
(let* ([layout (draw-tree tree3 #:node-width test-width #:padding test-padding)]
|
||||
[nodes (graph-layout-nodes layout)]
|
||||
[dnode-a (get-node 'a layout)]
|
||||
[dnode-b (get-node 'b layout)]
|
||||
[dnode-c (get-node 'c layout)]
|
||||
[dnode-d (get-node 'd layout)]
|
||||
[dnode-e (get-node 'e layout)])
|
||||
(check-equal? (graph-layout-width layout) 50)
|
||||
(check-equal? (graph-layout-height layout) 50)
|
||||
(check-equal? (drawable-node-x dnode-a) 20)
|
||||
(check-equal? (drawable-node-y dnode-a) 5)
|
||||
(check-equal? (drawable-node-x dnode-b) test-padding)
|
||||
(check-equal? (drawable-node-y dnode-b) (+ (* 2 test-padding) test-width))
|
||||
(check-equal? (drawable-node-x dnode-c) (+ (* 2 test-padding) test-width))
|
||||
(check-equal? (drawable-node-y dnode-c) (drawable-node-y dnode-b))
|
||||
(check-equal? (drawable-node-x dnode-e) (+ (* 3 test-padding) (* 2 test-width)))
|
||||
(check-equal? (drawable-node-y dnode-e) (drawable-node-y dnode-c))
|
||||
(check-equal? (drawable-node-x dnode-d) (drawable-node-x dnode-c))
|
||||
(check-equal? (drawable-node-y dnode-d) (+ (drawable-node-y dnode-c) test-padding test-width)))
|
||||
(let ([atree (build-attr-tree tree3 0)])
|
||||
(check-equal? (attributed-node-num-leaves atree) 3))
|
||||
|
||||
#|
|
||||
a
|
||||
/ | | \
|
||||
b c f g
|
||||
/ \
|
||||
d e
|
||||
|#
|
||||
(define tree4 (tree 'a
|
||||
(tree 'b)
|
||||
(tree 'c
|
||||
(tree 'd)
|
||||
(tree 'e))
|
||||
(tree 'f)
|
||||
(tree 'g)))
|
||||
(let* ([layout (draw-tree tree4 #:node-width test-width #:padding test-padding)]
|
||||
[nodes (graph-layout-nodes layout)]
|
||||
[dnode-a (get-node 'a layout)]
|
||||
[dnode-b (get-node 'b layout)]
|
||||
[dnode-c (get-node 'c layout)]
|
||||
[dnode-d (get-node 'd layout)]
|
||||
[dnode-e (get-node 'e layout)]
|
||||
[dnode-f (get-node 'f layout)]
|
||||
[dnode-g (get-node 'g layout)])
|
||||
(check-equal? (graph-layout-width layout) 80)
|
||||
(check-equal? (graph-layout-height layout) 50)
|
||||
(check-equal? (drawable-node-x dnode-b) test-padding)
|
||||
(check-equal? (drawable-node-y dnode-b) (+ (drawable-node-y dnode-a) test-width test-padding))
|
||||
(check-equal? (drawable-node-y dnode-c) (drawable-node-y dnode-b))
|
||||
(check-equal? (drawable-node-x dnode-d) (+ (drawable-node-x dnode-b) test-width test-padding))
|
||||
(check-equal? (drawable-node-y dnode-d) (+ (drawable-node-y dnode-c) test-width test-padding))
|
||||
(check-equal? (drawable-node-x dnode-e) (+ (drawable-node-x dnode-d) test-width test-padding))
|
||||
(check-equal? (drawable-node-y dnode-e) (drawable-node-y dnode-d))
|
||||
(check-equal? (drawable-node-x dnode-f) (+ (drawable-node-x dnode-e) test-width test-padding))
|
||||
(check-equal? (drawable-node-y dnode-f) (drawable-node-y dnode-c))
|
||||
(check-equal? (drawable-node-x dnode-g) (+ (drawable-node-x dnode-f) test-width test-padding)))
|
||||
(let ([atree (build-attr-tree tree4 0)])
|
||||
(check-equal? (attributed-node-num-leaves atree) 5))
|
||||
|
||||
#|
|
||||
Layered-tree-draw example from Di Battista
|
||||
a
|
||||
/ \
|
||||
b g
|
||||
| / \
|
||||
c h k
|
||||
| / \
|
||||
d i j
|
||||
/ \
|
||||
e f
|
||||
|#
|
||||
(define tree5 (tree 'a
|
||||
(tree 'b
|
||||
(tree 'c
|
||||
(tree 'd
|
||||
(tree 'e)
|
||||
(tree 'f))))
|
||||
(tree 'g
|
||||
(tree 'h
|
||||
(tree 'i)
|
||||
(tree 'j))
|
||||
(tree 'k))))
|
||||
(let* ([layout (draw-tree tree5 #:node-width test-width #:padding test-padding)]
|
||||
[nodes (graph-layout-nodes layout)]
|
||||
[dnode-a (get-node 'a layout)]
|
||||
[dnode-b (get-node 'b layout)]
|
||||
[dnode-c (get-node 'c layout)]
|
||||
[dnode-d (get-node 'd layout)]
|
||||
[dnode-e (get-node 'e layout)]
|
||||
[dnode-f (get-node 'f layout)]
|
||||
[dnode-g (get-node 'g layout)]
|
||||
[dnode-h (get-node 'h layout)]
|
||||
[dnode-i (get-node 'i layout)]
|
||||
[dnode-j (get-node 'j layout)]
|
||||
[dnode-k (get-node 'k layout)])
|
||||
(check-equal? (graph-layout-width layout) 80)
|
||||
(check-equal? (graph-layout-height layout) 80)
|
||||
(check-equal? (drawable-node-x dnode-e) test-padding)
|
||||
(check-equal? (drawable-node-y dnode-e) 65)
|
||||
(check-equal? (drawable-node-x dnode-f) (+ (drawable-node-x dnode-e) test-width test-padding))
|
||||
(check-equal? (drawable-node-x dnode-i) (+ (drawable-node-x dnode-f) test-width test-padding))
|
||||
(check-equal? (drawable-node-x dnode-j) (+ (drawable-node-x dnode-i) test-width test-padding))
|
||||
(check-equal? (drawable-node-x dnode-k) (+ (drawable-node-x dnode-j) test-width test-padding)))
|
||||
(let ([atree (build-attr-tree tree5 0)])
|
||||
(check-equal? (attributed-node-num-leaves atree) 5))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
(graph-layout-nodes layout))))
|
|
@ -8,15 +8,15 @@
|
|||
"graph-drawing.rkt"
|
||||
(only-in '#%futures init-visualizer-tracking!))
|
||||
|
||||
(provide (contract-out [start-performance-tracking! (-> void?)])
|
||||
(provide start-performance-tracking!
|
||||
(struct-out future-event)
|
||||
(struct-out indexed-fevent)
|
||||
(struct-out indexed-future-event)
|
||||
(struct-out trace)
|
||||
(struct-out process-timeline)
|
||||
(struct-out future-timeline)
|
||||
(struct-out event)
|
||||
(struct-out rtcall-info)
|
||||
raw-log-output
|
||||
timeline-events
|
||||
organize-output
|
||||
build-trace
|
||||
event-has-duration?
|
||||
|
@ -44,7 +44,7 @@
|
|||
;Many future-events can be logged at what appears to be the same
|
||||
;time, apparently because the time values don't have great enough precision
|
||||
;to separate events which temporally occur close together.
|
||||
(struct indexed-fevent (index fevent) #:transparent)
|
||||
(struct indexed-future-event (index fevent) #:transparent)
|
||||
|
||||
;The whole trace, with a start/end time and list of process timelines
|
||||
(struct trace (start-time ;Absolute start time (in process milliseconds)
|
||||
|
@ -68,12 +68,6 @@
|
|||
sync-hash) ; op name --o--> number of syncs
|
||||
#:transparent)
|
||||
|
||||
;The timeline of events for a specific process
|
||||
(struct timeline (id
|
||||
start
|
||||
end
|
||||
events))
|
||||
|
||||
;(struct process-timeline timeline (proc-index))
|
||||
(struct process-timeline (proc-id
|
||||
proc-index
|
||||
|
@ -133,30 +127,30 @@
|
|||
(define (relative-time trace abs-time)
|
||||
(- abs-time (trace-start-time trace)))
|
||||
|
||||
;Gets log output as a straight list, ordered according to when the
|
||||
;message was logged
|
||||
;;raw-log-output : uint -> (listof indexed-fevent)
|
||||
(define (raw-log-output index)
|
||||
(let ([info (sync/timeout 0 recv)])
|
||||
;Gets log events for an execution timeline
|
||||
;;timeline-events : (listof indexed-future-event)
|
||||
(define (timeline-events)
|
||||
(let ([index 0]
|
||||
[info (sync/timeout 0 recv)])
|
||||
(if info
|
||||
(let ([v (vector-ref info 2)])
|
||||
(if (future-event? v)
|
||||
(cons (indexed-fevent index v) (raw-log-output (add1 index)))
|
||||
(raw-log-output index)))
|
||||
(cons (indexed-future-event index v) (timeline-events (add1 index)))
|
||||
(timeline-events index)))
|
||||
'())))
|
||||
|
||||
;Produces a vector of vectors, where each inner vector contains
|
||||
;all the log output messages for a specific process
|
||||
;;organize-output : (listof indexed-fevent) -> (vectorof (vectorof future-event))
|
||||
;;organize-output : (listof indexed-future-event) -> (vectorof (vectorof future-event))
|
||||
(define (organize-output raw-log-output)
|
||||
(define unique-proc-ids (for/set ([ie (in-list raw-log-output)])
|
||||
(future-event-process-id (indexed-fevent-fevent ie))))
|
||||
(future-event-process-id (indexed-future-event-fevent ie))))
|
||||
(for/vector ([procid (in-list (sort (set->list unique-proc-ids) <))])
|
||||
(for/vector ([e (in-list raw-log-output)]
|
||||
#:when (eq? procid (future-event-process-id (indexed-fevent-fevent e))))
|
||||
#:when (eq? procid (future-event-process-id (indexed-future-event-fevent e))))
|
||||
e)))
|
||||
|
||||
;;build-trace : (listof indexed-fevent) -> trace
|
||||
;;build-trace : (listof indexed-future-event) -> trace
|
||||
(define (build-trace log-output)
|
||||
(define data (organize-output log-output))
|
||||
(define-values (start-time end-time unique-fids nblocks nsyncs)
|
||||
|
@ -165,7 +159,7 @@
|
|||
[unique-fids (set)]
|
||||
[nblocks 0]
|
||||
[nsyncs 0]) ([ie (in-list log-output)])
|
||||
(let* ([evt (indexed-fevent-fevent ie)]
|
||||
(let* ([evt (indexed-future-event-fevent ie)]
|
||||
[fid (future-event-future-id evt)]
|
||||
[is-future-thread? (not (= (future-event-process-id evt) RT-THREAD-ID))])
|
||||
(values
|
||||
|
@ -190,16 +184,16 @@
|
|||
(define tls (for/list ([proc-log-vec (in-vector data)]
|
||||
[i (in-naturals)])
|
||||
(let* ([fst-ie (vector-ref proc-log-vec 0)]
|
||||
[fst-log-msg (indexed-fevent-fevent fst-ie)])
|
||||
[fst-log-msg (indexed-future-event-fevent fst-ie)])
|
||||
(process-timeline (future-event-process-id fst-log-msg)
|
||||
i
|
||||
(future-event-time fst-log-msg)
|
||||
(future-event-time (indexed-fevent-fevent
|
||||
(future-event-time (indexed-future-event-fevent
|
||||
(vector-ref proc-log-vec
|
||||
(sub1 (vector-length proc-log-vec)))))
|
||||
(for/list ([ie (in-vector proc-log-vec)]
|
||||
[j (in-naturals)])
|
||||
(let* ([evt (indexed-fevent-fevent ie)]
|
||||
(let* ([evt (indexed-future-event-fevent ie)]
|
||||
[start (future-event-time evt)]
|
||||
[pos (cond
|
||||
[(zero? j) (if (= j (sub1 (vector-length proc-log-vec)))
|
||||
|
@ -207,11 +201,11 @@
|
|||
'start)]
|
||||
[(= j (sub1 (vector-length proc-log-vec))) 'end]
|
||||
[else 'interior])])
|
||||
(event (indexed-fevent-index ie)
|
||||
(event (indexed-future-event-index ie)
|
||||
start
|
||||
(if (or (equal? pos 'end) (equal? pos 'singleton))
|
||||
start
|
||||
(future-event-time (indexed-fevent-fevent
|
||||
(future-event-time (indexed-future-event-fevent
|
||||
(vector-ref proc-log-vec (add1 j)))))
|
||||
(future-event-process-id evt)
|
||||
i
|
||||
|
|
|
@ -10,19 +10,17 @@
|
|||
"display.rkt"
|
||||
"constants.rkt")
|
||||
|
||||
(provide seg-in-vregion
|
||||
(provide timeline-pict
|
||||
timeline-pict-for-trace-data
|
||||
timeline-overlay
|
||||
seg-in-vregion
|
||||
calc-segments
|
||||
calc-ticks
|
||||
calc-row-mid-y
|
||||
find-seg-for-coords
|
||||
segment-edge
|
||||
segs-equal-or-later
|
||||
build-timeline-pict
|
||||
build-timeline-bmp-from-log
|
||||
build-timeline-pict-from-log
|
||||
build-timeline-overlay
|
||||
build-timeline-with-overlay
|
||||
build-timeline-bmp-with-overlay
|
||||
creation-tree-pict
|
||||
draw-creategraph-pict
|
||||
zoom-level->factor
|
||||
graph-overlay-pict
|
||||
|
@ -581,104 +579,59 @@
|
|||
(loop next-targ-arr next)
|
||||
next-targ-arr)))))))
|
||||
|
||||
|
||||
;;timeline-bmp-from-log : (listof indexed-fevent) (or uint bool) (or uint bool) -> bitmap%
|
||||
(define (build-timeline-bmp-from-log logs
|
||||
#:max-width [max-width #f]
|
||||
#:max-height [max-height #f])
|
||||
(define vregion (if (or (not max-width) (not max-height))
|
||||
#f
|
||||
(viewable-region 0
|
||||
0
|
||||
max-width
|
||||
max-height)))
|
||||
|
||||
(define p (build-timeline-pict-from-log logs vregion))
|
||||
(pict->bitmap p))
|
||||
|
||||
(define (truncate-bmp bmp width height)
|
||||
(define w (min width (send bmp get-width)))
|
||||
(define h (min height (send bmp get-height)))
|
||||
(let ([buf (make-bytes (* width height 4))])
|
||||
(send bmp
|
||||
get-argb-pixels
|
||||
0
|
||||
0
|
||||
w
|
||||
h
|
||||
buf)
|
||||
(let ([new-b (make-bitmap w h)])
|
||||
(send new-b
|
||||
set-argb-pixels
|
||||
0
|
||||
0
|
||||
w
|
||||
h
|
||||
buf)
|
||||
new-b)))
|
||||
|
||||
;;build-timeline-bmp-with-overlay : (listof indexed-fevent) uint vregion [uint] [uint] -> bitmap%
|
||||
(define (build-timeline-bmp-with-overlay logs
|
||||
event-index
|
||||
vregion
|
||||
#:max-width [max-width #f]
|
||||
#:max-height [max-height #f])
|
||||
(define p (build-timeline-with-overlay logs event-index vregion))
|
||||
(define-values (w h)
|
||||
(values (if max-width (min max-width (pict-width p)) (pict-width p))
|
||||
(if max-height (min max-height (pict-height p)) (pict-height p))))
|
||||
(truncate-bmp (pict->bitmap p) w h))
|
||||
|
||||
|
||||
;;build-timeline-pict-from-trace : trace viewable-region -> pict
|
||||
(define (build-timeline-pict-from-trace tr vregion)
|
||||
;;timeline-pict : (listof indexed-future-event) [viewable-region] [integer] -> pict
|
||||
(define (timeline-pict logs
|
||||
#:x [x #f]
|
||||
#:y [y #f]
|
||||
#:width [width #f]
|
||||
#:height [height #f]
|
||||
#:selected-event-index [selected-event-index #f])
|
||||
(define tr (build-trace logs))
|
||||
(define-values (finfo segments) (calc-segments tr))
|
||||
(build-timeline-pict vregion
|
||||
tr
|
||||
finfo
|
||||
segments))
|
||||
(define vregion (if x
|
||||
(viewable-region x y width height)
|
||||
(viewable-region 0 0 (frame-info-adjusted-width finfo) (frame-info-adjusted-height finfo))))
|
||||
(timeline-pict-for-trace-data vregion
|
||||
tr
|
||||
finfo
|
||||
segments
|
||||
#:selected-event-index selected-event-index))
|
||||
|
||||
;;build-timeline-pict : (or viewable-region #f) trace frame-info (listof segment) -> pict
|
||||
(define (build-timeline-pict vregion tr finfo segments)
|
||||
;;timeline-pict : (or viewable-region #f) trace frame-info (listof segment) -> pict
|
||||
(define (timeline-pict-for-trace-data vregion
|
||||
tr
|
||||
finfo
|
||||
segments
|
||||
#:selected-event-index [selected-event-index #f])
|
||||
(define vr (if (not vregion)
|
||||
(viewable-region 0
|
||||
0
|
||||
(frame-info-adjusted-width finfo)
|
||||
(frame-info-adjusted-height finfo))
|
||||
vregion))
|
||||
(for/fold ([pct (frame-bg vr finfo tr)])
|
||||
([seg (in-list (filter (seg-in-vregion vr) segments))])
|
||||
(pin-over pct
|
||||
(- (segment-x seg) (viewable-region-x vr))
|
||||
(- (segment-y seg) (viewable-region-y vr))
|
||||
(pict-for-segment seg))))
|
||||
|
||||
;;build-timeline-pict-from-log : (listof indexed-fevent) viewable-region -> pict
|
||||
(define (build-timeline-pict-from-log logs vregion)
|
||||
(build-timeline-pict-from-trace (build-trace logs) vregion))
|
||||
|
||||
;;build-timeline-with-overlay : (listof indexed-fevent) uint -> pict
|
||||
(define (build-timeline-with-overlay logs event-index vregion)
|
||||
(define tr (build-trace logs))
|
||||
(define-values (finfo segments) (calc-segments tr))
|
||||
(define timeline-p (build-timeline-pict vregion
|
||||
tr
|
||||
finfo
|
||||
segments))
|
||||
(define overlay (build-timeline-overlay vregion
|
||||
#f
|
||||
(list-ref segments event-index)
|
||||
finfo
|
||||
tr))
|
||||
(pin-over timeline-p
|
||||
0
|
||||
0
|
||||
overlay))
|
||||
(define tp (for/fold ([pct (frame-bg vr finfo tr)])
|
||||
([seg (in-list (filter (seg-in-vregion vr) segments))])
|
||||
(pin-over pct
|
||||
(- (segment-x seg) (viewable-region-x vr))
|
||||
(- (segment-y seg) (viewable-region-y vr))
|
||||
(pict-for-segment seg))))
|
||||
(cond
|
||||
[selected-event-index
|
||||
(define overlay (timeline-overlay vregion
|
||||
#f
|
||||
(list-ref segments selected-event-index)
|
||||
finfo
|
||||
tr))
|
||||
(pin-over tp
|
||||
0
|
||||
0
|
||||
overlay)]
|
||||
[else tp]))
|
||||
|
||||
;Draws the pict that is layered on top of the exec. timeline canvas
|
||||
;to highlight a specific future's event sequence
|
||||
;;build-timeline-overlay : uint uint (or segment #f) (or segment #f) frame-info trace -> pict
|
||||
(define (build-timeline-overlay vregion tacked hovered finfo tr)
|
||||
;;timeline-overlay : uint uint (or segment #f) (or segment #f) frame-info trace -> pict
|
||||
(define (timeline-overlay vregion tacked hovered finfo tr)
|
||||
(define-values (width height) (values (viewable-region-width vregion)
|
||||
(viewable-region-height vregion)))
|
||||
(define base (blank (viewable-region-width vregion)
|
||||
|
@ -755,6 +708,32 @@
|
|||
(drawable-node-width dnode))
|
||||
(colorize (text ntext) (create-graph-node-forecolor)))))
|
||||
|
||||
;;creation-tree-pict : (listof indexed-future-event) [enni] [enni] [enni] [enni] [enni] [enni] [enni] -> pict
|
||||
(define (creation-tree-pict events
|
||||
#:x [x #f]
|
||||
#:y [y #f]
|
||||
#:width [width #f]
|
||||
#:height [height #f]
|
||||
#:node-width [node-width #f]
|
||||
#:padding [padding #f]
|
||||
#:zoom [zoom CREATE-GRAPH-MIN-ZOOM])
|
||||
(define tr (build-trace events))
|
||||
(define node-diam (if node-width
|
||||
node-width
|
||||
CREATE-GRAPH-NODE-DIAMETER))
|
||||
(define graph-padding (if padding
|
||||
padding
|
||||
CREATE-GRAPH-PADDING))
|
||||
(define layout (draw-tree (trace-creation-tree tr)
|
||||
#:node-width node-diam
|
||||
#:padding graph-padding
|
||||
#:zoom zoom))
|
||||
(define vregion (if x
|
||||
(viewable-region x y width height)
|
||||
#f))
|
||||
(draw-creategraph-pict vregion layout))
|
||||
|
||||
|
||||
;;draw-creategraph-pict : (or/c viewable-region #f) tree-layout -> pict
|
||||
;; if vregion is #f, return a pict that includes the entire tree
|
||||
(define (draw-creategraph-pict vregion layout)
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
"display.rkt"
|
||||
"constants.rkt")
|
||||
|
||||
(provide (contract-out [show-visualizer (-> void?)])
|
||||
show-visualizer-for-trace)
|
||||
(provide show-visualizer
|
||||
show-visualizer-for-events)
|
||||
|
||||
;;rebuild-mouse-index : frame-info trace (listof segment) -> interval-map of (range --> interval-map)
|
||||
(define (rebuild-mouse-index frameinfo tr segs)
|
||||
|
@ -84,7 +84,8 @@
|
|||
(values (min screen-w DEF-WINDOW-WIDTH)
|
||||
(min screen-h DEF-WINDOW-HEIGHT)))
|
||||
|
||||
(define (show-visualizer-for-trace logs)
|
||||
;;show-visualizer-for-events : (listof indexed-fevent) -> void
|
||||
(define (show-visualizer-for-events logs)
|
||||
;If for some reason the log is empty, error
|
||||
(when (empty? logs)
|
||||
(error 'show-visualizer "No future log messages found."))
|
||||
|
@ -148,23 +149,21 @@
|
|||
(define timeline-panel (new pict-canvas%
|
||||
[parent timeline-container]
|
||||
[redraw-on-resize #f]
|
||||
[pict-builder (λ (vregion) (build-timeline-pict vregion the-trace frameinfo segments))]
|
||||
[pict-builder (λ (vregion) (timeline-pict-for-trace-data vregion the-trace frameinfo segments))]
|
||||
[hover-handler (λ (x y vregion)
|
||||
(let ([seg (find-seg-for-coords x y timeline-mouse-index)])
|
||||
(let ([seg (find-seg-for-coords x y timeline-mouse-index)])
|
||||
(set! hover-seg seg)
|
||||
;(send timeline-panel set-redraw-overlay! #t)
|
||||
(post-event listener-table 'segment-hover timeline-panel seg)))]
|
||||
[click-handler (λ (x y vregion)
|
||||
(let ([seg (find-seg-for-coords x y timeline-mouse-index)])
|
||||
(set! tacked-seg seg)
|
||||
;(send timeline-panel set-redraw-overlay! #t)
|
||||
(post-event listener-table 'segment-click timeline-panel seg)))]
|
||||
(set! tacked-seg seg)
|
||||
(post-event listener-table 'segment-click timeline-panel seg)))]
|
||||
[overlay-builder (λ (vregion scale-factor)
|
||||
(build-timeline-overlay vregion
|
||||
tacked-seg
|
||||
hover-seg
|
||||
frameinfo
|
||||
the-trace))]
|
||||
(timeline-overlay vregion
|
||||
tacked-seg
|
||||
hover-seg
|
||||
frameinfo
|
||||
the-trace))]
|
||||
[min-width 500]
|
||||
[min-height (inexact->exact (round (* winh .7)))]
|
||||
[style '(hscroll vscroll)]
|
||||
|
@ -357,4 +356,4 @@
|
|||
(send f show #t))
|
||||
|
||||
(define (show-visualizer)
|
||||
(show-visualizer-for-trace (raw-log-output 0)))
|
||||
(show-visualizer-for-events (timeline-events)))
|
||||
|
|
22
collects/racket/future/trace.rkt
Normal file
22
collects/racket/future/trace.rkt
Normal file
|
@ -0,0 +1,22 @@
|
|||
#lang racket/base
|
||||
(require racket/contract
|
||||
"private/visualizer-data.rkt")
|
||||
(provide (struct-out future-event)
|
||||
(struct-out indexed-future-event)
|
||||
trace-futures
|
||||
(contract-out
|
||||
[start-performance-tracking! (-> void?)]
|
||||
[timeline-events (-> (listof indexed-future-event?))]
|
||||
[trace-futures-thunk ((-> any/c) . -> . (listof indexed-future-event?))]))
|
||||
|
||||
(define-syntax-rule (trace-futures e ...)
|
||||
(begin (start-performance-tracking!)
|
||||
(begin (begin e ...)
|
||||
(timeline-events))))
|
||||
|
||||
;;trace-futures-thunk : (-> any) -> (listof indexed-future-event)
|
||||
(define (trace-futures-thunk thunk)
|
||||
(start-performance-tracking!)
|
||||
(begin
|
||||
(thunk)
|
||||
(timeline-events)))
|
|
@ -1,5 +1,51 @@
|
|||
#lang racket/base
|
||||
(require "private/visualizer-gui.rkt"
|
||||
"private/visualizer-data.rkt")
|
||||
(provide start-performance-tracking!
|
||||
show-visualizer)
|
||||
(require racket/contract
|
||||
slideshow/pict
|
||||
racket/bool
|
||||
racket/future/trace
|
||||
"private/visualizer-gui.rkt"
|
||||
"private/visualizer-drawing.rkt")
|
||||
(provide visualize-futures
|
||||
(contract-out
|
||||
[show-visualizer (-> void?)]
|
||||
[visualize-futures-thunk ((-> any/c) . -> . any/c)]
|
||||
[show-visualizer-for-events ((listof indexed-future-event?) . -> . void?)]
|
||||
[timeline-pict (->i ([indexed-fevents (listof indexed-future-event?)])
|
||||
(#:x [x (or/c #f exact-nonnegative-integer?)]
|
||||
#:y [y (or/c #f exact-nonnegative-integer?)]
|
||||
#:width [width (or/c #f exact-nonnegative-integer?)]
|
||||
#:height [height (or/c #f exact-nonnegative-integer?)]
|
||||
#:selected-event-index [i (or/c #f exact-nonnegative-integer?)])
|
||||
#:pre
|
||||
(x y width height)
|
||||
(implies (or x y width height)
|
||||
(and x y width height))
|
||||
[p pict?])]
|
||||
[creation-tree-pict (->i ([indexed-fevents (listof indexed-future-event?)])
|
||||
(#:x [x (or/c #f exact-nonnegative-integer?)]
|
||||
#:y [y (or/c #f exact-nonnegative-integer?)]
|
||||
#:width [width (or/c #f exact-nonnegative-integer?)]
|
||||
#:height [height (or/c #f exact-nonnegative-integer?)]
|
||||
#:node-width [node-width (or/c #f exact-nonnegative-integer?)]
|
||||
#:padding [padding (or/c #f exact-nonnegative-integer?)]
|
||||
#:zoom [zoom (between/c 1 5)])
|
||||
#:pre
|
||||
(x y width height)
|
||||
(implies (or x y width height)
|
||||
(and x y width height))
|
||||
[p pict?])]))
|
||||
|
||||
(define-syntax-rule (visualize-futures e ...)
|
||||
(begin (start-performance-tracking!)
|
||||
(begin0 (begin e ...)
|
||||
(show-visualizer))))
|
||||
|
||||
;;visualize-futures-thunk : (-> any/c) -> any/c
|
||||
(define (visualize-futures-thunk thunk)
|
||||
(start-performance-tracking!)
|
||||
(begin0
|
||||
(thunk)
|
||||
(show-visualizer)))
|
||||
|
||||
|
||||
|
|
@ -16,7 +16,7 @@ those constructs, however, is limited by several factors, and the
|
|||
current implementation is best suited to numerical tasks.
|
||||
|
||||
@margin-note{Other functions, such as @racket[thread], support the
|
||||
creation of reliably concurrent tasks. However, thread never run truly
|
||||
creation of reliably concurrent tasks. However, threads never run truly
|
||||
in parallel, even if the hardware and operating system support
|
||||
parallelism.}
|
||||
|
||||
|
@ -109,13 +109,10 @@ To see why, use the @racketmodname[racket/future/visualizer], like this:
|
|||
|
||||
@racketblock[
|
||||
(require racket/future/visualizer)
|
||||
(start-performance-tracking!)
|
||||
|
||||
(let ([f (future (lambda () (mandelbrot 10000000 62 501 1000)))])
|
||||
(list (mandelbrot 10000000 62 500 1000)
|
||||
(touch f)))
|
||||
|
||||
(show-visualizer)]
|
||||
(visualize-futures
|
||||
(let ([f (future (lambda () (mandelbrot 10000000 62 501 1000)))])
|
||||
(list (mandelbrot 10000000 62 500 1000)
|
||||
(touch f))))]
|
||||
|
||||
This opens a window showing a graphical view of a trace of the computation.
|
||||
The upper-left portion of the window contains an execution timeline:
|
||||
|
@ -123,113 +120,115 @@ The upper-left portion of the window contains an execution timeline:
|
|||
@(interaction-eval
|
||||
#:eval future-eval
|
||||
(define bad-log
|
||||
(list (indexed-fevent 0 '#s(future-event #f 0 create 1334778390997.936 #f 1))
|
||||
(indexed-fevent 1 '#s(future-event 1 1 start-work 1334778390998.137 #f #f))
|
||||
(indexed-fevent 2 '#s(future-event 1 1 sync 1334778390998.145 #f #f))
|
||||
(indexed-fevent 3 '#s(future-event 1 0 sync 1334778391001.616 [allocate memory] #f))
|
||||
(indexed-fevent 4 '#s(future-event 1 0 result 1334778391001.629 #f #f))
|
||||
(indexed-fevent 5 '#s(future-event 1 1 result 1334778391001.643 #f #f))
|
||||
(indexed-fevent 6 '#s(future-event 1 1 block 1334778391001.653 #f #f))
|
||||
(indexed-fevent 7 '#s(future-event 1 1 suspend 1334778391001.658 #f #f))
|
||||
(indexed-fevent 8 '#s(future-event 1 1 end-work 1334778391001.658 #f #f))
|
||||
(indexed-fevent 9 '#s(future-event 1 0 block 1334778392134.226 > #f))
|
||||
(indexed-fevent 10 '#s(future-event 1 0 result 1334778392134.241 #f #f))
|
||||
(indexed-fevent 11 '#s(future-event 1 1 start-work 1334778392134.254 #f #f))
|
||||
(indexed-fevent 12 '#s(future-event 1 1 sync 1334778392134.339 #f #f))
|
||||
(indexed-fevent 13 '#s(future-event 1 0 sync 1334778392134.375 [allocate memory] #f))
|
||||
(indexed-fevent 14 '#s(future-event 1 0 result 1334778392134.38 #f #f))
|
||||
(indexed-fevent 15 '#s(future-event 1 1 result 1334778392134.387 #f #f))
|
||||
(indexed-fevent 16 '#s(future-event 1 1 block 1334778392134.39 #f #f))
|
||||
(indexed-fevent 17 '#s(future-event 1 1 suspend 1334778392134.391 #f #f))
|
||||
(indexed-fevent 18 '#s(future-event 1 1 end-work 1334778392134.391 #f #f))
|
||||
(indexed-fevent 19 '#s(future-event 1 0 touch-pause 1334778392134.432 #f #f))
|
||||
(indexed-fevent 20 '#s(future-event 1 0 touch-resume 1334778392134.433 #f #f))
|
||||
(indexed-fevent 21 '#s(future-event 1 0 block 1334778392134.533 * #f))
|
||||
(indexed-fevent 22 '#s(future-event 1 0 result 1334778392134.537 #f #f))
|
||||
(indexed-fevent 23 '#s(future-event 1 2 start-work 1334778392134.568 #f #f))
|
||||
(indexed-fevent 24 '#s(future-event 1 2 sync 1334778392134.57 #f #f))
|
||||
(indexed-fevent 25 '#s(future-event 1 0 touch-pause 1334778392134.587 #f #f))
|
||||
(indexed-fevent 26 '#s(future-event 1 0 touch-resume 1334778392134.587 #f #f))
|
||||
(indexed-fevent 27 '#s(future-event 1 0 block 1334778392134.6 [allocate memory] #f))
|
||||
(indexed-fevent 28 '#s(future-event 1 0 result 1334778392134.604 #f #f))
|
||||
(indexed-fevent 29 '#s(future-event 1 2 result 1334778392134.627 #f #f))
|
||||
(indexed-fevent 30 '#s(future-event 1 2 block 1334778392134.629 #f #f))
|
||||
(indexed-fevent 31 '#s(future-event 1 2 suspend 1334778392134.632 #f #f))
|
||||
(indexed-fevent 32 '#s(future-event 1 2 end-work 1334778392134.633 #f #f))
|
||||
(indexed-fevent 33 '#s(future-event 1 0 touch-pause 1334778392134.64 #f #f))
|
||||
(indexed-fevent 34 '#s(future-event 1 0 touch-resume 1334778392134.64 #f #f))
|
||||
(indexed-fevent 35 '#s(future-event 1 0 block 1334778392134.663 > #f))
|
||||
(indexed-fevent 36 '#s(future-event 1 0 result 1334778392134.666 #f #f))
|
||||
(indexed-fevent 37 '#s(future-event 1 1 start-work 1334778392134.673 #f #f))
|
||||
(indexed-fevent 38 '#s(future-event 1 1 block 1334778392134.676 #f #f))
|
||||
(indexed-fevent 39 '#s(future-event 1 1 suspend 1334778392134.677 #f #f))
|
||||
(indexed-fevent 40 '#s(future-event 1 1 end-work 1334778392134.677 #f #f))
|
||||
(indexed-fevent 41 '#s(future-event 1 0 touch-pause 1334778392134.704 #f #f))
|
||||
(indexed-fevent 42 '#s(future-event 1 0 touch-resume 1334778392134.704 #f #f))
|
||||
(indexed-fevent 43 '#s(future-event 1 0 block 1334778392134.727 * #f))
|
||||
(indexed-fevent 44 '#s(future-event 1 0 result 1334778392134.73 #f #f))
|
||||
(indexed-fevent 45 '#s(future-event 1 2 start-work 1334778392134.737 #f #f))
|
||||
(indexed-fevent 46 '#s(future-event 1 2 block 1334778392134.739 #f #f))
|
||||
(indexed-fevent 47 '#s(future-event 1 2 suspend 1334778392134.74 #f #f))
|
||||
(indexed-fevent 48 '#s(future-event 1 2 end-work 1334778392134.741 #f #f))
|
||||
(indexed-fevent 49 '#s(future-event 1 0 touch-pause 1334778392134.767 #f #f))
|
||||
(indexed-fevent 50 '#s(future-event 1 0 touch-resume 1334778392134.767 #f #f))
|
||||
(indexed-fevent 51 '#s(future-event 1 0 block 1334778392134.79 > #f))
|
||||
(indexed-fevent 52 '#s(future-event 1 0 result 1334778392134.793 #f #f))
|
||||
(indexed-fevent 53 '#s(future-event 1 1 start-work 1334778392134.799 #f #f))
|
||||
(indexed-fevent 54 '#s(future-event 1 1 block 1334778392134.801 #f #f))
|
||||
(indexed-fevent 55 '#s(future-event 1 1 suspend 1334778392134.802 #f #f))
|
||||
(indexed-fevent 56 '#s(future-event 1 1 end-work 1334778392134.803 #f #f))
|
||||
(indexed-fevent 57 '#s(future-event 1 0 touch-pause 1334778392134.832 #f #f))
|
||||
(indexed-fevent 58 '#s(future-event 1 0 touch-resume 1334778392134.832 #f #f))
|
||||
(indexed-fevent 59 '#s(future-event 1 0 block 1334778392134.854 * #f))
|
||||
(indexed-fevent 60 '#s(future-event 1 0 result 1334778392134.858 #f #f))
|
||||
(indexed-fevent 61 '#s(future-event 1 2 start-work 1334778392134.864 #f #f))
|
||||
(indexed-fevent 62 '#s(future-event 1 2 block 1334778392134.876 #f #f))
|
||||
(indexed-fevent 63 '#s(future-event 1 2 suspend 1334778392134.877 #f #f))
|
||||
(indexed-fevent 64 '#s(future-event 1 2 end-work 1334778392134.882 #f #f))
|
||||
(indexed-fevent 65 '#s(future-event 1 0 touch-pause 1334778392134.918 #f #f))
|
||||
(indexed-fevent 66 '#s(future-event 1 0 touch-resume 1334778392134.918 #f #f))
|
||||
(indexed-fevent 67 '#s(future-event 1 0 block 1334778392134.94 > #f))
|
||||
(indexed-fevent 68 '#s(future-event 1 0 result 1334778392134.943 #f #f))
|
||||
(indexed-fevent 69 '#s(future-event 1 1 start-work 1334778392134.949 #f #f))
|
||||
(indexed-fevent 70 '#s(future-event 1 1 block 1334778392134.952 #f #f))
|
||||
(indexed-fevent 71 '#s(future-event 1 1 suspend 1334778392134.953 #f #f))
|
||||
(indexed-fevent 72 '#s(future-event 1 1 end-work 1334778392134.96 #f #f))
|
||||
(indexed-fevent 73 '#s(future-event 1 0 touch-pause 1334778392134.991 #f #f))
|
||||
(indexed-fevent 74 '#s(future-event 1 0 touch-resume 1334778392134.991 #f #f))
|
||||
(indexed-fevent 75 '#s(future-event 1 0 block 1334778392135.013 * #f))
|
||||
(indexed-fevent 76 '#s(future-event 1 0 result 1334778392135.016 #f #f))
|
||||
(indexed-fevent 77 '#s(future-event 1 2 start-work 1334778392135.027 #f #f))
|
||||
(indexed-fevent 78 '#s(future-event 1 2 block 1334778392135.033 #f #f))
|
||||
(indexed-fevent 79 '#s(future-event 1 2 suspend 1334778392135.034 #f #f))
|
||||
(indexed-fevent 80 '#s(future-event 1 2 end-work 1334778392135.04 #f #f))
|
||||
(indexed-fevent 81 '#s(future-event 1 0 touch-pause 1334778392135.075 #f #f))
|
||||
(indexed-fevent 82 '#s(future-event 1 0 touch-resume 1334778392135.075 #f #f))
|
||||
(indexed-fevent 83 '#s(future-event 1 0 block 1334778392135.098 > #f))
|
||||
(indexed-fevent 84 '#s(future-event 1 0 result 1334778392135.101 #f #f))
|
||||
(indexed-fevent 85 '#s(future-event 1 1 start-work 1334778392135.107 #f #f))
|
||||
(indexed-fevent 86 '#s(future-event 1 1 block 1334778392135.117 #f #f))
|
||||
(indexed-fevent 87 '#s(future-event 1 1 suspend 1334778392135.118 #f #f))
|
||||
(indexed-fevent 88 '#s(future-event 1 1 end-work 1334778392135.123 #f #f))
|
||||
(indexed-fevent 89 '#s(future-event 1 0 touch-pause 1334778392135.159 #f #f))
|
||||
(indexed-fevent 90 '#s(future-event 1 0 touch-resume 1334778392135.159 #f #f))
|
||||
(indexed-fevent 91 '#s(future-event 1 0 block 1334778392135.181 * #f))
|
||||
(indexed-fevent 92 '#s(future-event 1 0 result 1334778392135.184 #f #f))
|
||||
(indexed-fevent 93 '#s(future-event 1 2 start-work 1334778392135.19 #f #f))
|
||||
(indexed-fevent 94 '#s(future-event 1 2 block 1334778392135.191 #f #f))
|
||||
(indexed-fevent 95 '#s(future-event 1 2 suspend 1334778392135.192 #f #f))
|
||||
(indexed-fevent 96 '#s(future-event 1 2 end-work 1334778392135.192 #f #f))
|
||||
(indexed-fevent 97 '#s(future-event 1 0 touch-pause 1334778392135.221 #f #f))
|
||||
(indexed-fevent 98 '#s(future-event 1 0 touch-resume 1334778392135.221 #f #f))
|
||||
(indexed-fevent 99 '#s(future-event 1 0 block 1334778392135.243 > #f))
|
||||
(list (indexed-future-event 0 '#s(future-event #f 0 create 1334778390997.936 #f 1))
|
||||
(indexed-future-event 1 '#s(future-event 1 1 start-work 1334778390998.137 #f #f))
|
||||
(indexed-future-event 2 '#s(future-event 1 1 sync 1334778390998.145 #f #f))
|
||||
(indexed-future-event 3 '#s(future-event 1 0 sync 1334778391001.616 [allocate memory] #f))
|
||||
(indexed-future-event 4 '#s(future-event 1 0 result 1334778391001.629 #f #f))
|
||||
(indexed-future-event 5 '#s(future-event 1 1 result 1334778391001.643 #f #f))
|
||||
(indexed-future-event 6 '#s(future-event 1 1 block 1334778391001.653 #f #f))
|
||||
(indexed-future-event 7 '#s(future-event 1 1 suspend 1334778391001.658 #f #f))
|
||||
(indexed-future-event 8 '#s(future-event 1 1 end-work 1334778391001.658 #f #f))
|
||||
(indexed-future-event 9 '#s(future-event 1 0 block 1334778392134.226 > #f))
|
||||
(indexed-future-event 10 '#s(future-event 1 0 result 1334778392134.241 #f #f))
|
||||
(indexed-future-event 11 '#s(future-event 1 1 start-work 1334778392134.254 #f #f))
|
||||
(indexed-future-event 12 '#s(future-event 1 1 sync 1334778392134.339 #f #f))
|
||||
(indexed-future-event 13 '#s(future-event 1 0 sync 1334778392134.375 [allocate memory] #f))
|
||||
(indexed-future-event 14 '#s(future-event 1 0 result 1334778392134.38 #f #f))
|
||||
(indexed-future-event 15 '#s(future-event 1 1 result 1334778392134.387 #f #f))
|
||||
(indexed-future-event 16 '#s(future-event 1 1 block 1334778392134.39 #f #f))
|
||||
(indexed-future-event 17 '#s(future-event 1 1 suspend 1334778392134.391 #f #f))
|
||||
(indexed-future-event 18 '#s(future-event 1 1 end-work 1334778392134.391 #f #f))
|
||||
(indexed-future-event 19 '#s(future-event 1 0 touch-pause 1334778392134.432 #f #f))
|
||||
(indexed-future-event 20 '#s(future-event 1 0 touch-resume 1334778392134.433 #f #f))
|
||||
(indexed-future-event 21 '#s(future-event 1 0 block 1334778392134.533 * #f))
|
||||
(indexed-future-event 22 '#s(future-event 1 0 result 1334778392134.537 #f #f))
|
||||
(indexed-future-event 23 '#s(future-event 1 2 start-work 1334778392134.568 #f #f))
|
||||
(indexed-future-event 24 '#s(future-event 1 2 sync 1334778392134.57 #f #f))
|
||||
(indexed-future-event 25 '#s(future-event 1 0 touch-pause 1334778392134.587 #f #f))
|
||||
(indexed-future-event 26 '#s(future-event 1 0 touch-resume 1334778392134.587 #f #f))
|
||||
(indexed-future-event 27 '#s(future-event 1 0 block 1334778392134.6 [allocate memory] #f))
|
||||
(indexed-future-event 28 '#s(future-event 1 0 result 1334778392134.604 #f #f))
|
||||
(indexed-future-event 29 '#s(future-event 1 2 result 1334778392134.627 #f #f))
|
||||
(indexed-future-event 30 '#s(future-event 1 2 block 1334778392134.629 #f #f))
|
||||
(indexed-future-event 31 '#s(future-event 1 2 suspend 1334778392134.632 #f #f))
|
||||
(indexed-future-event 32 '#s(future-event 1 2 end-work 1334778392134.633 #f #f))
|
||||
(indexed-future-event 33 '#s(future-event 1 0 touch-pause 1334778392134.64 #f #f))
|
||||
(indexed-future-event 34 '#s(future-event 1 0 touch-resume 1334778392134.64 #f #f))
|
||||
(indexed-future-event 35 '#s(future-event 1 0 block 1334778392134.663 > #f))
|
||||
(indexed-future-event 36 '#s(future-event 1 0 result 1334778392134.666 #f #f))
|
||||
(indexed-future-event 37 '#s(future-event 1 1 start-work 1334778392134.673 #f #f))
|
||||
(indexed-future-event 38 '#s(future-event 1 1 block 1334778392134.676 #f #f))
|
||||
(indexed-future-event 39 '#s(future-event 1 1 suspend 1334778392134.677 #f #f))
|
||||
(indexed-future-event 40 '#s(future-event 1 1 end-work 1334778392134.677 #f #f))
|
||||
(indexed-future-event 41 '#s(future-event 1 0 touch-pause 1334778392134.704 #f #f))
|
||||
(indexed-future-event 42 '#s(future-event 1 0 touch-resume 1334778392134.704 #f #f))
|
||||
(indexed-future-event 43 '#s(future-event 1 0 block 1334778392134.727 * #f))
|
||||
(indexed-future-event 44 '#s(future-event 1 0 result 1334778392134.73 #f #f))
|
||||
(indexed-future-event 45 '#s(future-event 1 2 start-work 1334778392134.737 #f #f))
|
||||
(indexed-future-event 46 '#s(future-event 1 2 block 1334778392134.739 #f #f))
|
||||
(indexed-future-event 47 '#s(future-event 1 2 suspend 1334778392134.74 #f #f))
|
||||
(indexed-future-event 48 '#s(future-event 1 2 end-work 1334778392134.741 #f #f))
|
||||
(indexed-future-event 49 '#s(future-event 1 0 touch-pause 1334778392134.767 #f #f))
|
||||
(indexed-future-event 50 '#s(future-event 1 0 touch-resume 1334778392134.767 #f #f))
|
||||
(indexed-future-event 51 '#s(future-event 1 0 block 1334778392134.79 > #f))
|
||||
(indexed-future-event 52 '#s(future-event 1 0 result 1334778392134.793 #f #f))
|
||||
(indexed-future-event 53 '#s(future-event 1 1 start-work 1334778392134.799 #f #f))
|
||||
(indexed-future-event 54 '#s(future-event 1 1 block 1334778392134.801 #f #f))
|
||||
(indexed-future-event 55 '#s(future-event 1 1 suspend 1334778392134.802 #f #f))
|
||||
(indexed-future-event 56 '#s(future-event 1 1 end-work 1334778392134.803 #f #f))
|
||||
(indexed-future-event 57 '#s(future-event 1 0 touch-pause 1334778392134.832 #f #f))
|
||||
(indexed-future-event 58 '#s(future-event 1 0 touch-resume 1334778392134.832 #f #f))
|
||||
(indexed-future-event 59 '#s(future-event 1 0 block 1334778392134.854 * #f))
|
||||
(indexed-future-event 60 '#s(future-event 1 0 result 1334778392134.858 #f #f))
|
||||
(indexed-future-event 61 '#s(future-event 1 2 start-work 1334778392134.864 #f #f))
|
||||
(indexed-future-event 62 '#s(future-event 1 2 block 1334778392134.876 #f #f))
|
||||
(indexed-future-event 63 '#s(future-event 1 2 suspend 1334778392134.877 #f #f))
|
||||
(indexed-future-event 64 '#s(future-event 1 2 end-work 1334778392134.882 #f #f))
|
||||
(indexed-future-event 65 '#s(future-event 1 0 touch-pause 1334778392134.918 #f #f))
|
||||
(indexed-future-event 66 '#s(future-event 1 0 touch-resume 1334778392134.918 #f #f))
|
||||
(indexed-future-event 67 '#s(future-event 1 0 block 1334778392134.94 > #f))
|
||||
(indexed-future-event 68 '#s(future-event 1 0 result 1334778392134.943 #f #f))
|
||||
(indexed-future-event 69 '#s(future-event 1 1 start-work 1334778392134.949 #f #f))
|
||||
(indexed-future-event 70 '#s(future-event 1 1 block 1334778392134.952 #f #f))
|
||||
(indexed-future-event 71 '#s(future-event 1 1 suspend 1334778392134.953 #f #f))
|
||||
(indexed-future-event 72 '#s(future-event 1 1 end-work 1334778392134.96 #f #f))
|
||||
(indexed-future-event 73 '#s(future-event 1 0 touch-pause 1334778392134.991 #f #f))
|
||||
(indexed-future-event 74 '#s(future-event 1 0 touch-resume 1334778392134.991 #f #f))
|
||||
(indexed-future-event 75 '#s(future-event 1 0 block 1334778392135.013 * #f))
|
||||
(indexed-future-event 76 '#s(future-event 1 0 result 1334778392135.016 #f #f))
|
||||
(indexed-future-event 77 '#s(future-event 1 2 start-work 1334778392135.027 #f #f))
|
||||
(indexed-future-event 78 '#s(future-event 1 2 block 1334778392135.033 #f #f))
|
||||
(indexed-future-event 79 '#s(future-event 1 2 suspend 1334778392135.034 #f #f))
|
||||
(indexed-future-event 80 '#s(future-event 1 2 end-work 1334778392135.04 #f #f))
|
||||
(indexed-future-event 81 '#s(future-event 1 0 touch-pause 1334778392135.075 #f #f))
|
||||
(indexed-future-event 82 '#s(future-event 1 0 touch-resume 1334778392135.075 #f #f))
|
||||
(indexed-future-event 83 '#s(future-event 1 0 block 1334778392135.098 > #f))
|
||||
(indexed-future-event 84 '#s(future-event 1 0 result 1334778392135.101 #f #f))
|
||||
(indexed-future-event 85 '#s(future-event 1 1 start-work 1334778392135.107 #f #f))
|
||||
(indexed-future-event 86 '#s(future-event 1 1 block 1334778392135.117 #f #f))
|
||||
(indexed-future-event 87 '#s(future-event 1 1 suspend 1334778392135.118 #f #f))
|
||||
(indexed-future-event 88 '#s(future-event 1 1 end-work 1334778392135.123 #f #f))
|
||||
(indexed-future-event 89 '#s(future-event 1 0 touch-pause 1334778392135.159 #f #f))
|
||||
(indexed-future-event 90 '#s(future-event 1 0 touch-resume 1334778392135.159 #f #f))
|
||||
(indexed-future-event 91 '#s(future-event 1 0 block 1334778392135.181 * #f))
|
||||
(indexed-future-event 92 '#s(future-event 1 0 result 1334778392135.184 #f #f))
|
||||
(indexed-future-event 93 '#s(future-event 1 2 start-work 1334778392135.19 #f #f))
|
||||
(indexed-future-event 94 '#s(future-event 1 2 block 1334778392135.191 #f #f))
|
||||
(indexed-future-event 95 '#s(future-event 1 2 suspend 1334778392135.192 #f #f))
|
||||
(indexed-future-event 96 '#s(future-event 1 2 end-work 1334778392135.192 #f #f))
|
||||
(indexed-future-event 97 '#s(future-event 1 0 touch-pause 1334778392135.221 #f #f))
|
||||
(indexed-future-event 98 '#s(future-event 1 0 touch-resume 1334778392135.221 #f #f))
|
||||
(indexed-future-event 99 '#s(future-event 1 0 block 1334778392135.243 > #f))
|
||||
)))
|
||||
|
||||
@interaction-eval-show[
|
||||
#:eval future-eval
|
||||
(build-timeline-bmp-from-log bad-log
|
||||
#:max-width 600
|
||||
#:max-height 300)
|
||||
(timeline-pict bad-log
|
||||
#:x 0
|
||||
#:y 0
|
||||
#:width 600
|
||||
#:height 300)
|
||||
]
|
||||
|
||||
Each horizontal row represents an OS-level thread, and the colored
|
||||
|
@ -262,10 +261,12 @@ This image shows those connections for our future.
|
|||
|
||||
@interaction-eval-show[
|
||||
#:eval future-eval
|
||||
(build-timeline-bmp-with-overlay bad-log
|
||||
6
|
||||
#:max-width 600
|
||||
#:max-height 300)
|
||||
(timeline-pict bad-log
|
||||
#:x 0
|
||||
#:y 0
|
||||
#:width 600
|
||||
#:height 300
|
||||
#:selected-event-index 6)
|
||||
]
|
||||
|
||||
The dotted orange line connects the first event in the future to
|
||||
|
@ -303,112 +304,116 @@ slow-path operation limiting our parallelism (orange dots):
|
|||
@interaction-eval[
|
||||
#:eval future-eval
|
||||
(define better-log
|
||||
(list (indexed-fevent 0 '#s(future-event #f 0 create 1334779296782.22 #f 2))
|
||||
(indexed-fevent 1 '#s(future-event 2 2 start-work 1334779296782.265 #f #f))
|
||||
(indexed-fevent 2 '#s(future-event 2 2 sync 1334779296782.378 #f #f))
|
||||
(indexed-fevent 3 '#s(future-event 2 0 sync 1334779296795.582 [allocate memory] #f))
|
||||
(indexed-fevent 4 '#s(future-event 2 0 result 1334779296795.587 #f #f))
|
||||
(indexed-fevent 5 '#s(future-event 2 2 result 1334779296795.6 #f #f))
|
||||
(indexed-fevent 6 '#s(future-event 2 2 sync 1334779296795.689 #f #f))
|
||||
(indexed-fevent 7 '#s(future-event 2 0 sync 1334779296795.807 [allocate memory] #f))
|
||||
(indexed-fevent 8 '#s(future-event 2 0 result 1334779296795.812 #f #f))
|
||||
(indexed-fevent 9 '#s(future-event 2 2 result 1334779296795.818 #f #f))
|
||||
(indexed-fevent 10 '#s(future-event 2 2 sync 1334779296795.827 #f #f))
|
||||
(indexed-fevent 11 '#s(future-event 2 0 sync 1334779296806.627 [allocate memory] #f))
|
||||
(indexed-fevent 12 '#s(future-event 2 0 result 1334779296806.635 #f #f))
|
||||
(indexed-fevent 13 '#s(future-event 2 2 result 1334779296806.646 #f #f))
|
||||
(indexed-fevent 14 '#s(future-event 2 2 sync 1334779296806.879 #f #f))
|
||||
(indexed-fevent 15 '#s(future-event 2 0 sync 1334779296806.994 [allocate memory] #f))
|
||||
(indexed-fevent 16 '#s(future-event 2 0 result 1334779296806.999 #f #f))
|
||||
(indexed-fevent 17 '#s(future-event 2 2 result 1334779296807.007 #f #f))
|
||||
(indexed-fevent 18 '#s(future-event 2 2 sync 1334779296807.023 #f #f))
|
||||
(indexed-fevent 19 '#s(future-event 2 0 sync 1334779296814.198 [allocate memory] #f))
|
||||
(indexed-fevent 20 '#s(future-event 2 0 result 1334779296814.206 #f #f))
|
||||
(indexed-fevent 21 '#s(future-event 2 2 result 1334779296814.221 #f #f))
|
||||
(indexed-fevent 22 '#s(future-event 2 2 sync 1334779296814.29 #f #f))
|
||||
(indexed-fevent 23 '#s(future-event 2 0 sync 1334779296820.796 [allocate memory] #f))
|
||||
(indexed-fevent 24 '#s(future-event 2 0 result 1334779296820.81 #f #f))
|
||||
(indexed-fevent 25 '#s(future-event 2 2 result 1334779296820.835 #f #f))
|
||||
(indexed-fevent 26 '#s(future-event 2 2 sync 1334779296821.089 #f #f))
|
||||
(indexed-fevent 27 '#s(future-event 2 0 sync 1334779296825.217 [allocate memory] #f))
|
||||
(indexed-fevent 28 '#s(future-event 2 0 result 1334779296825.226 #f #f))
|
||||
(indexed-fevent 29 '#s(future-event 2 2 result 1334779296825.242 #f #f))
|
||||
(indexed-fevent 30 '#s(future-event 2 2 sync 1334779296825.305 #f #f))
|
||||
(indexed-fevent 31 '#s(future-event 2 0 sync 1334779296832.541 [allocate memory] #f))
|
||||
(indexed-fevent 32 '#s(future-event 2 0 result 1334779296832.549 #f #f))
|
||||
(indexed-fevent 33 '#s(future-event 2 2 result 1334779296832.562 #f #f))
|
||||
(indexed-fevent 34 '#s(future-event 2 2 sync 1334779296832.667 #f #f))
|
||||
(indexed-fevent 35 '#s(future-event 2 0 sync 1334779296836.269 [allocate memory] #f))
|
||||
(indexed-fevent 36 '#s(future-event 2 0 result 1334779296836.278 #f #f))
|
||||
(indexed-fevent 37 '#s(future-event 2 2 result 1334779296836.326 #f #f))
|
||||
(indexed-fevent 38 '#s(future-event 2 2 sync 1334779296836.396 #f #f))
|
||||
(indexed-fevent 39 '#s(future-event 2 0 sync 1334779296843.481 [allocate memory] #f))
|
||||
(indexed-fevent 40 '#s(future-event 2 0 result 1334779296843.49 #f #f))
|
||||
(indexed-fevent 41 '#s(future-event 2 2 result 1334779296843.501 #f #f))
|
||||
(indexed-fevent 42 '#s(future-event 2 2 sync 1334779296843.807 #f #f))
|
||||
(indexed-fevent 43 '#s(future-event 2 0 sync 1334779296847.291 [allocate memory] #f))
|
||||
(indexed-fevent 44 '#s(future-event 2 0 result 1334779296847.3 #f #f))
|
||||
(indexed-fevent 45 '#s(future-event 2 2 result 1334779296847.312 #f #f))
|
||||
(indexed-fevent 46 '#s(future-event 2 2 sync 1334779296847.375 #f #f))
|
||||
(indexed-fevent 47 '#s(future-event 2 0 sync 1334779296854.487 [allocate memory] #f))
|
||||
(indexed-fevent 48 '#s(future-event 2 0 result 1334779296854.495 #f #f))
|
||||
(indexed-fevent 49 '#s(future-event 2 2 result 1334779296854.507 #f #f))
|
||||
(indexed-fevent 50 '#s(future-event 2 2 sync 1334779296854.656 #f #f))
|
||||
(indexed-fevent 51 '#s(future-event 2 0 sync 1334779296857.374 [allocate memory] #f))
|
||||
(indexed-fevent 52 '#s(future-event 2 0 result 1334779296857.383 #f #f))
|
||||
(indexed-fevent 53 '#s(future-event 2 2 result 1334779296857.421 #f #f))
|
||||
(indexed-fevent 54 '#s(future-event 2 2 sync 1334779296857.488 #f #f))
|
||||
(indexed-fevent 55 '#s(future-event 2 0 sync 1334779296869.919 [allocate memory] #f))
|
||||
(indexed-fevent 56 '#s(future-event 2 0 result 1334779296869.947 #f #f))
|
||||
(indexed-fevent 57 '#s(future-event 2 2 result 1334779296869.981 #f #f))
|
||||
(indexed-fevent 58 '#s(future-event 2 2 sync 1334779296870.32 #f #f))
|
||||
(indexed-fevent 59 '#s(future-event 2 0 sync 1334779296879.438 [allocate memory] #f))
|
||||
(indexed-fevent 60 '#s(future-event 2 0 result 1334779296879.446 #f #f))
|
||||
(indexed-fevent 61 '#s(future-event 2 2 result 1334779296879.463 #f #f))
|
||||
(indexed-fevent 62 '#s(future-event 2 2 sync 1334779296879.526 #f #f))
|
||||
(indexed-fevent 63 '#s(future-event 2 0 sync 1334779296882.928 [allocate memory] #f))
|
||||
(indexed-fevent 64 '#s(future-event 2 0 result 1334779296882.935 #f #f))
|
||||
(indexed-fevent 65 '#s(future-event 2 2 result 1334779296882.944 #f #f))
|
||||
(indexed-fevent 66 '#s(future-event 2 2 sync 1334779296883.311 #f #f))
|
||||
(indexed-fevent 67 '#s(future-event 2 0 sync 1334779296890.471 [allocate memory] #f))
|
||||
(indexed-fevent 68 '#s(future-event 2 0 result 1334779296890.479 #f #f))
|
||||
(indexed-fevent 69 '#s(future-event 2 2 result 1334779296890.517 #f #f))
|
||||
(indexed-fevent 70 '#s(future-event 2 2 sync 1334779296890.581 #f #f))
|
||||
(indexed-fevent 71 '#s(future-event 2 0 sync 1334779296894.362 [allocate memory] #f))
|
||||
(indexed-fevent 72 '#s(future-event 2 0 result 1334779296894.369 #f #f))
|
||||
(indexed-fevent 73 '#s(future-event 2 2 result 1334779296894.382 #f #f))
|
||||
(indexed-fevent 74 '#s(future-event 2 2 sync 1334779296894.769 #f #f))
|
||||
(indexed-fevent 75 '#s(future-event 2 0 sync 1334779296901.501 [allocate memory] #f))
|
||||
(indexed-fevent 76 '#s(future-event 2 0 result 1334779296901.51 #f #f))
|
||||
(indexed-fevent 77 '#s(future-event 2 2 result 1334779296901.556 #f #f))
|
||||
(indexed-fevent 78 '#s(future-event 2 2 sync 1334779296901.62 #f #f))
|
||||
(indexed-fevent 79 '#s(future-event 2 0 sync 1334779296905.428 [allocate memory] #f))
|
||||
(indexed-fevent 80 '#s(future-event 2 0 result 1334779296905.434 #f #f))
|
||||
(indexed-fevent 81 '#s(future-event 2 2 result 1334779296905.447 #f #f))
|
||||
(indexed-fevent 82 '#s(future-event 2 2 sync 1334779296905.743 #f #f))
|
||||
(indexed-fevent 83 '#s(future-event 2 0 sync 1334779296912.538 [allocate memory] #f))
|
||||
(indexed-fevent 84 '#s(future-event 2 0 result 1334779296912.547 #f #f))
|
||||
(indexed-fevent 85 '#s(future-event 2 2 result 1334779296912.564 #f #f))
|
||||
(indexed-fevent 86 '#s(future-event 2 2 sync 1334779296912.625 #f #f))
|
||||
(indexed-fevent 87 '#s(future-event 2 0 sync 1334779296916.094 [allocate memory] #f))
|
||||
(indexed-fevent 88 '#s(future-event 2 0 result 1334779296916.1 #f #f))
|
||||
(indexed-fevent 89 '#s(future-event 2 2 result 1334779296916.108 #f #f))
|
||||
(indexed-fevent 90 '#s(future-event 2 2 sync 1334779296916.243 #f #f))
|
||||
(indexed-fevent 91 '#s(future-event 2 0 sync 1334779296927.233 [allocate memory] #f))
|
||||
(indexed-fevent 92 '#s(future-event 2 0 result 1334779296927.242 #f #f))
|
||||
(indexed-fevent 93 '#s(future-event 2 2 result 1334779296927.262 #f #f))
|
||||
(indexed-fevent 94 '#s(future-event 2 2 sync 1334779296927.59 #f #f))
|
||||
(indexed-fevent 95 '#s(future-event 2 0 sync 1334779296934.603 [allocate memory] #f))
|
||||
(indexed-fevent 96 '#s(future-event 2 0 result 1334779296934.612 #f #f))
|
||||
(indexed-fevent 97 '#s(future-event 2 2 result 1334779296934.655 #f #f))
|
||||
(indexed-fevent 98 '#s(future-event 2 2 sync 1334779296934.72 #f #f))
|
||||
(indexed-fevent 99 '#s(future-event 2 0 sync 1334779296938.773 [allocate memory] #f))
|
||||
(list (indexed-future-event 0 '#s(future-event #f 0 create 1334779296782.22 #f 2))
|
||||
(indexed-future-event 1 '#s(future-event 2 2 start-work 1334779296782.265 #f #f))
|
||||
(indexed-future-event 2 '#s(future-event 2 2 sync 1334779296782.378 #f #f))
|
||||
(indexed-future-event 3 '#s(future-event 2 0 sync 1334779296795.582 [allocate memory] #f))
|
||||
(indexed-future-event 4 '#s(future-event 2 0 result 1334779296795.587 #f #f))
|
||||
(indexed-future-event 5 '#s(future-event 2 2 result 1334779296795.6 #f #f))
|
||||
(indexed-future-event 6 '#s(future-event 2 2 sync 1334779296795.689 #f #f))
|
||||
(indexed-future-event 7 '#s(future-event 2 0 sync 1334779296795.807 [allocate memory] #f))
|
||||
(indexed-future-event 8 '#s(future-event 2 0 result 1334779296795.812 #f #f))
|
||||
(indexed-future-event 9 '#s(future-event 2 2 result 1334779296795.818 #f #f))
|
||||
(indexed-future-event 10 '#s(future-event 2 2 sync 1334779296795.827 #f #f))
|
||||
(indexed-future-event 11 '#s(future-event 2 0 sync 1334779296806.627 [allocate memory] #f))
|
||||
(indexed-future-event 12 '#s(future-event 2 0 result 1334779296806.635 #f #f))
|
||||
(indexed-future-event 13 '#s(future-event 2 2 result 1334779296806.646 #f #f))
|
||||
(indexed-future-event 14 '#s(future-event 2 2 sync 1334779296806.879 #f #f))
|
||||
(indexed-future-event 15 '#s(future-event 2 0 sync 1334779296806.994 [allocate memory] #f))
|
||||
(indexed-future-event 16 '#s(future-event 2 0 result 1334779296806.999 #f #f))
|
||||
(indexed-future-event 17 '#s(future-event 2 2 result 1334779296807.007 #f #f))
|
||||
(indexed-future-event 18 '#s(future-event 2 2 sync 1334779296807.023 #f #f))
|
||||
(indexed-future-event 19 '#s(future-event 2 0 sync 1334779296814.198 [allocate memory] #f))
|
||||
(indexed-future-event 20 '#s(future-event 2 0 result 1334779296814.206 #f #f))
|
||||
(indexed-future-event 21 '#s(future-event 2 2 result 1334779296814.221 #f #f))
|
||||
(indexed-future-event 22 '#s(future-event 2 2 sync 1334779296814.29 #f #f))
|
||||
(indexed-future-event 23 '#s(future-event 2 0 sync 1334779296820.796 [allocate memory] #f))
|
||||
(indexed-future-event 24 '#s(future-event 2 0 result 1334779296820.81 #f #f))
|
||||
(indexed-future-event 25 '#s(future-event 2 2 result 1334779296820.835 #f #f))
|
||||
(indexed-future-event 26 '#s(future-event 2 2 sync 1334779296821.089 #f #f))
|
||||
(indexed-future-event 27 '#s(future-event 2 0 sync 1334779296825.217 [allocate memory] #f))
|
||||
(indexed-future-event 28 '#s(future-event 2 0 result 1334779296825.226 #f #f))
|
||||
(indexed-future-event 29 '#s(future-event 2 2 result 1334779296825.242 #f #f))
|
||||
(indexed-future-event 30 '#s(future-event 2 2 sync 1334779296825.305 #f #f))
|
||||
(indexed-future-event 31 '#s(future-event 2 0 sync 1334779296832.541 [allocate memory] #f))
|
||||
(indexed-future-event 32 '#s(future-event 2 0 result 1334779296832.549 #f #f))
|
||||
(indexed-future-event 33 '#s(future-event 2 2 result 1334779296832.562 #f #f))
|
||||
(indexed-future-event 34 '#s(future-event 2 2 sync 1334779296832.667 #f #f))
|
||||
(indexed-future-event 35 '#s(future-event 2 0 sync 1334779296836.269 [allocate memory] #f))
|
||||
(indexed-future-event 36 '#s(future-event 2 0 result 1334779296836.278 #f #f))
|
||||
(indexed-future-event 37 '#s(future-event 2 2 result 1334779296836.326 #f #f))
|
||||
(indexed-future-event 38 '#s(future-event 2 2 sync 1334779296836.396 #f #f))
|
||||
(indexed-future-event 39 '#s(future-event 2 0 sync 1334779296843.481 [allocate memory] #f))
|
||||
(indexed-future-event 40 '#s(future-event 2 0 result 1334779296843.49 #f #f))
|
||||
(indexed-future-event 41 '#s(future-event 2 2 result 1334779296843.501 #f #f))
|
||||
(indexed-future-event 42 '#s(future-event 2 2 sync 1334779296843.807 #f #f))
|
||||
(indexed-future-event 43 '#s(future-event 2 0 sync 1334779296847.291 [allocate memory] #f))
|
||||
(indexed-future-event 44 '#s(future-event 2 0 result 1334779296847.3 #f #f))
|
||||
(indexed-future-event 45 '#s(future-event 2 2 result 1334779296847.312 #f #f))
|
||||
(indexed-future-event 46 '#s(future-event 2 2 sync 1334779296847.375 #f #f))
|
||||
(indexed-future-event 47 '#s(future-event 2 0 sync 1334779296854.487 [allocate memory] #f))
|
||||
(indexed-future-event 48 '#s(future-event 2 0 result 1334779296854.495 #f #f))
|
||||
(indexed-future-event 49 '#s(future-event 2 2 result 1334779296854.507 #f #f))
|
||||
(indexed-future-event 50 '#s(future-event 2 2 sync 1334779296854.656 #f #f))
|
||||
(indexed-future-event 51 '#s(future-event 2 0 sync 1334779296857.374 [allocate memory] #f))
|
||||
(indexed-future-event 52 '#s(future-event 2 0 result 1334779296857.383 #f #f))
|
||||
(indexed-future-event 53 '#s(future-event 2 2 result 1334779296857.421 #f #f))
|
||||
(indexed-future-event 54 '#s(future-event 2 2 sync 1334779296857.488 #f #f))
|
||||
(indexed-future-event 55 '#s(future-event 2 0 sync 1334779296869.919 [allocate memory] #f))
|
||||
(indexed-future-event 56 '#s(future-event 2 0 result 1334779296869.947 #f #f))
|
||||
(indexed-future-event 57 '#s(future-event 2 2 result 1334779296869.981 #f #f))
|
||||
(indexed-future-event 58 '#s(future-event 2 2 sync 1334779296870.32 #f #f))
|
||||
(indexed-future-event 59 '#s(future-event 2 0 sync 1334779296879.438 [allocate memory] #f))
|
||||
(indexed-future-event 60 '#s(future-event 2 0 result 1334779296879.446 #f #f))
|
||||
(indexed-future-event 61 '#s(future-event 2 2 result 1334779296879.463 #f #f))
|
||||
(indexed-future-event 62 '#s(future-event 2 2 sync 1334779296879.526 #f #f))
|
||||
(indexed-future-event 63 '#s(future-event 2 0 sync 1334779296882.928 [allocate memory] #f))
|
||||
(indexed-future-event 64 '#s(future-event 2 0 result 1334779296882.935 #f #f))
|
||||
(indexed-future-event 65 '#s(future-event 2 2 result 1334779296882.944 #f #f))
|
||||
(indexed-future-event 66 '#s(future-event 2 2 sync 1334779296883.311 #f #f))
|
||||
(indexed-future-event 67 '#s(future-event 2 0 sync 1334779296890.471 [allocate memory] #f))
|
||||
(indexed-future-event 68 '#s(future-event 2 0 result 1334779296890.479 #f #f))
|
||||
(indexed-future-event 69 '#s(future-event 2 2 result 1334779296890.517 #f #f))
|
||||
(indexed-future-event 70 '#s(future-event 2 2 sync 1334779296890.581 #f #f))
|
||||
(indexed-future-event 71 '#s(future-event 2 0 sync 1334779296894.362 [allocate memory] #f))
|
||||
(indexed-future-event 72 '#s(future-event 2 0 result 1334779296894.369 #f #f))
|
||||
(indexed-future-event 73 '#s(future-event 2 2 result 1334779296894.382 #f #f))
|
||||
(indexed-future-event 74 '#s(future-event 2 2 sync 1334779296894.769 #f #f))
|
||||
(indexed-future-event 75 '#s(future-event 2 0 sync 1334779296901.501 [allocate memory] #f))
|
||||
(indexed-future-event 76 '#s(future-event 2 0 result 1334779296901.51 #f #f))
|
||||
(indexed-future-event 77 '#s(future-event 2 2 result 1334779296901.556 #f #f))
|
||||
(indexed-future-event 78 '#s(future-event 2 2 sync 1334779296901.62 #f #f))
|
||||
(indexed-future-event 79 '#s(future-event 2 0 sync 1334779296905.428 [allocate memory] #f))
|
||||
(indexed-future-event 80 '#s(future-event 2 0 result 1334779296905.434 #f #f))
|
||||
(indexed-future-event 81 '#s(future-event 2 2 result 1334779296905.447 #f #f))
|
||||
(indexed-future-event 82 '#s(future-event 2 2 sync 1334779296905.743 #f #f))
|
||||
(indexed-future-event 83 '#s(future-event 2 0 sync 1334779296912.538 [allocate memory] #f))
|
||||
(indexed-future-event 84 '#s(future-event 2 0 result 1334779296912.547 #f #f))
|
||||
(indexed-future-event 85 '#s(future-event 2 2 result 1334779296912.564 #f #f))
|
||||
(indexed-future-event 86 '#s(future-event 2 2 sync 1334779296912.625 #f #f))
|
||||
(indexed-future-event 87 '#s(future-event 2 0 sync 1334779296916.094 [allocate memory] #f))
|
||||
(indexed-future-event 88 '#s(future-event 2 0 result 1334779296916.1 #f #f))
|
||||
(indexed-future-event 89 '#s(future-event 2 2 result 1334779296916.108 #f #f))
|
||||
(indexed-future-event 90 '#s(future-event 2 2 sync 1334779296916.243 #f #f))
|
||||
(indexed-future-event 91 '#s(future-event 2 0 sync 1334779296927.233 [allocate memory] #f))
|
||||
(indexed-future-event 92 '#s(future-event 2 0 result 1334779296927.242 #f #f))
|
||||
(indexed-future-event 93 '#s(future-event 2 2 result 1334779296927.262 #f #f))
|
||||
(indexed-future-event 94 '#s(future-event 2 2 sync 1334779296927.59 #f #f))
|
||||
(indexed-future-event 95 '#s(future-event 2 0 sync 1334779296934.603 [allocate memory] #f))
|
||||
(indexed-future-event 96 '#s(future-event 2 0 result 1334779296934.612 #f #f))
|
||||
(indexed-future-event 97 '#s(future-event 2 2 result 1334779296934.655 #f #f))
|
||||
(indexed-future-event 98 '#s(future-event 2 2 sync 1334779296934.72 #f #f))
|
||||
(indexed-future-event 99 '#s(future-event 2 0 sync 1334779296938.773 [allocate memory] #f))
|
||||
))
|
||||
]
|
||||
|
||||
@interaction-eval-show[
|
||||
#:eval future-eval
|
||||
(build-timeline-bmp-from-log better-log #:max-width 600 #:max-height 300)
|
||||
(timeline-pict better-log
|
||||
#:x 0
|
||||
#:y 0
|
||||
#:width 600
|
||||
#:height 300)
|
||||
]
|
||||
|
||||
The problem is that most every arithmetic operation in this example
|
||||
|
@ -424,10 +429,10 @@ much less allocation:
|
|||
@interaction-eval[
|
||||
#:eval future-eval
|
||||
(define good-log
|
||||
(list (indexed-fevent 0 '#s(future-event #f 0 create 1334778395768.733 #f 3))
|
||||
(indexed-fevent 1 '#s(future-event 3 2 start-work 1334778395768.771 #f #f))
|
||||
(indexed-fevent 2 '#s(future-event 3 2 complete 1334778395864.648 #f #f))
|
||||
(indexed-fevent 3 '#s(future-event 3 2 end-work 1334778395864.652 #f #f))
|
||||
(list (indexed-future-event 0 '#s(future-event #f 0 create 1334778395768.733 #f 3))
|
||||
(indexed-future-event 1 '#s(future-event 3 2 start-work 1334778395768.771 #f #f))
|
||||
(indexed-future-event 2 '#s(future-event 3 2 complete 1334778395864.648 #f #f))
|
||||
(indexed-future-event 3 '#s(future-event 3 2 end-work 1334778395864.652 #f #f))
|
||||
))
|
||||
]
|
||||
|
||||
|
@ -454,9 +459,11 @@ Executing this program yields the following in the visualizer:
|
|||
|
||||
@interaction-eval-show[
|
||||
#:eval future-eval
|
||||
(build-timeline-bmp-from-log good-log
|
||||
#:max-width 600
|
||||
#:max-height 300)
|
||||
(timeline-pict good-log
|
||||
#:x 0
|
||||
#:y 0
|
||||
#:width 600
|
||||
#:height 300)
|
||||
]
|
||||
|
||||
Notice that only one green bar is shown here because one of the
|
||||
|
|
|
@ -18,5 +18,6 @@ support for parallelism to improve performance.
|
|||
@include-section["thread-local.scrbl"]
|
||||
@include-section["futures.scrbl"]
|
||||
@include-section["futures-visualizer.scrbl"]
|
||||
@include-section["futures-trace.scrbl"]
|
||||
@include-section["places.scrbl"]
|
||||
@include-section["distributed.scrbl"]
|
||||
|
|
207
collects/scribblings/reference/futures-trace.scrbl
Normal file
207
collects/scribblings/reference/futures-trace.scrbl
Normal file
|
@ -0,0 +1,207 @@
|
|||
#lang scribble/doc
|
||||
@(require "mz.rkt" (for-label racket/future racket/future/trace))
|
||||
|
||||
@title[#:tag "futures-trace"]{Futures Tracing}
|
||||
|
||||
@guideintro["effective-futures"]{the future visualizer}
|
||||
|
||||
@defmodule[racket/future/trace]
|
||||
|
||||
The @deftech{futures trace} module exposes low-level information about
|
||||
the execution of parallel programs written using @racket[future].
|
||||
|
||||
@deftogether[(
|
||||
@defform[(trace-futures e ...)]
|
||||
@defproc[(trace-futures-thunk [thunk (-> any)]) (listof indexed-future-event?)]
|
||||
)]{
|
||||
The @racket[trace-futures] macro and @racket[trace-futures-thunk] function
|
||||
track the execution of a program using futures and return the program
|
||||
trace as a list of @racket[indexed-future-event] structures.
|
||||
|
||||
This program:
|
||||
|
||||
@racketblock[
|
||||
(require racket/future
|
||||
racket/future/trace)
|
||||
|
||||
(trace-futures
|
||||
(let ([f (future (lambda () ...))])
|
||||
...
|
||||
(touch f)))
|
||||
]
|
||||
|
||||
Is equivalent to:
|
||||
|
||||
@racketblock[
|
||||
(require racket/future
|
||||
racket/future/trace)
|
||||
|
||||
(start-performance-tracking!)
|
||||
(let ([f (future (lambda () ...))])
|
||||
...
|
||||
(touch f))
|
||||
|
||||
(timeline-events)
|
||||
]
|
||||
}
|
||||
|
||||
@deftogether[(
|
||||
@defproc[(start-performance-tracking!) void?]
|
||||
@defproc[(timeline-events) (listof indexed-future-event?)]
|
||||
)]{
|
||||
The @racket[start-performance-tracking!] procedure enables the collection
|
||||
of future-related execution data. This function should be called immediately
|
||||
prior to executing code the programmer wishes to profile.
|
||||
|
||||
The @racket[timeline-events] procedure returns the program trace as
|
||||
a list of @racket[indexed-future-event] structures.
|
||||
}
|
||||
|
||||
@defstruct[indexed-future-event ([index exact-nonnegative-integer?]
|
||||
[event future-event?])]{
|
||||
Represents an individual log message in a program trace. Because multiple
|
||||
@racket[future-event] structures may contain identical timestamps, the
|
||||
@racket[index] field ranks them in the order in which they were recorded
|
||||
in the log output.
|
||||
}
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
|
||||
@section[#:tag "future-logging"]{Future Performance Logging}
|
||||
|
||||
Racket traces use logging (see @secref["logging"]) extensively to
|
||||
report information about how futures are evaluated. Logging output is
|
||||
useful for debugging the performance of programs that use futures.
|
||||
|
||||
Though textual log output can be viewed directly (or retrieved in
|
||||
code via @racket[trace-futures]), it is much
|
||||
easier to use the graphical profiler tool provided by
|
||||
@racketmodname[racket/future/visualizer].
|
||||
|
||||
In addition to its string message, each event logged for a future has
|
||||
a data value that is an instance of a @racket[future-event]
|
||||
@tech{prefab} structure:
|
||||
|
||||
@defstruct[future-event ([future-id (or exact-nonnegative-integer? #f)]
|
||||
[proc-id exact-nonnegative-integer?]
|
||||
[action symbol?]
|
||||
[time-id real?]
|
||||
[prim-name (or symbol? #f)]
|
||||
[user-data (or #f symbol? exact-nonnegative-integer?)])
|
||||
#:prefab]
|
||||
|
||||
The @racket[future-id] field is an exact integer that identifies a
|
||||
future, or it is @racket[#f] when @racket[action] is
|
||||
@racket['missing]. The @racket[future-id] field is particularly useful
|
||||
for correlating logged events.
|
||||
|
||||
The @racket[proc-id] fields is an exact, non-negative integer that
|
||||
identifies a parallel process. Process 0 is the main Racket process,
|
||||
where all expressions other than future thunks evaluate.
|
||||
|
||||
The @racket[time-id] field is an inexact number that represents time in
|
||||
the same way as @racket[current-inexact-milliseconds].
|
||||
|
||||
The @racket[action] field is a symbol:
|
||||
|
||||
@itemlist[
|
||||
|
||||
@item{@racket['create]: a future was created.}
|
||||
|
||||
@item{@racket['complete]: a future's thunk evaluated successfully, so
|
||||
that @racket[touch] will produce a value for the future
|
||||
immediately.}
|
||||
|
||||
@item{@racket['start-work] and @racket['end-work]: a particular
|
||||
process started and ended working on a particular future.}
|
||||
|
||||
@item{@racket['start-0-work]: like @racket['start-work], but for a
|
||||
future thunk that for some structural reason could not be
|
||||
started in a process other than 0 (e.g., the thunk requires too
|
||||
much local storage to start).}
|
||||
|
||||
@item{@racket['start-overflow-work]: like @racket['start-work], where
|
||||
the future thunk's work was previously stopped due to an
|
||||
internal stack overflow.}
|
||||
|
||||
@item{@racket['sync]: blocking (processes other than 0) or initiation
|
||||
of handing (process 0) for an ``unsafe'' operation in a future
|
||||
thunk's evaluation; the operation must run in process 0.}
|
||||
|
||||
@item{@racket['block]: like @racket['sync], but for a part of
|
||||
evaluation that must be delayed until the future is
|
||||
@racket[touch]ed, because the evaluation may depend on the
|
||||
current continuation.}
|
||||
|
||||
@item{@racket['touch] (never in process 0): like @racket['sync] or
|
||||
@racket['block], but for a @racket[touch] operation within a
|
||||
future thunk.}
|
||||
|
||||
@item{@racket['overflow] (never in process 0): like @racket['sync] or
|
||||
@racket['block], but for the case that a process encountered an
|
||||
internal stack overflow while evaluating a future thunk.}
|
||||
|
||||
@item{@racket['result] or @racket['abort]: waiting or handling for
|
||||
@racket['sync], @racket['block], or @racket['touch] ended with
|
||||
a value or an error, respectively.}
|
||||
|
||||
@item{@racket['suspend] (never in process 0): a process blocked by
|
||||
@racket['sync], @racket['block], or @racket['touch] abandoned
|
||||
evaluation of a future; some other process may pick up the
|
||||
future later.}
|
||||
|
||||
@item{@racket['touch-pause] and @racket['touch-resume] (in process 0,
|
||||
only): waiting in @racket[touch] for a future whose thunk is
|
||||
being evaluated in another process.}
|
||||
|
||||
@item{@racket['missing]: one or more events for the process were lost
|
||||
due to internal buffer limits before they could be reported,
|
||||
and the @racket[time-id] field reports an upper limit on the time
|
||||
of the missing events; this kind of event is rare.}
|
||||
|
||||
]
|
||||
|
||||
Assuming no @racket['missing] events, then @racket['start-work],
|
||||
@racket['start-0-work], @racket['start-overflow-work] is always paired with @racket['end-work];
|
||||
@racket['sync], @racket['block], and @racket['touch] are always paired
|
||||
with @racket['result], @racket['abort], or @racket['suspend]; and
|
||||
@racket['touch-pause] is always paired with @racket['touch-resume].
|
||||
|
||||
In process 0, some event pairs can be nested within other event pairs:
|
||||
@racket['sync], @racket['block], or @racket['touch] with
|
||||
@racket['result] or @racket['abort]; and @racket['touch-pause] with
|
||||
@racket['touch-resume].
|
||||
|
||||
An @racket['block] in process 0 is generated when an unsafe operation
|
||||
is handled. This type of event will contain a symbol in the
|
||||
@racket[unsafe-op-name] field that is the name of the operation. In all
|
||||
other cases, this field contains @racket[#f].
|
||||
|
||||
The @racket[prim-name] field will always be @racket[#f] unless the event occurred
|
||||
on process 0 and its @racket[action] is either @racket['block] or @racket['sync]. If
|
||||
these conditions are met, @racket[prim-name] will contain the name
|
||||
of the Racket primitive which required the future to synchronize with the runtime
|
||||
thread (represented as a symbol).
|
||||
|
||||
The @racket[user-data] field may take on a number of different
|
||||
values depending on both the @racket[action] and @racket[prim-name] fields:
|
||||
|
||||
@itemlist[
|
||||
|
||||
@item{@racket['touch] on process 0: contains the integer ID of the future
|
||||
being touched.}
|
||||
|
||||
@item{@racket['sync] and @racket[prim-name] = @racket[|allocate memory|]:
|
||||
The size (in bytes) of the requested allocation.}
|
||||
|
||||
@item{@racket['sync] and @racket[prim-name] = @racket[|jit_on_demand|]:
|
||||
The runtime thread is performing a JIT compilation on behalf of the
|
||||
future @racket[future-id]. The field contains the name of the function
|
||||
being JIT compiled (as a symbol).}
|
||||
|
||||
@item{@racket['create]: A new future was created. The field contains the integer ID
|
||||
of the newly created future.}
|
||||
|
||||
]
|
||||
|
||||
@; ----------------------------------------------------------------------
|
|
@ -1,5 +1,5 @@
|
|||
#lang scribble/doc
|
||||
@(require "mz.rkt" #;(for-label racket/future/visualizer))
|
||||
@(require "mz.rkt" (for-label racket/future/trace racket/future))
|
||||
|
||||
@title[#:tag "futures-visualizer"]{Futures Visualizer}
|
||||
|
||||
|
@ -14,19 +14,32 @@ events, as well as the overall amount of processor utilization
|
|||
at any point during the program's lifetime.
|
||||
|
||||
@deftogether[(
|
||||
@defproc[(start-performance-tracking!) void?]
|
||||
@defproc[(show-visualizer) void?]
|
||||
@defform[(visualize-futures e ...)]
|
||||
@defproc[(visualize-futures-thunk [thunk (-> any)]) any]
|
||||
)]{
|
||||
The @racket[start-performance-tracking!] procedure enables the collection
|
||||
of data required by the visualizer. This function should be called immediately
|
||||
prior to executing code the programmer wishes to profile.
|
||||
|
||||
The @racket[show-visualizer] procedure displays the profiler window.
|
||||
The @racket[visualize-futures] macro enables the collection
|
||||
of data required by the visualizer and displays a profiler
|
||||
window showing the corresponding trace. The @racket[visualize-futures-thunk]
|
||||
provides similar functionality where program code is contained
|
||||
within @racket[thunk].
|
||||
|
||||
A typical program using profiling might look like the following:
|
||||
|
||||
@racketblock[
|
||||
(require racket/future
|
||||
racket/future/visualizer)
|
||||
|
||||
(visualize-futures
|
||||
(let ([f (future (lambda () ...))])
|
||||
...
|
||||
(touch f)))
|
||||
]
|
||||
|
||||
The preceding program is equivalent to:
|
||||
|
||||
@racketblock[
|
||||
(require racket/future
|
||||
racket/future/trace
|
||||
racket/future/visualizer)
|
||||
|
||||
(start-performance-tracking!)
|
||||
|
@ -38,6 +51,12 @@ at any point during the program's lifetime.
|
|||
]
|
||||
}
|
||||
|
||||
@defproc[(show-visualizer) void?]{
|
||||
Displays the profiler window. Calls to this
|
||||
function must be preceded by a call to @racket[start-performance-tracking!] (or can
|
||||
be avoided altogether by using either @racket[visualize-futures] or @racket[visualize-futures-thunk]).
|
||||
}
|
||||
|
||||
@section[#:tag "future-visualizer-timeline"]{Execution Timeline}
|
||||
|
||||
The @deftech{execution timeline}, shown in the top left-hand corner of the
|
||||
|
@ -74,6 +93,19 @@ though the time interval is fixed, the pixel distance between lines varies
|
|||
based on the event density for any given time range to prevent overlapping
|
||||
event circles.
|
||||
|
||||
@defproc[(timeline-pict [events (listof indexed-future-event?)]
|
||||
[#:x x (or #f exact-nonnegative-integer?) #f]
|
||||
[#:y y (or #f exact-nonnegative-integer?) #f]
|
||||
[#:width width (or #f exact-nonnegative-integer?) #f]
|
||||
[#:height height (or #f exact-nonnegative-integer?) #f]
|
||||
[#:selected-event-index selected-event-index (or #f exact-nonnegative-integer?) #f]) pict?]{
|
||||
Returns a @racket[pict] showing the execution timeline for the trace in @racket[events]. The optional
|
||||
arguments @racket[x], @racket[y], @racket[width], and @racket[height] can be used to obtain a specific
|
||||
area (in pixels) of the timeline image. The @racket[selected-event-index] argument, if specified, shows
|
||||
the timeline image as if the user placed the mouse pointer over the @racket[indexed-future-event] with
|
||||
the corresponding index.
|
||||
}
|
||||
|
||||
@section[#:tag "future-visualizer-tree"]{Future Creation Tree}
|
||||
|
||||
The @deftech{creation tree} shows a tree with a single node per
|
||||
|
@ -84,3 +116,19 @@ of that node represent futures which were created by that future (within
|
|||
the scope of its thunk). For all programs, the root of the tree
|
||||
is a special node representing the main computation thread (the runtime thread),
|
||||
and is denoted @deftech{RTT}.
|
||||
|
||||
@defproc[(creation-tree-pict [events (listof indexed-future-event?)]
|
||||
[#:x x (or #f exact-nonnegative-integer?) #f]
|
||||
[#:y y (or #f exact-nonnegative-integer?) #f]
|
||||
[#:width width (or #f exact-nonnegative-integer?) #f]
|
||||
[#:node-width node-width (or #f exact-nonnegative-integer?) #f]
|
||||
[#:height height (or #f exact-nonnegative-integer?) #f]
|
||||
[#:padding padding (or #f exact-nonnegative-integer?) #f]
|
||||
[#:zoom zoom exact-nonnegative-integer? 1]) pict?]{
|
||||
Returns a @racket[pict] showing the future creation tree for the trace in @racket[events]. The optional
|
||||
arguments @racket[x], @racket[y], @racket[width], and @racket[height] can be used to obtain a specific
|
||||
area (in pixels) of the creation tree image. The @racket[node-width] argument
|
||||
specifies (in pixels) the diameter of each node. The @racket[padding] argument specifies the minimum space vertically
|
||||
between each depth and horizontally between siblings. The @racket[zoom] argument specifies the zoom factor for the
|
||||
tree image in the range 1-5, where 5 returns a 500% zoom.
|
||||
}
|
||||
|
|
|
@ -175,120 +175,4 @@ execute through a call to @racket[touch], however.
|
|||
|
||||
}
|
||||
|
||||
@; ------------------------------------------------------------
|
||||
|
||||
@section[#:tag "future-logging"]{Future Performance Logging}
|
||||
|
||||
Racket futures use logging (see @secref["logging"]) extensively to
|
||||
report information about how futures are evaluated. Logging output is
|
||||
useful for debugging the performance of programs that use futures.
|
||||
|
||||
Though textual log output can be viewed directly, it is much
|
||||
easier to use the graphical profiler tool provided by
|
||||
@racketmodname[racket/future/visualizer].
|
||||
|
||||
In addition to its string message, each event logged for a future has
|
||||
a data value that is an instance of a @racket[future-event]
|
||||
@tech{prefab} structure:
|
||||
|
||||
@racketblock[
|
||||
(define-struct future-event (future-id proc-id action time unsafe-op-name target-fid)
|
||||
#:prefab)
|
||||
]
|
||||
|
||||
The @racket[future-id] field is an exact integer that identifies a
|
||||
future, or it is @racket[#f] when @racket[action] is
|
||||
@racket['missing]. The @racket[future-id] field is particularly useful
|
||||
for correlating logged events.
|
||||
|
||||
The @racket[proc-id] fields is an exact, non-negative integer that
|
||||
identifies a parallel process. Process 0 is the main Racket process,
|
||||
where all expressions other than future thunks evaluate.
|
||||
|
||||
The @|time-id| field is an inexact number that represents time in
|
||||
the same way as @racket[current-inexact-milliseconds].
|
||||
|
||||
The @racket[action] field is a symbol:
|
||||
|
||||
@itemlist[
|
||||
|
||||
@item{@racket['create]: a future was created.}
|
||||
|
||||
@item{@racket['complete]: a future's thunk evaluated successfully, so
|
||||
that @racket[touch] will produce a value for the future
|
||||
immediately.}
|
||||
|
||||
@item{@racket['start-work] and @racket['end-work]: a particular
|
||||
process started and ended working on a particular future.}
|
||||
|
||||
@item{@racket['start-0-work]: like @racket['start-work], but for a
|
||||
future thunk that for some structural reason could not be
|
||||
started in a process other than 0 (e.g., the thunk requires too
|
||||
much local storage to start).}
|
||||
|
||||
@item{@racket['start-overflow-work]: like @racket['start-work], where
|
||||
the future thunk's work was previously stopped due to an
|
||||
internal stack overflow.}
|
||||
|
||||
@item{@racket['sync]: blocking (processes other than 0) or initiation
|
||||
of handing (process 0) for an ``unsafe'' operation in a future
|
||||
thunk's evaluation; the operation must run in process 0.}
|
||||
|
||||
@item{@racket['block]: like @racket['sync], but for a part of
|
||||
evaluation that must be delayed until the future is
|
||||
@racket[touch]ed, because the evaluation may depend on the
|
||||
current continuation.}
|
||||
|
||||
@item{@racket['touch] (never in process 0): like @racket['sync] or
|
||||
@racket['block], but for a @racket[touch] operation within a
|
||||
future thunk.}
|
||||
|
||||
@item{@racket['overflow] (never in process 0): like @racket['sync] or
|
||||
@racket['block], but for the case that a process encountered an
|
||||
internal stack overflow while evaluating a future thunk.}
|
||||
|
||||
@item{@racket['result] or @racket['abort]: waiting or handling for
|
||||
@racket['sync], @racket['block], or @racket['touch] ended with
|
||||
a value or an error, respectively.}
|
||||
|
||||
@item{@racket['suspend] (never in process 0): a process blocked by
|
||||
@racket['sync], @racket['block], or @racket['touch] abandoned
|
||||
evaluation of a future; some other process may pick up the
|
||||
future later.}
|
||||
|
||||
@item{@racket['touch-pause] and @racket['touch-resume] (in process 0,
|
||||
only): waiting in @racket[touch] for a future whose thunk is
|
||||
being evaluated in another process.}
|
||||
|
||||
@item{@racket['missing]: one or more events for the process were lost
|
||||
due to internal buffer limits before they could be reported,
|
||||
and the @|time-id| field reports an upper limit on the time
|
||||
of the missing events; this kind of event is rare.}
|
||||
|
||||
]
|
||||
|
||||
Assuming no @racket['missing] events, then @racket['start-work],
|
||||
@racket['start-0-work], @racket['start-overflow-work] is always paired with @racket['end-work];
|
||||
@racket['sync], @racket['block], and @racket['touch] are always paired
|
||||
with @racket['result], @racket['abort], or @racket['suspend]; and
|
||||
@racket['touch-pause] is always paired with @racket['touch-resume].
|
||||
|
||||
In process 0, some event pairs can be nested within other event pairs:
|
||||
@racket['sync], @racket['block], or @racket['touch] with
|
||||
@racket['result] or @racket['abort]; and @racket['touch-pause] with
|
||||
@racket['touch-resume].
|
||||
|
||||
An @racket[block] in process 0 is generated when an unsafe operation
|
||||
is handled. This type of event will contain a symbol in the
|
||||
@racket[unsafe-op-name] field that is the name of the operation. In all
|
||||
other cases, this field contains @racket[#f].
|
||||
|
||||
The @racket[target-fid] field contains an exact integer value in certain
|
||||
cases where the @racket[action] occurs in one future but is being
|
||||
performed on another (e.g. @racket['create] or @racket['touch]). In such
|
||||
cases, the integer value is the identifier of the future on which the action
|
||||
is being performed. In all other cases, this field contains @racket[#f].
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
|
||||
@close-eval[future-eval]
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
#lang racket/base
|
||||
(require rackunit
|
||||
racket/list
|
||||
racket/vector
|
||||
racket/future/private/visualizer-drawing
|
||||
racket/future/private/visualizer-data
|
||||
racket/future/private/display)
|
||||
racket/future/private/display
|
||||
racket/future/private/graph-drawing)
|
||||
|
||||
(define (compile-trace-data logs)
|
||||
(define tr (build-trace logs))
|
||||
|
@ -50,10 +52,10 @@
|
|||
(check-equal? (length in-vr) 5))
|
||||
|
||||
;Trace compilation tests
|
||||
(let* ([future-log (list (indexed-fevent 0 (future-event 0 0 'create 0 #f 0))
|
||||
(indexed-fevent 1 (future-event 0 1 'start-work 1 #f #f))
|
||||
(indexed-fevent 2 (future-event 0 1 'end-work 2 #f #f))
|
||||
(indexed-fevent 3 (future-event 0 0 'complete 3 #f #f)))]
|
||||
(let* ([future-log (list (indexed-future-event 0 (future-event 0 0 'create 0 #f 0))
|
||||
(indexed-future-event 1 (future-event 0 1 'start-work 1 #f #f))
|
||||
(indexed-future-event 2 (future-event 0 1 'end-work 2 #f #f))
|
||||
(indexed-future-event 3 (future-event 0 0 'complete 3 #f #f)))]
|
||||
[organized (organize-output future-log)])
|
||||
(check-equal? (vector-length organized) 2)
|
||||
(let ([proc0log (vector-ref organized 0)]
|
||||
|
@ -61,10 +63,10 @@
|
|||
(check-equal? (vector-length proc0log) 2)
|
||||
(check-equal? (vector-length proc1log) 2)))
|
||||
|
||||
(let* ([future-log (list (indexed-fevent 0 (future-event #f 0 'create 0 #f 0))
|
||||
(indexed-fevent 1 (future-event 0 1 'start-work 1 #f #f))
|
||||
(indexed-fevent 2 (future-event 0 1 'end-work 2 #f #f))
|
||||
(indexed-fevent 3 (future-event 0 0 'complete 3 #f #f)))]
|
||||
(let* ([future-log (list (indexed-future-event 0 (future-event #f 0 'create 0 #f 0))
|
||||
(indexed-future-event 1 (future-event 0 1 'start-work 1 #f #f))
|
||||
(indexed-future-event 2 (future-event 0 1 'end-work 2 #f #f))
|
||||
(indexed-future-event 3 (future-event 0 0 'complete 3 #f #f)))]
|
||||
[trace (build-trace future-log)]
|
||||
[evts (trace-all-events trace)])
|
||||
(check-equal? (length evts) 4)
|
||||
|
@ -72,14 +74,14 @@
|
|||
(check-equal? (length (filter (λ (e) (event-next-targ-future-event e)) evts)) 1)
|
||||
(check-equal? (length (filter (λ (e) (event-prev-targ-future-event e)) evts)) 1))
|
||||
|
||||
(let* ([future-log (list (indexed-fevent 0 (future-event 0 0 'create 0 #f 0))
|
||||
(indexed-fevent 1 (future-event 1 0 'create 1 #f 1))
|
||||
(indexed-fevent 2 (future-event 0 1 'start-work 2 #f #f))
|
||||
(indexed-fevent 3 (future-event 1 2 'start-work 2 #f #f))
|
||||
(indexed-fevent 4 (future-event 0 1 'end-work 4 #f #f))
|
||||
(indexed-fevent 5 (future-event 0 0 'complete 5 #f #f))
|
||||
(indexed-fevent 6 (future-event 1 2 'end-work 5 #f #f))
|
||||
(indexed-fevent 7 (future-event 1 0 'complete 7 #f #f)))]
|
||||
(let* ([future-log (list (indexed-future-event 0 (future-event 0 0 'create 0 #f 0))
|
||||
(indexed-future-event 1 (future-event 1 0 'create 1 #f 1))
|
||||
(indexed-future-event 2 (future-event 0 1 'start-work 2 #f #f))
|
||||
(indexed-future-event 3 (future-event 1 2 'start-work 2 #f #f))
|
||||
(indexed-future-event 4 (future-event 0 1 'end-work 4 #f #f))
|
||||
(indexed-future-event 5 (future-event 0 0 'complete 5 #f #f))
|
||||
(indexed-future-event 6 (future-event 1 2 'end-work 5 #f #f))
|
||||
(indexed-future-event 7 (future-event 1 0 'complete 7 #f #f)))]
|
||||
[organized (organize-output future-log)])
|
||||
(check-equal? (vector-length organized) 3)
|
||||
(let ([proc0log (vector-ref organized 0)]
|
||||
|
@ -88,18 +90,18 @@
|
|||
(check-equal? (vector-length proc0log) 4)
|
||||
(check-equal? (vector-length proc1log) 2)
|
||||
(check-equal? (vector-length proc2log) 2)
|
||||
(for ([msg (in-vector (vector-map indexed-fevent-fevent proc0log))])
|
||||
(for ([msg (in-vector (vector-map indexed-future-event-fevent proc0log))])
|
||||
(check-equal? (future-event-process-id msg) 0))
|
||||
(for ([msg (in-vector (vector-map indexed-fevent-fevent proc1log))])
|
||||
(for ([msg (in-vector (vector-map indexed-future-event-fevent proc1log))])
|
||||
(check-equal? (future-event-process-id msg) 1))
|
||||
(for ([msg (in-vector (vector-map indexed-fevent-fevent proc2log))])
|
||||
(for ([msg (in-vector (vector-map indexed-future-event-fevent proc2log))])
|
||||
(check-equal? (future-event-process-id msg) 2))))
|
||||
|
||||
;Drawing calculation tests
|
||||
(let* ([future-log (list (indexed-fevent 0 (future-event #f 0 'create 0 #f 0))
|
||||
(indexed-fevent 1 (future-event 0 1 'start-work 1 #f #f))
|
||||
(indexed-fevent 2 (future-event 0 1 'end-work 2 #f #f))
|
||||
(indexed-fevent 3 (future-event 0 0 'complete 3 #f #f)))]
|
||||
(let* ([future-log (list (indexed-future-event 0 (future-event #f 0 'create 0 #f 0))
|
||||
(indexed-future-event 1 (future-event 0 1 'start-work 1 #f #f))
|
||||
(indexed-future-event 2 (future-event 0 1 'end-work 2 #f #f))
|
||||
(indexed-future-event 3 (future-event 0 0 'complete 3 #f #f)))]
|
||||
[trace (build-trace future-log)])
|
||||
(let-values ([(finfo segments) (calc-segments trace)])
|
||||
(check-equal? (length segments) 4)
|
||||
|
@ -108,10 +110,10 @@
|
|||
(check-equal? (length (filter (λ (s) (segment-prev-targ-future-seg s)) segments)) 1)))
|
||||
|
||||
;Future=42
|
||||
(let* ([future-log (list (indexed-fevent 0 (future-event #f 0 'create 0.05 #f 42))
|
||||
(indexed-fevent 1 (future-event 42 1 'start-work 0.07 #f #f))
|
||||
(indexed-fevent 2 (future-event 42 1 'end-work 0.3 #f #f))
|
||||
(indexed-fevent 3 (future-event 42 0 'complete 1.2 #f #f)))]
|
||||
(let* ([future-log (list (indexed-future-event 0 (future-event #f 0 'create 0.05 #f 42))
|
||||
(indexed-future-event 1 (future-event 42 1 'start-work 0.07 #f #f))
|
||||
(indexed-future-event 2 (future-event 42 1 'end-work 0.3 #f #f))
|
||||
(indexed-future-event 3 (future-event 42 0 'complete 1.2 #f #f)))]
|
||||
[tr (build-trace future-log)])
|
||||
(define-values (finfo segs) (calc-segments tr))
|
||||
(define ticks (frame-info-timeline-ticks finfo))
|
||||
|
@ -158,25 +160,25 @@
|
|||
[(> evt-rel-time ttime)
|
||||
(do-seg-check tr seg tick >= "after")]))))
|
||||
|
||||
(let* ([future-log (list (indexed-fevent 0 (future-event #f 0 'create 0.05 #f 42))
|
||||
(indexed-fevent 1 (future-event 42 1 'start-work 0.09 #f #f))
|
||||
(indexed-fevent 2 (future-event 42 1 'suspend 1.1 #f #f))
|
||||
(indexed-fevent 3 (future-event 42 1 'resume 1.101 #f #f))
|
||||
(indexed-fevent 4 (future-event 42 1 'suspend 1.102 #f #f))
|
||||
(indexed-fevent 5 (future-event 42 1 'resume 1.103 #f #f))
|
||||
(indexed-fevent 6 (future-event 42 1 'start-work 1.104 #f #f))
|
||||
(indexed-fevent 7 (future-event 42 1 'complete 1.41 #f #f))
|
||||
(indexed-fevent 8 (future-event 42 1 'end-work 1.42 #f #f))
|
||||
(indexed-fevent 9 (future-event 42 0 'result 1.43 #f #f)))]
|
||||
(let* ([future-log (list (indexed-future-event 0 (future-event #f 0 'create 0.05 #f 42))
|
||||
(indexed-future-event 1 (future-event 42 1 'start-work 0.09 #f #f))
|
||||
(indexed-future-event 2 (future-event 42 1 'suspend 1.1 #f #f))
|
||||
(indexed-future-event 3 (future-event 42 1 'resume 1.101 #f #f))
|
||||
(indexed-future-event 4 (future-event 42 1 'suspend 1.102 #f #f))
|
||||
(indexed-future-event 5 (future-event 42 1 'resume 1.103 #f #f))
|
||||
(indexed-future-event 6 (future-event 42 1 'start-work 1.104 #f #f))
|
||||
(indexed-future-event 7 (future-event 42 1 'complete 1.41 #f #f))
|
||||
(indexed-future-event 8 (future-event 42 1 'end-work 1.42 #f #f))
|
||||
(indexed-future-event 9 (future-event 42 0 'result 1.43 #f #f)))]
|
||||
[tr (build-trace future-log)])
|
||||
(define-values (finfo segs) (calc-segments tr))
|
||||
(define ticks (frame-info-timeline-ticks finfo))
|
||||
(check-seg-layout tr segs ticks))
|
||||
|
||||
(let* ([future-log (list (indexed-fevent 0 (future-event #f 0 'create 0 #f 0))
|
||||
(indexed-fevent 1 (future-event 0 1 'start-work 1 #f #f))
|
||||
(indexed-fevent 2 (future-event 0 1 'end-work 2 #f #f))
|
||||
(indexed-fevent 3 (future-event 0 0 'complete 3 #f #f)))]
|
||||
(let* ([future-log (list (indexed-future-event 0 (future-event #f 0 'create 0 #f 0))
|
||||
(indexed-future-event 1 (future-event 0 1 'start-work 1 #f #f))
|
||||
(indexed-future-event 2 (future-event 0 1 'end-work 2 #f #f))
|
||||
(indexed-future-event 3 (future-event 0 0 'complete 3 #f #f)))]
|
||||
[trace (build-trace future-log)])
|
||||
(check-equal? (trace-start-time trace) 0)
|
||||
(check-equal? (trace-end-time trace) 3)
|
||||
|
@ -244,9 +246,9 @@
|
|||
(check-equal? (length (segs-equal-or-later 4.0 segs)) 0))
|
||||
|
||||
;Tick drawing
|
||||
(let ([l (list (indexed-fevent 0 (future-event #f 0 'create 10.0 #f 0))
|
||||
(indexed-fevent 1 (future-event 0 0 'start-work 11.0 #f #f))
|
||||
(indexed-fevent 2 (future-event 0 0 'end-work 20.0 #f #f)))])
|
||||
(let ([l (list (indexed-future-event 0 (future-event #f 0 'create 10.0 #f 0))
|
||||
(indexed-future-event 1 (future-event 0 0 'start-work 11.0 #f #f))
|
||||
(indexed-future-event 2 (future-event 0 0 'end-work 20.0 #f #f)))])
|
||||
(define-values (tr finfo segs ticks) (compile-trace-data l))
|
||||
;Check that number of ticks stays constant whatever the time->pixel modifier
|
||||
(check-equal? (length ticks) 100)
|
||||
|
@ -257,43 +259,274 @@
|
|||
(format "Wrong number of ticks for time->pix mod ~a\n" i)))
|
||||
(check-seg-layout tr segs ticks))
|
||||
|
||||
(let ([l (list (indexed-fevent 0 '#s(future-event #f 0 create 1334778395768.733 #f 3))
|
||||
(indexed-fevent 1 '#s(future-event 3 2 start-work 1334778395768.771 #f #f))
|
||||
(indexed-fevent 2 '#s(future-event 3 2 complete 1334778395864.648 #f #f))
|
||||
(indexed-fevent 3 '#s(future-event 3 2 end-work 1334778395864.652 #f #f)))])
|
||||
(let ([l (list (indexed-future-event 0 '#s(future-event #f 0 create 1334778395768.733 #f 3))
|
||||
(indexed-future-event 1 '#s(future-event 3 2 start-work 1334778395768.771 #f #f))
|
||||
(indexed-future-event 2 '#s(future-event 3 2 complete 1334778395864.648 #f #f))
|
||||
(indexed-future-event 3 '#s(future-event 3 2 end-work 1334778395864.652 #f #f)))])
|
||||
(define-values (tr finfo segs ticks) (compile-trace-data l))
|
||||
(define last-evt (indexed-fevent-fevent (list-ref l 3)))
|
||||
(define first-evt (indexed-fevent-fevent (list-ref l 0)))
|
||||
(define last-evt (indexed-future-event-fevent (list-ref l 3)))
|
||||
(define first-evt (indexed-future-event-fevent (list-ref l 0)))
|
||||
(define total-time (- (future-event-time last-evt) (future-event-time first-evt)))
|
||||
(check-equal? (length ticks) (inexact->exact (floor (* 10 total-time)))))
|
||||
|
||||
(define mand-first
|
||||
(list (indexed-fevent 0 '#s(future-event #f 0 create 1334779294212.415 #f 1))
|
||||
(indexed-fevent 1 '#s(future-event 1 1 start-work 1334779294212.495 #f #f))
|
||||
(indexed-fevent 2 '#s(future-event 1 1 sync 1334779294212.501 #f #f))
|
||||
(indexed-fevent 3 (future-event 1 0 'sync 1334779294221.128 'allocate_memory #f))
|
||||
(indexed-fevent 4 '#s(future-event 1 0 result 1334779294221.138 #f #f))
|
||||
(indexed-fevent 5 '#s(future-event 1 1 result 1334779294221.15 #f #f))))
|
||||
(list (indexed-future-event 0 '#s(future-event #f 0 create 1334779294212.415 #f 1))
|
||||
(indexed-future-event 1 '#s(future-event 1 1 start-work 1334779294212.495 #f #f))
|
||||
(indexed-future-event 2 '#s(future-event 1 1 sync 1334779294212.501 #f #f))
|
||||
(indexed-future-event 3 (future-event 1 0 'sync 1334779294221.128 'allocate_memory #f))
|
||||
(indexed-future-event 4 '#s(future-event 1 0 result 1334779294221.138 #f #f))
|
||||
(indexed-future-event 5 '#s(future-event 1 1 result 1334779294221.15 #f #f))))
|
||||
(let-values ([(tr finfo segs ticks) (compile-trace-data mand-first)])
|
||||
(check-seg-layout tr segs ticks))
|
||||
|
||||
(define single-block-log
|
||||
(list
|
||||
(indexed-fevent 0 '#s(future-event #f 0 create 1339469018856.55 #f 1))
|
||||
(indexed-fevent 1 '#s(future-event 1 1 start-work 1339469018856.617 #f 0))
|
||||
(indexed-fevent 2 '#s(future-event 1 1 block 1339469018856.621 #f 0))
|
||||
(indexed-fevent 3 '#s(future-event 1 1 suspend 1339469018856.891 #f 0))
|
||||
(indexed-fevent 4 '#s(future-event 1 1 end-work 1339469018856.891 #f 0))
|
||||
(indexed-fevent 5 '#s(future-event 1 0 block 1339469019057.609 printf 0))
|
||||
(indexed-fevent 6 '#s(future-event 1 0 result 1339469019057.783 #f 0))
|
||||
(indexed-fevent 7 '#s(future-event 1 2 start-work 1339469019057.796 #f 0))
|
||||
(indexed-fevent 8 '#s(future-event 1 2 complete 1339469019057.799 #f 0))
|
||||
(indexed-fevent 9 '#s(future-event 1 2 end-work 1339469019057.801 #f 0))))
|
||||
(indexed-future-event 0 '#s(future-event #f 0 create 1339469018856.55 #f 1))
|
||||
(indexed-future-event 1 '#s(future-event 1 1 start-work 1339469018856.617 #f 0))
|
||||
(indexed-future-event 2 '#s(future-event 1 1 block 1339469018856.621 #f 0))
|
||||
(indexed-future-event 3 '#s(future-event 1 1 suspend 1339469018856.891 #f 0))
|
||||
(indexed-future-event 4 '#s(future-event 1 1 end-work 1339469018856.891 #f 0))
|
||||
(indexed-future-event 5 '#s(future-event 1 0 block 1339469019057.609 printf 0))
|
||||
(indexed-future-event 6 '#s(future-event 1 0 result 1339469019057.783 #f 0))
|
||||
(indexed-future-event 7 '#s(future-event 1 2 start-work 1339469019057.796 #f 0))
|
||||
(indexed-future-event 8 '#s(future-event 1 2 complete 1339469019057.799 #f 0))
|
||||
(indexed-future-event 9 '#s(future-event 1 2 end-work 1339469019057.801 #f 0))))
|
||||
(let ([tr (build-trace single-block-log)])
|
||||
(check-equal? (length (hash-keys (trace-block-counts tr))) 1)
|
||||
(check-equal? (length (hash-keys (trace-sync-counts tr))) 0)
|
||||
(check-equal? (length (hash-keys (trace-future-rtcalls tr))) 1))
|
||||
|
||||
;Graph drawing tests
|
||||
(let* ([nodea (drawable-node (node 'a '()) 5 5 10 0 0 '() 10)]
|
||||
[center (drawable-node-center nodea)])
|
||||
(check-equal? (point-x center) 10.0)
|
||||
(check-equal? (point-y center) 10.0))
|
||||
|
||||
|
||||
(define test-padding 5)
|
||||
(define test-width 10)
|
||||
|
||||
(define (tree root-data . children)
|
||||
(node root-data children))
|
||||
|
||||
(define (get-node data layout)
|
||||
(first (filter (λ (dn) (equal? (node-data (drawable-node-node dn)) data)) (graph-layout-nodes layout))))
|
||||
|
||||
#|
|
||||
a
|
||||
|
|
||||
b
|
||||
|#
|
||||
(define tree0 (tree 'a (tree 'b)))
|
||||
(let* ([layout (draw-tree tree0 #:node-width test-width #:padding test-padding)]
|
||||
[dnode-a (get-node 'a layout)]
|
||||
[dnode-b (get-node 'b layout)])
|
||||
(check-equal? (graph-layout-width layout) (+ (* test-padding 2) test-width))
|
||||
(check-equal? (graph-layout-height layout) (+ (* test-padding 3) (* test-width 2)))
|
||||
(check-equal? (drawable-node-x dnode-a) test-padding)
|
||||
(check-equal? (drawable-node-y dnode-a) test-padding)
|
||||
(check-equal? (drawable-node-x dnode-b) test-padding)
|
||||
(check-equal? (drawable-node-y dnode-b) (+ test-padding test-width test-padding)))
|
||||
(let ([atree (build-attr-tree tree0 0)])
|
||||
(check-equal? (attributed-node-num-leaves atree) 1))
|
||||
|
||||
#|
|
||||
a
|
||||
/ \
|
||||
b c
|
||||
|#
|
||||
(define tree1 (tree 'a
|
||||
(tree 'b)
|
||||
(tree 'c)))
|
||||
(define layout (draw-tree tree1 #:node-width test-width #:padding test-padding))
|
||||
(for ([dnode (in-list (graph-layout-nodes layout))])
|
||||
(check-equal? (drawable-node-width dnode) test-width))
|
||||
(define dnode-a (get-node 'a layout))
|
||||
(define dnode-b (get-node 'b layout))
|
||||
(define dnode-c (get-node 'c layout))
|
||||
|
||||
(define slot-one-pos (+ test-padding test-width test-padding))
|
||||
(define square-sz (+ (* test-padding 3) (* test-width 2)))
|
||||
(check-equal? (graph-layout-width layout) square-sz)
|
||||
(check-equal? (graph-layout-height layout) square-sz)
|
||||
(check-equal? (drawable-node-x dnode-b) test-padding)
|
||||
(check-equal? (drawable-node-y dnode-b) slot-one-pos)
|
||||
(check-equal? (drawable-node-x dnode-c) slot-one-pos)
|
||||
(check-equal? (drawable-node-y dnode-c) slot-one-pos)
|
||||
(check-equal? (drawable-node-x dnode-a) (/ 25 2))
|
||||
(check-equal? (drawable-node-y dnode-a) test-padding)
|
||||
(check-equal? (length (drawable-node-children dnode-a)) 2)
|
||||
(let ([atree (build-attr-tree tree1 0)])
|
||||
(check-equal? (attributed-node-num-leaves atree) 2))
|
||||
|
||||
#|
|
||||
a
|
||||
/ \
|
||||
b d
|
||||
| / \
|
||||
c e f
|
||||
|
|
||||
g
|
||||
|#
|
||||
(define tree2 (tree 'a
|
||||
(tree 'b
|
||||
(tree 'c))
|
||||
(tree 'd
|
||||
(tree 'e)
|
||||
(tree 'f
|
||||
(tree 'g)))))
|
||||
(let* ([layout (draw-tree tree2 #:node-width test-width #:padding test-padding)]
|
||||
[nodes (graph-layout-nodes layout)]
|
||||
[dnode-a (get-node 'a layout)]
|
||||
[dnode-b (get-node 'b layout)]
|
||||
[dnode-c (get-node 'c layout)]
|
||||
[dnode-d (get-node 'd layout)]
|
||||
[dnode-e (get-node 'e layout)]
|
||||
[dnode-f (get-node 'f layout)]
|
||||
[dnode-g (get-node 'g layout)])
|
||||
(check-equal? (node-data (drawable-node-node dnode-a)) 'a)
|
||||
(check-equal? (node-data (drawable-node-node dnode-b)) 'b)
|
||||
(check-equal? (node-data (drawable-node-node dnode-c)) 'c)
|
||||
(check-equal? (node-data (drawable-node-node dnode-d)) 'd)
|
||||
(check-equal? (node-data (drawable-node-node dnode-e)) 'e)
|
||||
(check-equal? (node-data (drawable-node-node dnode-f)) 'f)
|
||||
(check-equal? (node-data (drawable-node-node dnode-g)) 'g)
|
||||
(check-equal? (graph-layout-width layout) 50)
|
||||
(check-equal? (graph-layout-height layout) 65)
|
||||
(check-equal? (drawable-node-x dnode-a) (/ 65 4))
|
||||
(check-equal? (drawable-node-y dnode-a) test-padding)
|
||||
(check-equal? (drawable-node-x dnode-b) test-padding)
|
||||
(check-equal? (drawable-node-y dnode-b) (+ (* 2 test-padding) test-width))
|
||||
(check-equal? (drawable-node-x dnode-c) test-padding)
|
||||
(check-equal? (drawable-node-y dnode-c) (+ (drawable-node-y dnode-b) test-width test-padding))
|
||||
(check-equal? (drawable-node-x dnode-e) (+ (* 2 test-padding) test-width))
|
||||
(check-equal? (drawable-node-y dnode-e) (+ (drawable-node-y dnode-d) test-width test-padding))
|
||||
(check-equal? (drawable-node-x dnode-f) (+ (drawable-node-x dnode-e) test-width test-padding))
|
||||
(check-equal? (drawable-node-y dnode-f) (drawable-node-y dnode-e))
|
||||
(check-equal? (drawable-node-x dnode-g) (drawable-node-x dnode-f))
|
||||
(check-equal? (drawable-node-y dnode-g) (+ (drawable-node-y dnode-f) test-width test-padding)))
|
||||
(let ([atree (build-attr-tree tree2 0)])
|
||||
(check-equal? (attributed-node-num-leaves atree) 3))
|
||||
|
||||
#|
|
||||
a
|
||||
/|\
|
||||
b c e
|
||||
|
|
||||
d
|
||||
|#
|
||||
(define tree3 (tree 'a
|
||||
(tree 'b)
|
||||
(tree 'c
|
||||
(tree 'd))
|
||||
(tree 'e)))
|
||||
(let* ([layout (draw-tree tree3 #:node-width test-width #:padding test-padding)]
|
||||
[nodes (graph-layout-nodes layout)]
|
||||
[dnode-a (get-node 'a layout)]
|
||||
[dnode-b (get-node 'b layout)]
|
||||
[dnode-c (get-node 'c layout)]
|
||||
[dnode-d (get-node 'd layout)]
|
||||
[dnode-e (get-node 'e layout)])
|
||||
(check-equal? (graph-layout-width layout) 50)
|
||||
(check-equal? (graph-layout-height layout) 50)
|
||||
(check-equal? (drawable-node-x dnode-a) 20)
|
||||
(check-equal? (drawable-node-y dnode-a) 5)
|
||||
(check-equal? (drawable-node-x dnode-b) test-padding)
|
||||
(check-equal? (drawable-node-y dnode-b) (+ (* 2 test-padding) test-width))
|
||||
(check-equal? (drawable-node-x dnode-c) (+ (* 2 test-padding) test-width))
|
||||
(check-equal? (drawable-node-y dnode-c) (drawable-node-y dnode-b))
|
||||
(check-equal? (drawable-node-x dnode-e) (+ (* 3 test-padding) (* 2 test-width)))
|
||||
(check-equal? (drawable-node-y dnode-e) (drawable-node-y dnode-c))
|
||||
(check-equal? (drawable-node-x dnode-d) (drawable-node-x dnode-c))
|
||||
(check-equal? (drawable-node-y dnode-d) (+ (drawable-node-y dnode-c) test-padding test-width)))
|
||||
(let ([atree (build-attr-tree tree3 0)])
|
||||
(check-equal? (attributed-node-num-leaves atree) 3))
|
||||
|
||||
#|
|
||||
a
|
||||
/ | | \
|
||||
b c f g
|
||||
/ \
|
||||
d e
|
||||
|#
|
||||
(define tree4 (tree 'a
|
||||
(tree 'b)
|
||||
(tree 'c
|
||||
(tree 'd)
|
||||
(tree 'e))
|
||||
(tree 'f)
|
||||
(tree 'g)))
|
||||
(let* ([layout (draw-tree tree4 #:node-width test-width #:padding test-padding)]
|
||||
[nodes (graph-layout-nodes layout)]
|
||||
[dnode-a (get-node 'a layout)]
|
||||
[dnode-b (get-node 'b layout)]
|
||||
[dnode-c (get-node 'c layout)]
|
||||
[dnode-d (get-node 'd layout)]
|
||||
[dnode-e (get-node 'e layout)]
|
||||
[dnode-f (get-node 'f layout)]
|
||||
[dnode-g (get-node 'g layout)])
|
||||
(check-equal? (graph-layout-width layout) 80)
|
||||
(check-equal? (graph-layout-height layout) 50)
|
||||
(check-equal? (drawable-node-x dnode-b) test-padding)
|
||||
(check-equal? (drawable-node-y dnode-b) (+ (drawable-node-y dnode-a) test-width test-padding))
|
||||
(check-equal? (drawable-node-y dnode-c) (drawable-node-y dnode-b))
|
||||
(check-equal? (drawable-node-x dnode-d) (+ (drawable-node-x dnode-b) test-width test-padding))
|
||||
(check-equal? (drawable-node-y dnode-d) (+ (drawable-node-y dnode-c) test-width test-padding))
|
||||
(check-equal? (drawable-node-x dnode-e) (+ (drawable-node-x dnode-d) test-width test-padding))
|
||||
(check-equal? (drawable-node-y dnode-e) (drawable-node-y dnode-d))
|
||||
(check-equal? (drawable-node-x dnode-f) (+ (drawable-node-x dnode-e) test-width test-padding))
|
||||
(check-equal? (drawable-node-y dnode-f) (drawable-node-y dnode-c))
|
||||
(check-equal? (drawable-node-x dnode-g) (+ (drawable-node-x dnode-f) test-width test-padding)))
|
||||
(let ([atree (build-attr-tree tree4 0)])
|
||||
(check-equal? (attributed-node-num-leaves atree) 5))
|
||||
|
||||
#|
|
||||
Layered-tree-draw example from Di Battista
|
||||
a
|
||||
/ \
|
||||
b g
|
||||
| / \
|
||||
c h k
|
||||
| / \
|
||||
d i j
|
||||
/ \
|
||||
e f
|
||||
|#
|
||||
(define tree5 (tree 'a
|
||||
(tree 'b
|
||||
(tree 'c
|
||||
(tree 'd
|
||||
(tree 'e)
|
||||
(tree 'f))))
|
||||
(tree 'g
|
||||
(tree 'h
|
||||
(tree 'i)
|
||||
(tree 'j))
|
||||
(tree 'k))))
|
||||
(let* ([layout (draw-tree tree5 #:node-width test-width #:padding test-padding)]
|
||||
[nodes (graph-layout-nodes layout)]
|
||||
[dnode-a (get-node 'a layout)]
|
||||
[dnode-b (get-node 'b layout)]
|
||||
[dnode-c (get-node 'c layout)]
|
||||
[dnode-d (get-node 'd layout)]
|
||||
[dnode-e (get-node 'e layout)]
|
||||
[dnode-f (get-node 'f layout)]
|
||||
[dnode-g (get-node 'g layout)]
|
||||
[dnode-h (get-node 'h layout)]
|
||||
[dnode-i (get-node 'i layout)]
|
||||
[dnode-j (get-node 'j layout)]
|
||||
[dnode-k (get-node 'k layout)])
|
||||
(check-equal? (graph-layout-width layout) 80)
|
||||
(check-equal? (graph-layout-height layout) 80)
|
||||
(check-equal? (drawable-node-x dnode-e) test-padding)
|
||||
(check-equal? (drawable-node-y dnode-e) 65)
|
||||
(check-equal? (drawable-node-x dnode-f) (+ (drawable-node-x dnode-e) test-width test-padding))
|
||||
(check-equal? (drawable-node-x dnode-i) (+ (drawable-node-x dnode-f) test-width test-padding))
|
||||
(check-equal? (drawable-node-x dnode-j) (+ (drawable-node-x dnode-i) test-width test-padding))
|
||||
(check-equal? (drawable-node-x dnode-k) (+ (drawable-node-x dnode-j) test-width test-padding)))
|
||||
(let ([atree (build-attr-tree tree5 0)])
|
||||
(check-equal? (attributed-node-num-leaves atree) 5))
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user