demos are updated based on feedback.

a few "useful-code" functions were added and documented.

svn: r149
This commit is contained in:
Jono Spiro 2004-08-06 11:25:19 +00:00
parent 04e9cefc17
commit ffd45198fa
12 changed files with 311 additions and 201 deletions

View File

@ -1,6 +1,6 @@
;; The program being debugged (a module in "highway.ss") generates fake speed readings over and over. #| The program being debugged (a module in "highway.ss") generates fake speed readings over and over. |#
(require (lib "animation.ss" "frtime")) ;; needed for display-shapes (require (lib "animation.ss" "frtime")) #| needed for display-shapes |#
(define-mztake-process radar-program ("highway.ss" [values-of-speed 3 4 bind 'speed])) (define-mztake-process radar-program ("highway.ss" [values-of-speed 3 4 bind 'speed]))
@ -10,44 +10,46 @@
this is right before the program sleeps for 1 second. this is right before the program sleeps for 1 second.
* At this tracepoint, define "values-of-speed" to a FrTime eventstream that * At this tracepoint, define "values-of-speed" to a FrTime eventstream that
recieves events containing a single numerical value: recieves events containing the current value of the variable `speed',
- The (lexically-scoped) current value of the variables `speed' are send which are sent every time the code at line 3, column 4, is reached. |#
every time the code at line 3, column 4, is reached.
|#
(printf-b "current speed: ~a" (hold values-of-speed)) (printf-b "current speed: ~a" (hold values-of-speed))
;; Prints the current speed being recorded #| Prints the current speed being recorded |#
(printf-b "last ten speeds: ~a" (history-b 10 values-of-speed)) (printf-b "last ten speeds: ~a" (history-b 10 values-of-speed))
;; prints a FIFO list of the last 10 speeds seen #| prints a FIFO list of the last 10 speeds seen |#
(map-e (lambda (a-speed) (when (>= a-speed 55) (pause radar-program))) (map-e (lambda (a-speed) (when (>= a-speed 55) (pause radar-program)))
values-of-speed) values-of-speed)
;; pauses the program for inspection when a speed is too fast #| pauses the program for inspection when a speed is too fast |#
;; produces a list of shapes to draw/animate, taking in a number for speed
#| produces a list of shapes to draw/animate, taking in a number for speed |#
(define (make-speed-gauge speed) (define (make-speed-gauge speed)
(let ([center (make-posn 200 200)]) (let ([center (make-posn 200 200)])
(list (make-circle center 170 "black") (list (make-circle center 170 "black")
(make-circle center 160 "white") (make-circle center 160 "white")
(make-rect (make-posn 0 202) 1000 1000 "white") (make-rect (make-posn 0 202) 1000 1000 "white")
(make-line (make-posn 30 201) (make-posn 370 201) "black") (make-line (make-posn 30 201) (make-posn 370 201) "black")
;; draws the the half-circle guage #| draws the the half-circle guage |#
;; draws the red line for the current speed #| draws the red line for the current speed |#
(make-line center (make-line center
(posn+ center (make-posn (- (* 150 (cos (/ speed 30)))) (posn+ center (make-posn (- (* 150 (cos (/ speed 30))))
(- (* 150 (sin (/ speed 30)))))) (- (* 150 (sin (/ speed 30))))))
"red")))) "red"))))
(display-shapes (make-speed-gauge (hold values-of-speed))) (display-shapes (make-speed-gauge (hold values-of-speed)))
#| display-shapes takes a list of objects to draw. #| display-shapes takes a list of objects to draw.
(hold values-of-speed) keeps track of the current value of speed, (hold values-of-speed) keeps track of the current value of speed,
as seen on the eventstream, and that is passed to make-speed-guage, as seen on the eventstream, and that is passed to make-speed-guage,
which gets called every time values-of-speed gets a new speed. which gets called every time values-of-speed gets a new speed. |#
|#
(start/resume radar-program)
;; Start the process for highway.ss (start/resume radar-program) #| Start the process for highway.ss |#

View File

@ -3,15 +3,14 @@
anonymous locations. anonymous locations.
We don't even need to bind any variables or add any breaks, we just We don't even need to bind any variables or add any breaks, we just
run the program and catch the exception it throws. run the program and catch the exception it throws. |#
|#
(define-mztake-process p ("exception.ss")) (define-mztake-process p ("exception.ss"))
(printf-b "exception.ss exited? ~a" (process:exited? p)) (printf-b "exception.ss exited? ~a" (process:exited? p))
;; Prints out a behavior that tells you whether the debug-process is still running... #| Prints out a behavior that tells you whether the debug-process is still running... |#
(printf-b "last exception seen: ~a" (hold (process:exceptions p))) (printf-b "last exception seen: ~a" (hold (process:exceptions p)))
;; Prints out the last exception that the program threw #| Prints out the last exception that the program threw |#
(start/resume p) (start/resume p)

