demos are updated based on feedback.
a few "useful-code" functions were added and documented. svn: r149
This commit is contained in:
parent
04e9cefc17
commit
ffd45198fa
|
@ -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]))
|
||||
|
@ -10,44 +10,46 @@
|
|||
this is right before the program sleeps for 1 second.
|
||||
|
||||
* At this tracepoint, define "values-of-speed" to a FrTime eventstream that
|
||||
recieves events containing a single numerical value:
|
||||
- The (lexically-scoped) current value of the variables `speed' are send
|
||||
every time the code at line 3, column 4, is reached.
|
||||
|#
|
||||
recieves events containing the current value of the variable `speed',
|
||||
which are sent every time the code at line 3, column 4, is reached. |#
|
||||
|
||||
|
||||
|
||||
(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))
|
||||
;; 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)))
|
||||
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)
|
||||
(let ([center (make-posn 200 200)])
|
||||
(list (make-circle center 170 "black")
|
||||
(make-circle center 160 "white")
|
||||
(make-rect (make-posn 0 202) 1000 1000 "white")
|
||||
(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
|
||||
(posn+ center (make-posn (- (* 150 (cos (/ speed 30))))
|
||||
(- (* 150 (sin (/ speed 30))))))
|
||||
"red"))))
|
||||
|
||||
|
||||
(display-shapes (make-speed-gauge (hold values-of-speed)))
|
||||
#| display-shapes takes a list of objects to draw.
|
||||
(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,
|
||||
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 |#
|
|
@ -3,15 +3,14 @@
|
|||
anonymous locations.
|
||||
|
||||
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"))
|
||||
|
||||
(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)))
|
||||
;; Prints out the last exception that the program threw
|
||||
#| Prints out the last exception that the program threw |#
|
||||
|
||||
(start/resume p)
|
|
@ -6,8 +6,7 @@
|
|||
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
|
||||
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]
|
||||
[x-in-let 4 25 bind 'x]
|
||||
|
@ -19,12 +18,11 @@
|
|||
x-after-let)))
|
||||
#| 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,
|
||||
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 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))
|
||||
;; 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)
|
|
@ -1,14 +1,22 @@
|
|||
#| The program being debugged (a module in the file "montecarlo.ss") runs an infinite loop,
|
||||
binding "x" and "y" to a random number between [-199,199] each iteration, and "pi"
|
||||
to the value of pi as calculated using this algorithm.
|
||||
#| The program being debugged (a module in the file "montecarlo.ss") runs
|
||||
an infinite loop, binding "x" and "y" to a random number between
|
||||
[-199,199], each iteration.
|
||||
|
||||
This MzTake script draws only the points that are deemed *not* within
|
||||
a radius of 200 pixels from the center of the window.
|
||||
|#
|
||||
This is supposed to represent throwing darts at a circular dartboard.
|
||||
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"))
|
||||
;; Needed for open-graphics, open-viewport, and draw-solid-ellipse
|
||||
#| Needed for open-graphics, open-viewport, and draw-solid-ellipse |#
|
||||
|
||||
|
||||
(open-graphics)
|
||||
(define window (open-viewport "Debugger" 400 400))
|
||||
|
@ -17,49 +25,47 @@
|
|||
and the dots are stationary -- so we just keep drawing the circles at
|
||||
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
|
||||
|
||||
* Add a tracepoint at line 13, column 18; in the program,
|
||||
this is right after the cond determined that the point is not in
|
||||
the radius of the circle. [else ->(loop ...)]
|
||||
* Add a tracepoint at line 13, column 13; in the program,
|
||||
this is right after the cond determined that the point *is* within
|
||||
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
|
||||
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))
|
||||
#| 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 y (+ 200 (second x/y/pi)))
|
||||
(define current-pi (third x/y/pi))
|
||||
#| 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 "log error: ~a" (log (abs (- current-pi 3.141592653)))) ;; the more negative, the better...
|
||||
|
||||
; more negative the better ...down to -14
|
||||
(printf-b "log error: ~a" (log (abs (- current-pi 3.1415926))))
|
||||
((draw-viewport window) "wheat")
|
||||
((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))
|
||||
3 3 "blue"))
|
||||
3 3 "black"))
|
||||
(changes (list x y)))
|
||||
#| 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 the process for montecarlo.ss
|
||||
(start/resume p) #| Start the process for montecarlo.ss |#
|
||||
|
|
|
@ -5,10 +5,11 @@
|
|||
(define (run)
|
||||
(let loop ([hits 1]
|
||||
[total 1])
|
||||
(let* ([x (- (random 400) 200)]
|
||||
[y (- (random 400) 200)]
|
||||
(let* ([x (- (random 401) 200)]
|
||||
[y (- (random 401) 200)]
|
||||
[length (sqrt (+ (* x x) (* y y)))]
|
||||
[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))]))))
|
||||
(run))
|
BIN
collects/mztake/demos/random/random screenshot.jpg
Normal file
BIN
collects/mztake/demos/random/random screenshot.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 64 KiB |
|
@ -1,13 +1,38 @@
|
|||
#| 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,
|
||||
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")
|
||||
;; Needed for open-graphics, open-viewport, and draw-solid-ellipse
|
||||
#| Needed for open-graphics, open-viewport, and draw-solid-ellipse |#
|
||||
|
||||
(lifted mzscheme
|
||||
make-hash-table
|
||||
|
@ -15,19 +40,21 @@
|
|||
hash-table-get))
|
||||
#| "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
|
||||
values (such as MzTake traces) as arguments.
|
||||
|#
|
||||
values (such as MzTake traces) as arguments. |#
|
||||
|
||||
|
||||
|
||||
(open-graphics)
|
||||
(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
|
||||
objects quickly reaches the thousands (slowing drawing time severly),
|
||||
and they are stationary -- so we just keep drawing the circles at
|
||||
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]))
|
||||
#| * Create a process to debug random-xs.ss
|
||||
|
@ -38,43 +65,48 @@
|
|||
|
||||
* At this tracepoint, define "x-trace" to a FrTime eventstream that
|
||||
recieves events containing the latest value of "x" seen,
|
||||
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.
|
||||
|#
|
||||
every time the code at line 4, column 6, is reached. |#
|
||||
|
||||
(define largest-bin 0)
|
||||
(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)
|
||||
(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.
|
||||
((draw-solid-ellipse window) (make-posn (* x 3)
|
||||
(- 500 (* 3 (hash-table-get valcount x (lambda () 1)))))
|
||||
4 4 "blue"))
|
||||
(changes x))
|
||||
#| Every time the local variable x changes (x-trace gets a new value), take this latest value ("==>")
|
||||
and pass it to a function which increments the count in the hashtable, and draws a circle in the window
|
||||
at (* x 3) pixels from the left, and the height is (3 * the latest count in the hashtable for that x).
|
||||
|
||||
((draw-solid-rectangle window) (make-posn (* x 6) (- 500 (* 2 new-cnt)))
|
||||
6 10 ;; width height
|
||||
(make-rgb 0 (* 0.75 color) color))))
|
||||
x-trace)
|
||||
#| Every time x-trace gets a new value, take this latest value and pass it to a function
|
||||
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)))
|
||||
#| prints the current value of x and a count of how many times x has changed,
|
||||
in other words, how many values are in the histogram
|
||||
|
||||
(printf-b "count: ~a" (count-b x-trace))
|
||||
#| prints the count of how many events x-trace got,
|
||||
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 the process for random-xs.ss
|
|
@ -1,5 +1,5 @@
|
|||
(module |random-Xs| mzscheme
|
||||
(define (run)
|
||||
(let loop ([x (random 200)])
|
||||
(loop (random 200))))
|
||||
(let loop ([x (random 100)])
|
||||
(loop (random 100))))
|
||||
(run))
|
|
@ -1,62 +1,63 @@
|
|||
#| 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
|
||||
|
||||
|
||||
(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
|
||||
|
||||
* Add a tracepoint at line 5, column 8; in the program,
|
||||
this is right after the let values are bound, ->(if (x ...)
|
||||
|
||||
* At this tracepoint, define "sin/x-trace" to a FrTime eventstream that
|
||||
recieves events containing a list of two elements:
|
||||
- The (lexically-scoped) current values of the variables `sin-x' and `x' are
|
||||
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
|
||||
* At this tracepoint, define "x/sinx-trace" to be a FrTime eventstream that
|
||||
recieves events containing a list of two elements -- the current values
|
||||
of the variables `x' and `sin-x', respectively. |#
|
||||
|
||||
|
||||
(printf-b "sine.ss exited? ~a" (process:exited? p))
|
||||
;; Prints out a behavior that tells you whether the mztake-process is still running...
|
||||
(define x/sinx (hold x/sinx-trace))
|
||||
#| the local variable "sin/x" now is a FrTime behavior that holds the current value of the list (sin-x x) |#
|
||||
|
||||
|
||||
(define sin/x (hold sin/x-trace))
|
||||
;; the local variable "sin/x" now is a FrTime behavior that holds the current value of the list (sin-x x)
|
||||
|
||||
|
||||
(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)
|
||||
(define x (first x/sinx))
|
||||
(define sin-x (second x/sinx))
|
||||
#| the local variables x, sin-x hold their current values |#
|
||||
|
||||
|
||||
(printf-b "x: ~a" x)
|
||||
(printf-b "sin(x): ~a" sin-x)
|
||||
;; Print the current values of x and sin-x
|
||||
(printf-b "sin(x/20): ~a" 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
|
||||
(list* (make-line (make-posn 0 200) (make-posn 400 200) "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
|
||||
(make-posn x sin-x)
|
||||
5 ; diameter
|
||||
5
|
||||
(if (< 200 sin-x)
|
||||
(if (< 200 x) "blue" "darkblue") ; Quadrants 3 and 4
|
||||
(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.
|
||||
|#
|
||||
(if (< 200 x) "blue" "darkblue") #| Quadrants 3 and 4 |#
|
||||
(if (< 200 x) "red" "darkred")))))))) #| 1 and 2 |#
|
||||
|
||||
(start/resume p)
|
||||
;; Start the process for sine.ss
|
||||
#| Make a circle at position x:(x + 200) and y:(100*sin(x/20) + 200) (scaled so we can draw it on screen)
|
||||
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 |#
|
|
@ -1,8 +1,8 @@
|
|||
(module sine mzscheme
|
||||
(define (run)
|
||||
(let loop ([x -200])
|
||||
(let ([sin-x (* 100 (sin (/ x 20.0)))])
|
||||
(if (x . <= . 200)
|
||||
(let ([sin-x (sin (/ x 20.0))])
|
||||
(if (x . < . 200)
|
||||
(loop (add1 x))
|
||||
(loop -200)))))
|
||||
(run))
|
|
@ -6,9 +6,10 @@
|
|||
|
||||
_MzTake_ is a _scripted debugger_ for PLT Scheme. It helps
|
||||
programmers monitor the execution of a target program as it
|
||||
unfolds (and optionally pause or resume its execution!).
|
||||
In the future, MzTake will support other kinds of interactions,
|
||||
such as inspecting the call stack.
|
||||
unfolds (and optionally pause or resume its execution!). MzTake
|
||||
gives you the power to easily write real programs that debug real
|
||||
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
|
||||
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
|
||||
of the MzTake collection:
|
||||
|
||||
(define-mztake-process
|
||||
radar-program
|
||||
(define-mztake-process radar-program
|
||||
("highway.ss" [values-of-speed 3 4 bind 'speed]))
|
||||
(printf-b "current speed: ~a" (hold values-of-speed))
|
||||
(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"
|
||||
(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
|
||||
|
||||
./sine/sine-test.ss - plots values extracted from the
|
||||
|
@ -178,73 +184,96 @@ with them.
|
|||
|
||||
_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
|
||||
processes, traces, bindings, animations, and other FrTime
|
||||
code fragments that do the debugging and program monitoring.
|
||||
|
||||
* This script file is run in the MzTake language in DrScheme.
|
||||
Interaction and textual print-outs are provided in the
|
||||
interaction pane.
|
||||
* This script file is loaded into the Definitions window in
|
||||
DrScheme, and run using the MzTake language. User interaction
|
||||
with the debugger is provided through the Interactions window.
|
||||
|
||||
* A MzTake *process* is like an operating system that runs a group of
|
||||
programs, installs hooks into them to monitor their execution,
|
||||
and provides FrTime with these hooks to do computations.
|
||||
|
||||
* Each MzTake process is independent of the other MzTake processes.
|
||||
One will not affect the other, only their traces can interact in
|
||||
the script.
|
||||
* Also like an operating system, each MzTake process runs
|
||||
independently of all other MzTake processes; one will not affect
|
||||
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
|
||||
debug and monitor. Each client should contain a module program,
|
||||
of the form:
|
||||
|
||||
(module mod-nam mzscheme
|
||||
(... module body ...))
|
||||
(module mod-name mzscheme
|
||||
... program-body ... )
|
||||
|
||||
MzTake does not support debugging anything other than modules.
|
||||
|
||||
* The first client defined for each process is *always* the main module.
|
||||
That is, START/RESUME runs the *first* client module (in the same way
|
||||
that you run it in DrScheme in the "module..." language), assuming there
|
||||
will be side-effects that start the debugging.
|
||||
* The first client defined for each MzTake process is *always* the
|
||||
main ("top level") module. That is, START/RESUME runs the main
|
||||
client module, in much the same way that you would run it in
|
||||
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
|
||||
modules used *by* the main-module, allowing you to see
|
||||
what is going on deeper than the main module. For example:
|
||||
The rest of the files traced in a MZTAKE-PROCESS are modules
|
||||
used *by* the main module, allowing you to see what is going
|
||||
on deeper than in the main-module. For example:
|
||||
|
||||
(define-mztake-process p1
|
||||
("my-stack-tests.ss")
|
||||
((lib "my-stack.ss" "my-stack") [s-push-p1 3 29 bind 'insert-value]
|
||||
[s-pop-p1 10 16 bind 'return-value]))
|
||||
|
||||
"my-stack-tests.ss" uses functions from "my-stack.ss". You want to
|
||||
make sure "my-stack.ss" is working properly in the context of
|
||||
running the module in "my-stack-tests.ss" for side-effects.
|
||||
"my-stack-tests.ss" is the main module. Suppose it is a test-suite
|
||||
for "my-stack.ss"; the test suite asserts that the stacks are not
|
||||
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
|
||||
different main clients using them:
|
||||
* The same module can be traced differently for each MzTake processe.
|
||||
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
|
||||
("more-my-stack-tests.ss")
|
||||
((lib "my-stack.ss" "my-stack") [s-clear-p2 22 8 ENTRY]))
|
||||
("my-stack-tests.ss")
|
||||
((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).
|
||||
Every time (clear) gets called, s-clear-p2 will get a ping of "#t".
|
||||
This installs an ENTRY trace at the function entry point for
|
||||
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
|
||||
each starting their execution.
|
||||
* Once a MzTake processe is defined, and all the script code operating
|
||||
on traces is defined, START/RESUME can be called on the process
|
||||
to begin its execution.
|
||||
|
||||
* All the variables bound (MZTAKE-PROCESSes, BINDs, ENTRYs),
|
||||
from all the different MZTAKE-PROCESSes, are collected together by
|
||||
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?".
|
||||
* All of the variables defined by traces (BINDs and ENTRYs on the active
|
||||
MzTake processes) are available simulatenously in the script.
|
||||
|
||||
* Lastly, proceses can be started, paused, resumed, and terminated.
|
||||
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_
|
||||
|
||||
MzTake defines a few functions on time-varying values
|
||||
that are particularly useful when debugging.
|
||||
Note: FrTime uss naming convention where functions which
|
||||
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)
|
||||
|
||||
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,
|
||||
in order, oldest first.
|
||||
|
||||
> (count-e stream)
|
||||
> (count-b stream)
|
||||
|
||||
Counts number of event pings on an eventstream,
|
||||
regardless of whether the value changes or not
|
||||
(often used with ENTRY traces).
|
||||
Counts number of events seen on an eventstream.
|
||||
|
||||
> (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
|
||||
updates/changes (often used with BIND traces).
|
||||
Also useful to count how many times a BIND changed
|
||||
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)
|
||||
|
||||
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 ...)
|
||||
|
||||
|
|
|
@ -6,25 +6,48 @@
|
|||
|
||||
(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
|
||||
(define (history-b n stream)
|
||||
(hold (history-e n stream) empty))
|
||||
(define/contract history-b (case-> (event? . -> . any)
|
||||
(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)
|
||||
(define ((add-to-hist thing) hist) (append (if ((length hist) . < . n) hist (rest hist)) (list thing)))
|
||||
(accum-e (stream . ==> . add-to-hist) empty))
|
||||
[(n stream)
|
||||
(define ((add-to-short-hist x) hist) (append (if (< (length hist) n) hist (rest hist)) (list x)))
|
||||
(accum-b (stream . ==> . add-to-short-hist) empty)]))
|
||||
|
||||
; Counts number of event pings on an eventstream
|
||||
(define (count-e evs)
|
||||
(accum-b (evs . -=> . add1) 0))
|
||||
; Counts number of events on an event stream
|
||||
(define/contract count-b (event? . -> . any)
|
||||
(lambda (stream)
|
||||
(accum-b (stream . -=> . add1) 0)))
|
||||
|
||||
; Counts number of times a behavior updates/changes
|
||||
(define (count-b b)
|
||||
(accum-b ((changes b) . -=> . add1) 0))
|
||||
; Keeps track of the largest value seen on a stream
|
||||
(define/contract largest-val-b (event? . -> . any)
|
||||
(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
|
||||
(define (sequence-match? seq evs)
|
||||
(equal? seq (history-b (length seq) evs)))
|
||||
(define/contract sequence-match? ((listof any?) . -> . any)
|
||||
(lambda (seq evs)
|
||||
(equal? seq (history-b (length seq) evs))))
|
||||
|
||||
; Cheap printf for behaviors
|
||||
(define printf-b format)
|
||||
|
|
Loading…
Reference in New Issue
Block a user