View File

@ -6,8 +6,7 @@
and recieve different values, watching how an algorithm unfolds. and recieve different values, watching how an algorithm unfolds.
Be sure you look at first-class.ss to see where the bindings are taken from, to get Be sure you look at first-class.ss to see where the bindings are taken from, to get
and idea of why they recieve different values from the same "x". and idea of why they recieve different values from the same "x". |#
|#
(define-mztake-process p ("first-class.ss" [x-before-let 3 29 bind 'x] (define-mztake-process p ("first-class.ss" [x-before-let 3 29 bind 'x]
[x-in-let 4 25 bind 'x] [x-in-let 4 25 bind 'x]
@ -19,12 +18,11 @@
x-after-let))) x-after-let)))
#| merge-e takes multiple event streams and turns them into one event stream. #| merge-e takes multiple event streams and turns them into one event stream.
count-e then counts how many pings are recieved on all three streams, count-e then counts how many pings are recieved on all three streams,
in other words, how many times "x" updates in all the traces. in other words, how many times "x" updates in all the traces. |#
|#
(printf-b "x before let, should be (2 4 6 7): ~a" (history-b 4 x-before-let)) (printf-b "x before let, should be (2 4 6 7): ~a" (history-b 4 x-before-let))
(printf-b "x in let, should be (6 10 14 16): ~a" (history-b 4 x-in-let)) (printf-b "x in let, should be (6 10 14 16): ~a" (history-b 4 x-in-let))
(printf-b "x after let, should be (5 9 13 15): ~a" (history-b 4 x-after-let)) (printf-b "x after let, should be (5 9 13 15): ~a" (history-b 4 x-after-let))
;; Prints out a FIFO list containing the last 4 values seen by each trace. #| Prints out a FIFO list containing the last 4 values seen by each trace. |#
(start/resume p) (start/resume p)

View File

@ -1,14 +1,22 @@
#| The program being debugged (a module in the file "montecarlo.ss") runs an infinite loop, #| The program being debugged (a module in the file "montecarlo.ss") runs
binding "x" and "y" to a random number between [-199,199] each iteration, and "pi" an infinite loop, binding "x" and "y" to a random number between
to the value of pi as calculated using this algorithm. [-199,199], each iteration.
This MzTake script draws only the points that are deemed *not* within This is supposed to represent throwing darts at a circular dartboard.
a radius of 200 pixels from the center of the window. You keep a count of how many darts you have thrown, and a side count
|# for each time the dart is thrown within the circle. The ratio of
hits to total tries, multiplied by 4, approaches "pi" with some error,
usually closing in around 3.13. The target program does this computation
and binds it to the variable "pi".
This MzTake script visualizes the process, drawing points (darts)
that "hit" the circle, a radius of 200 pixels from the center of
the window. |#
(require (lib "graphics.ss" "graphics")) (require (lib "graphics.ss" "graphics"))
;; Needed for open-graphics, open-viewport, and draw-solid-ellipse #| Needed for open-graphics, open-viewport, and draw-solid-ellipse |#
(open-graphics) (open-graphics)
(define window (open-viewport "Debugger" 400 400)) (define window (open-viewport "Debugger" 400 400))
@ -17,49 +25,47 @@
and the dots are stationary -- so we just keep drawing the circles at and the dots are stationary -- so we just keep drawing the circles at
the random coordinates that we get from the target program. the random coordinates that we get from the target program.
See the doc for more information on this kind of drawing. See the doc for more information on this kind of drawing. |#
|#
(define-mztake-process p ("montecarlo.ss" [x/y/pi-trace 13 18 bind '(x y pi)]))
(define-mztake-process p ("montecarlo.ss" [x/y/pi-trace 13 13 bind '(x y pi)]))
#| * Create a process to debug montecarlo.ss #| * Create a process to debug montecarlo.ss
* Add a tracepoint at line 13, column 18; in the program, * Add a tracepoint at line 13, column 13; in the program,
this is right after the cond determined that the point is not in this is right after the cond determined that the point *is* within
the radius of the circle. [else ->(loop ...)] the radius of the circle, before starting the next iteration of the loop.
* At this tracepoint, define "x/y/pi-trace" to a FrTime eventstream that * At this tracepoint, define "x/y/pi-trace" to a FrTime eventstream that
recieves events containing a list of the latest values of "x" "y" and "pi" recieves events containing a list of the latest values of "x" "y" and "pi"
in a list, every time the code at line 13, column 18, is reached. in a list, every time the code at line 13, column 18, is reached. |#
|#
(define x/y/pi (hold x/y/pi-trace)) (define x/y/pi (hold x/y/pi-trace))
#| The local, time-varying variable "x/y/pi" is now is a FrTime behavior that always #| The local, time-varying variable "x/y/pi" is now is a FrTime behavior that always
holds the current (latest) list of values from x/y/pi-trace. holds the current (latest) list of values from x/y/pi-trace. |#
|#
(define x (+ 200 (first x/y/pi))) (define x (+ 200 (first x/y/pi)))
(define y (+ 200 (second x/y/pi))) (define y (+ 200 (second x/y/pi)))
(define current-pi (third x/y/pi)) (define current-pi (third x/y/pi))
#| The local, time-varying variables "x" "y" and "current-pi" are bound to #| The local, time-varying variables "x" "y" and "current-pi" are bound to
their respective values in the list from x/y/pi. their respective values in the list from x/y/pi. |#
|#
(printf-b "total points chosen: ~a" (count-b x)) (printf-b "total points chosen: ~a" (count-b (changes x)))
(printf-b "current computed value of pi: ~a" current-pi) (printf-b "current computed value of pi: ~a" current-pi)
(printf-b "log error: ~a" (log (abs (- current-pi 3.141592653)))) ;; the more negative, the better...
; more negative the better ...down to -14 ((draw-viewport window) "wheat")
(printf-b "log error: ~a" (log (abs (- current-pi 3.1415926)))) ((draw-solid-ellipse window) (make-posn -4 -4) 408 408 "black")
((draw-solid-ellipse window) (make-posn 0 0) 400 400 "sienna")
#| Draw the dartboard |#
(map-e (lambda (x/y) ((draw-solid-ellipse window) (make-posn (first x/y) (second x/y)) (map-e (lambda (x/y) ((draw-solid-ellipse window) (make-posn (first x/y) (second x/y))
3 3 "blue")) 3 3 "black"))
(changes (list x y))) (changes (list x y)))
#| Every time the list (x y) changes (x and y get a new value), take this latest list value ("==>") #| Every time the list (x y) changes (x and y get a new value), take this latest list value ("==>")
and pass it to a function which draws a circle at the x,y coordinates in the list. and pass it to a function which draws a circle at the x,y coordinates in the list. |#
|#
(start/resume p) (start/resume p) #| Start the process for montecarlo.ss |#
;; Start the process for montecarlo.ss

View File

@ -5,10 +5,11 @@
(define (run) (define (run)
(let loop ([hits 1] (let loop ([hits 1]
[total 1]) [total 1])
(let* ([x (- (random 400) 200)] (let* ([x (- (random 401) 200)]
[y (- (random 400) 200)] [y (- (random 401) 200)]
[length (sqrt (+ (* x x) (* y y)))] [length (sqrt (+ (* x x) (* y y)))]
[pi (* 4. (/ hits total))]) [pi (* 4. (/ hits total))])
(cond [(length . <= . 200) (loop (add1 hits) (add1 total))] (cond [(length . < . 200)
(loop (add1 hits) (add1 total))]
[else (loop hits (add1 total))])))) [else (loop hits (add1 total))]))))
(run)) (run))

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -1,13 +1,38 @@
#| The program being debugged (a module in the file "random-xs.ss") runs an infinite loop, #| The program being debugged (a module in the file "random-xs.ss") runs an infinite loop,
binding "x" to a random number between [0,199] each iteration. binding "x" to a random number between [0,100) each iteration.
This MzTake script draws a histogram of the values of x seen over time, This MzTake script draws a histogram of the values of x seen over time,
in sync with the execution of "random-xs.ss". in sync with the execution of "random-xs.ss". This will run until one
|# bar reaches the top of the screen.
This histogram provides three pieces of information:
* Each bar represents a bin, the height represents how many times
that "random" number was generated.
* The brighter the blue, the faster that bin is growing compared
to the others. The darker, the slower.
* You can see a history of speeds over time based on how the colors
change in each bin.
Try looking for small groupings of bins where all are light, or all
are dark -- these represent trends in the numbers.
Look for tortoises that stay low and black, and hares which are very
active and bright.
Notice how the bottom tends to be rather patchy with lots of color
variation (the "start-up" phase of the random number generator),
and then towards the middle of the screen, most of the blues have
settled down and evened out.
The bars drag a bit when moving upwards (the height goes up by 2, but
the redrawing of the latest color goes down 10 pixels) so that you can
spot vertical and horizontal trends more easily. |#
(require (lib "graphics.ss" "graphics") (require (lib "graphics.ss" "graphics")
;; Needed for open-graphics, open-viewport, and draw-solid-ellipse #| Needed for open-graphics, open-viewport, and draw-solid-ellipse |#
(lifted mzscheme (lifted mzscheme
make-hash-table make-hash-table
@ -15,19 +40,21 @@
hash-table-get)) hash-table-get))
#| "Lifted" is explained in FrTime's own documentation (plt/collects/frtime/doc.txt) #| "Lifted" is explained in FrTime's own documentation (plt/collects/frtime/doc.txt)
Quickly put, lifting extends the functions listed above so they can take FrTime time-varying Quickly put, lifting extends the functions listed above so they can take FrTime time-varying
values (such as MzTake traces) as arguments. values (such as MzTake traces) as arguments. |#
|#
(open-graphics) (open-graphics)
(define window (open-viewport "Debugger" 600 500)) (define window (open-viewport "Debugger" 600 500))
((draw-viewport window) (make-rgb 0.95 0.95 0.95))
#| This file doesn't animate a list of objects since the number of #| This file doesn't animate a list of objects since the number of
objects quickly reaches the thousands (slowing drawing time severly), objects quickly reaches the thousands (slowing drawing time severly),
and they are stationary -- so we just keep drawing the circles at and they are stationary -- so we just keep drawing the circles at
their new heights based on the value in the hashtable. their new heights based on the value in the hashtable.
See the doc for more information on this kind of drawing. See the doc for more information on this kind of drawing. |#
|#
(define-mztake-process p ("random-Xs.ss" [x-trace 4 6 bind 'x])) (define-mztake-process p ("random-Xs.ss" [x-trace 4 6 bind 'x]))
#| * Create a process to debug random-xs.ss #| * Create a process to debug random-xs.ss
@ -38,43 +65,48 @@
* At this tracepoint, define "x-trace" to a FrTime eventstream that * At this tracepoint, define "x-trace" to a FrTime eventstream that
recieves events containing the latest value of "x" seen, recieves events containing the latest value of "x" seen,
every time the code at line 4, column 6, is reached. every time the code at line 4, column 6, is reached. |#
|#
(define x (hold x-trace))
#| The local, time-varying variable "x" is now is a FrTime behavior that always
holds the current (latest) value of x-trace.
|#
(define largest-bin 0)
(define valcount (make-hash-table)) (define valcount (make-hash-table))
;; this will hold the counts for the histogram #| this will hold the counts for the histogram
x is the key, and the number of times x shows up is the value |#
(hold (x-trace . -=> .(printf-b "largest count: ~a" largest-bin)))
#| Prints out the largest count every time we get a new x-trace event |#
(map-e (lambda (x) (map-e (lambda (x)
(hash-table-put! valcount x (add1 (hash-table-get valcount x (lambda () 0)))) (let* ([new-cnt (add1 (hash-table-get valcount x (lambda () 0)))]
[color (/ new-cnt (add1 largest-bin))])
(when (= largest-bin 250)
(kill p))
; when one of the bars reaches the top of the screen, kill the program.
(when (> new-cnt largest-bin) (set! largest-bin new-cnt))
; keep track of the largest count
(hash-table-put! valcount x new-cnt)
;; increment the value in the hashtable, starting from 0 if none exists. ;; increment the value in the hashtable, starting from 0 if none exists.
((draw-solid-ellipse window) (make-posn (* x 3)
(- 500 (* 3 (hash-table-get valcount x (lambda () 1))))) ((draw-solid-rectangle window) (make-posn (* x 6) (- 500 (* 2 new-cnt)))
4 4 "blue")) 6 10 ;; width height
(changes x)) (make-rgb 0 (* 0.75 color) color))))
#| Every time the local variable x changes (x-trace gets a new value), take this latest value ("==>") x-trace)
and pass it to a function which increments the count in the hashtable, and draws a circle in the window #| Every time x-trace gets a new value, take this latest value and pass it to a function
at (* x 3) pixels from the left, and the height is (3 * the latest count in the hashtable for that x). which increments the count in the hashtable, and draws a circle in the window at
(* x 6) pixels from the left, and the height is (2 * the latest count in the hashtable for that x),
making a color (MAKE-RGB) that is lighter based on how fast it is growing.
|# |#
(printf-b "x: ~a" x)
(printf-b "count: ~a" (count-e (changes x))) (printf-b "count: ~a" (count-b x-trace))
#| prints the current value of x and a count of how many times x has changed, #| prints the count of how many events x-trace got,
in other words, how many values are in the histogram aka how many values are in the histogram and on the screen.
|# |#
(let ([cnt (count-e (changes x))])
(when (= 2000 cnt) (pause p)))
#| This binds the same type of count seen above to cnt,
when the histogram is showing 2000 values, pause the program
the next time the breakpoint is reached before doing anything else.
Then try restarting it with (start/resume p)
|#
(start/resume p) (start/resume p)
;; Start the process for random-xs.ss ;; Start the process for random-xs.ss

View File

@ -1,5 +1,5 @@
(module |random-Xs| mzscheme (module |random-Xs| mzscheme
(define (run) (define (run)
(let loop ([x (random 200)]) (let loop ([x (random 100)])
(loop (random 200)))) (loop (random 100))))
(run)) (run))

View File

@ -1,62 +1,63 @@
#| The program being debugged (a module in "sine.ss") runs an infinite loop, #| The program being debugged (a module in "sine.ss") runs an infinite loop,
binding "x" to a moment in time [-200,200], and "sin-x" to the sin(x) each iteration. binding "x" to a moment in time [-200,200], and "sin-x" to the sin(x/20) each iteration.
This MzTake script plots the value of x over time, in sync with the execution of "sine.ss". This MzTake script plots the value of x over time, in sync with the execution of "sine.ss". |#
|#
(require (lib "animation.ss" "frtime")) ;; needed for display-shapes (require (lib "animation.ss" "frtime")) ;; needed for display-shapes
(define-mztake-process p ("sine.ss" [sin/x-trace 5 8 bind '(sin-x x)])) (define-mztake-process p ("sine.ss" [x/sinx-trace 5 8 bind '(x sin-x)]))
#| * Create a process to debug sine.ss #| * Create a process to debug sine.ss
* Add a tracepoint at line 5, column 8; in the program, * Add a tracepoint at line 5, column 8; in the program,
this is right after the let values are bound, ->(if (x ...) this is right after the let values are bound, ->(if (x ...)
* At this tracepoint, define "sin/x-trace" to a FrTime eventstream that * At this tracepoint, define "x/sinx-trace" to be a FrTime eventstream that
recieves events containing a list of two elements: recieves events containing a list of two elements -- the current values
- The (lexically-scoped) current values of the variables `sin-x' and `x' are of the variables `x' and `sin-x', respectively. |#
sent as a list every time the code at line 5, column 8, is reached.
|#
(printf-b "runtime elapsed: ~a" (process:runtime/seconds p))
;; Prints how long the program has been running, in seconds
(printf-b "sine.ss exited? ~a" (process:exited? p)) (define x/sinx (hold x/sinx-trace))
;; Prints out a behavior that tells you whether the mztake-process is still running... #| the local variable "sin/x" now is a FrTime behavior that holds the current value of the list (sin-x x) |#
(define x (first x/sinx))
(define sin/x (hold sin/x-trace)) (define sin-x (second x/sinx))
;; the local variable "sin/x" now is a FrTime behavior that holds the current value of the list (sin-x x) #| the local variables x, sin-x hold their current values |#
(define sin-x (+ 200 (first sin/x)))
(define x (+ 200 (second sin/x)))
;; "x" and "sin-x" are the current values of (x + 200) and (sin(x) + 200)
(printf-b "x: ~a" x) (printf-b "x: ~a" x)
(printf-b "sin(x): ~a" sin-x) (printf-b "sin(x/20): ~a" sin-x)
;; Print the current values of x and sin-x #| Print the current values of x and sin-x |#
(printf-b "largest x: ~a sin(x/20): ~a"
(largest-val-b (changes (first x/sinx)))
(largest-val-b (changes (second x/sinx))))
(printf-b "smallest x:~a sin(x/20):~a"
(smallest-val-b (changes (first x/sinx)))
(smallest-val-b (changes (second x/sinx))))
(display-shapes (display-shapes
(list* (make-line (make-posn 0 200) (make-posn 400 200) "gray") (list* (make-line (make-posn 0 200) (make-posn 400 200) "gray")
(make-line (make-posn 200 0) (make-posn 200 400) "gray") (make-line (make-posn 200 0) (make-posn 200 400) "gray")
;; draw horizontal and vertical gray lines #| draw horizontal and vertical gray lines |#
(let ([x (+ 200 x)]
[sin-x (+ 200 (* 100 sin-x))])
(history-b 50 (changes (make-circle (history-b 50 (changes (make-circle
(make-posn x sin-x) (make-posn x sin-x)
5 ; diameter 5
(if (< 200 sin-x) (if (< 200 sin-x)
(if (< 200 x) "blue" "darkblue") ; Quadrants 3 and 4 (if (< 200 x) "blue" "darkblue") #| Quadrants 3 and 4 |#
(if (< 200 x) "red" "darkred"))))))) ; 1 and 2 (if (< 200 x) "red" "darkred")))))))) #| 1 and 2 |#
#| * Make a circle at position (x, sin-x) with diameter 5 pixels, and a color based on the coords.
* Everytime this value (the circle) changes (when the values of x and sin-x change)
* Keep a history (as a FIFO list) of (up to) the last 50 circles that were created.
* Pass this list to the display-shapes function, which will redraw everytime this list changes.
|#
(start/resume p) #| Make a circle at position x:(x + 200) and y:(100*sin(x/20) + 200) (scaled so we can draw it on screen)
;; Start the process for sine.ss with diameter of 5 pixels, and a color based on which quadrant the coordinate is in.
Every time this value (the circle) changes (when the values of x and sin-x change):
* Keep a history (as a FIFO list) of (up to) the last 50 circles that were created.
* Pass this list to the display-shapes function, which will redraw every time this list changes. |#
(start/resume p) #| Start the process for sine.ss |#

View File

@ -1,8 +1,8 @@
(module sine mzscheme (module sine mzscheme
(define (run) (define (run)
(let loop ([x -200]) (let loop ([x -200])
(let ([sin-x (* 100 (sin (/ x 20.0)))]) (let ([sin-x (sin (/ x 20.0))])
(if (x . <= . 200) (if (x . < . 200)
(loop (add1 x)) (loop (add1 x))
(loop -200))))) (loop -200)))))
(run)) (run))

View File

@ -6,9 +6,10 @@
_MzTake_ is a _scripted debugger_ for PLT Scheme. It helps _MzTake_ is a _scripted debugger_ for PLT Scheme. It helps
programmers monitor the execution of a target program as it programmers monitor the execution of a target program as it
unfolds (and optionally pause or resume its execution!). unfolds (and optionally pause or resume its execution!). MzTake
In the future, MzTake will support other kinds of interactions, gives you the power to easily write real programs that debug real
such as inspecting the call stack. programs. You are no longer limited to a tool chest of buttons
like "add breakpoint", "step-next", "step-into", and "step-over".
MzTake scripts are written in the FrTime programming MzTake scripts are written in the FrTime programming
language, which is bundled with DrScheme. FrTime supports the language, which is bundled with DrScheme. FrTime supports the
@ -23,8 +24,7 @@ using callbacks). Consider a MzTake script to monitor the
behavior of the program "highway.ss", in the demos directory behavior of the program "highway.ss", in the demos directory
of the MzTake collection: of the MzTake collection:
(define-mztake-process (define-mztake-process radar-program
radar-program
("highway.ss" [values-of-speed 3 4 bind 'speed])) ("highway.ss" [values-of-speed 3 4 bind 'speed]))
(printf-b "current speed: ~a" (hold values-of-speed)) (printf-b "current speed: ~a" (hold values-of-speed))
(start/resume radar-program) (start/resume radar-program)
@ -136,6 +136,12 @@ You should be able to run them in DrScheme by switching to the
of DrScheme's language dialog, and then selecting "Run" of DrScheme's language dialog, and then selecting "Run"
(or "Execute") from the DrScheme tool bar. (or "Execute") from the DrScheme tool bar.
The demos are listed in order of complexity. When you open them
in DrScheme, don't let the amount of text overwhelm you -- the
scripts themselves are only a few lines of code. However, the
commenting is *exhaustive* so that a FrTime novice can still use
MzTake without ever having written a FrTime script before!
./highway/highway-test.ss - a small MzTake example, shown above ./highway/highway-test.ss - a small MzTake example, shown above
./sine/sine-test.ss - plots values extracted from the ./sine/sine-test.ss - plots values extracted from the
@ -178,73 +184,96 @@ with them.
_Debugging with MzTake_ _Debugging with MzTake_
The model of the debugger is as follows: Conceptually, MzTake is an extension of FrTime, providing
functions that execute a target program (or many!), and
"connect" to points in its code. MzTake then provides the
running FrTime script with interesting information (such as
a variable's current value) which it derives from these
"connections". FrTime then handles the rest.
FrTime takes that information and lets the script author
compute with it, verify it, print it, make visualizations
with it, anything you would like to do.
Currently, other than the powerful monitoring facilities that
MzTake provides (see BIND and ENTRY in the next section), user
interaction is limited to pausing/resuming the running program,
and operating on a few properties and predicates over general
program state (see PROCESS:EXITED?, PROCESS:RUNTIME/SECONDS,
and PROCESS:EXCEPTIONS). In the future, MzTake will offer other
types of interaction and information, such as inspecting
(and stepping through!) the call stack.
In more depth, the debugger works on a model roughly as follows:
* A single debugging script file contains all the MzTake * A single debugging script file contains all the MzTake
processes, traces, bindings, animations, and other FrTime processes, traces, bindings, animations, and other FrTime
code fragments that do the debugging and program monitoring. code fragments that do the debugging and program monitoring.
* This script file is run in the MzTake language in DrScheme. * This script file is loaded into the Definitions window in
Interaction and textual print-outs are provided in the DrScheme, and run using the MzTake language. User interaction
interaction pane. with the debugger is provided through the Interactions window.
* A MzTake *process* is like an operating system that runs a group of * A MzTake *process* is like an operating system that runs a group of
programs, installs hooks into them to monitor their execution, programs, installs hooks into them to monitor their execution,
and provides FrTime with these hooks to do computations. and provides FrTime with these hooks to do computations.
* Each MzTake process is independent of the other MzTake processes. * Also like an operating system, each MzTake process runs
One will not affect the other, only their traces can interact in independently of all other MzTake processes; one will not affect
the script. another. They can "interact" in the script by adding traces and
computing with those traces.
* A MzTake process accepts a number of target-files as "clients" to * A MzTake process accepts a number of target-files as "clients" to
debug and monitor. Each client should contain a module program, debug and monitor. Each client should contain a module program,
of the form: of the form:
(module mod-nam mzscheme (module mod-name mzscheme
(... module body ...)) ... program-body ... )
MzTake does not support debugging anything other than modules. MzTake does not support debugging anything other than modules.
* The first client defined for each process is *always* the main module. * The first client defined for each MzTake process is *always* the
That is, START/RESUME runs the *first* client module (in the same way main ("top level") module. That is, START/RESUME runs the main
that you run it in DrScheme in the "module..." language), assuming there client module, in much the same way that you would run it in
will be side-effects that start the debugging. DrScheme (in the "module..." language). It is assumed the module
has "side-effects" which start the target program.
The rest of the files traced in a MZTAKE-PROCESS are typically The rest of the files traced in a MZTAKE-PROCESS are modules
modules used *by* the main-module, allowing you to see used *by* the main module, allowing you to see what is going
what is going on deeper than the main module. For example: on deeper than in the main-module. For example:
(define-mztake-process p1 (define-mztake-process p1
("my-stack-tests.ss") ("my-stack-tests.ss")
((lib "my-stack.ss" "my-stack") [s-push-p1 3 29 bind 'insert-value] ((lib "my-stack.ss" "my-stack") [s-push-p1 3 29 bind 'insert-value]
[s-pop-p1 10 16 bind 'return-value])) [s-pop-p1 10 16 bind 'return-value]))
"my-stack-tests.ss" uses functions from "my-stack.ss". You want to "my-stack-tests.ss" is the main module. Suppose it is a test-suite
make sure "my-stack.ss" is working properly in the context of for "my-stack.ss"; the test suite asserts that the stacks are not
running the module in "my-stack-tests.ss" for side-effects. working as expected. You may want to use these traces to test how
"my-stack.ss" is operating "inside" during the test-suite.
Watch the pushes and pops and see how they correlate to what you expect.
* The same file can be traced differently in different processes, even with * The same module can be traced differently for each MzTake processe.
different main clients using them: Lets say that in the same script you want to see why the stack is using
a lot more memory than expected. You can set traces to count how many times
spaces is allocated and cleared and see if they are equal.
(define-mztake-process p2 (define-mztake-process p2
("more-my-stack-tests.ss") ("my-stack-tests.ss")
((lib "my-stack.ss" "my-stack") [s-clear-p2 22 8 ENTRY])) ((lib "my-stack.ss" "my-stack") [s-allocates-p2 22 2 entry]
[s-clears-p2 28 2 entry]))
This installs an ENTRY trace at the function entry point for (clear). This installs an ENTRY trace at the function entry point for
Every time (clear) gets called, s-clear-p2 will get a ping of "#t". ALLOCATE-STACK and CLEAR-STACK in "my-stack.ss". Every time
those functions get called, these traces will send a "#t" event,
and could be counted using COUNT-E.
* Once all the processes are defined, (start/resume ...) is called on * Once a MzTake processe is defined, and all the script code operating
each starting their execution. on traces is defined, START/RESUME can be called on the process
to begin its execution.
* All the variables bound (MZTAKE-PROCESSes, BINDs, ENTRYs), * All of the variables defined by traces (BINDs and ENTRYs on the active
from all the different MZTAKE-PROCESSes, are collected together by MzTake processes) are available simulatenously in the script.
MzTake so they can be all be computed with using FrTime functions
and idioms.
* Processes have certain properties and predicates which you can get,
such as runtime (in seconds or milliseconds), exceptions that are thrown,
and whether the process exited yet. See "process:runtime/(milli)seconds",
"process:exceptions", and "process:exited?".
* Lastly, proceses can be started, paused, resumed, and terminated. * Lastly, proceses can be started, paused, resumed, and terminated.
See START/RESUME, PAUSE, KILL, KILL-ALL. See START/RESUME, PAUSE, KILL, KILL-ALL.
@ -405,10 +434,21 @@ and can be used in the Interactions window.
_Useful Functions for Time-Varying Values_ _Useful Functions for Time-Varying Values_
MzTake defines a few functions on time-varying values Note: FrTime uss naming convention where functions which
that are particularly useful when debugging. return behaviors have names that end in "-b", and
functions that return event streams end in "-e".
MzTake defines a few functions on time-varying values
that are particularly useful when debugging:
> (history-b stream)
Keeps a complete history of all the values seen
on an event stream as a list, oldest events last.
Use with BINDs: (history-b x-trace)
> (history-b n stream) > (history-b n stream)
Keeps a list of the last n values of a behavior Keeps a list of the last n values of a behavior
@ -416,21 +456,29 @@ that are particularly useful when debugging.
elements are the n last values seem on the stream, elements are the n last values seem on the stream,
in order, oldest first. in order, oldest first.
> (count-e stream) > (count-b stream)
Counts number of event pings on an eventstream, Counts number of events seen on an eventstream.
regardless of whether the value changes or not
(often used with ENTRY traces).
> (count-b b) Often used directly on ENTRY traces, counting how many
times ENTRY occured: (count-e entry-trace)
Counts number of times a behavior's value Also useful to count how many times a BIND changed
updates/changes (often used with BIND traces). by calling: (count-b (changes bind-trace))
> (largest-val-b stream)
> (smallest-val-b stream)
Keeps track of the largest/smallest values seen on a stream.
Use with BINDs: (largest-val-b (changes bind-trace)).
> (sequence-match? seq evs) > (sequence-match? seq evs)
Matches a sequence of items in a list to the history Matches a sequence of items in a list to the history
of event pings, on the event stream evs. of event pings, on the event stream evs. Returns #t
when it matches, and #f otherwise. Use when you expect
a certain pattern to show up, and want to know when:
(sequence-match? '(0 1 2 1 0) (changes bind-trace))
> (printf-b format-string arg ...) > (printf-b format-string arg ...)

View File

@ -6,25 +6,48 @@
(provide (all-defined)) (provide (all-defined))
; Everything is contracted to 'any' for speed benefits, though there is already a big performance hit
; Keeps a list of the last n values of a behavior ; Keeps a list of the last n values of a behavior
(define (history-b n stream) (define/contract history-b (case-> (event? . -> . any)
(hold (history-e n stream) empty)) (number? event? . -> . any))
(case-lambda [(stream)
(define ((add-to-complete-hist x) hist) (append hist (list x)))
(accum-b (stream . ==> . add-to-complete-hist) empty)]
(define (history-e n stream) [(n stream)
(define ((add-to-hist thing) hist) (append (if ((length hist) . < . n) hist (rest hist)) (list thing))) (define ((add-to-short-hist x) hist) (append (if (< (length hist) n) hist (rest hist)) (list x)))
(accum-e (stream . ==> . add-to-hist) empty)) (accum-b (stream . ==> . add-to-short-hist) empty)]))
; Counts number of event pings on an eventstream ; Counts number of events on an event stream
(define (count-e evs) (define/contract count-b (event? . -> . any)
(accum-b (evs . -=> . add1) 0)) (lambda (stream)
(accum-b (stream . -=> . add1) 0)))
; Counts number of times a behavior updates/changes ; Keeps track of the largest value seen on a stream
(define (count-b b) (define/contract largest-val-b (event? . -> . any)
(accum-b ((changes b) . -=> . add1) 0)) (lambda (stream)
(hold (accum-e (stream
. ==> .
(lambda (last)
(lambda (x)
(if (> x last) x last))))
-inf.0))))
; Keeps track of the smallest value seen on a stream
(define/contract smallest-val-b (event? . -> . any)
(lambda (stream)
(hold (accum-e (stream
. ==> .
(lambda (last)
(lambda (x)
(if (< x last) x last))))
+inf.0))))
; Matches a sequence of items in a list to event pings ; Matches a sequence of items in a list to event pings
(define (sequence-match? seq evs) (define/contract sequence-match? ((listof any?) . -> . any)
(equal? seq (history-b (length seq) evs))) (lambda (seq evs)
(equal? seq (history-b (length seq) evs))))
; Cheap printf for behaviors ; Cheap printf for behaviors
(define printf-b format) (define printf-b format)