diff --git a/collects/mztake/demos/highway/highway-test.ss b/collects/mztake/demos/highway/highway-test.ss index 36eff02198..bd603e33e3 100644 --- a/collects/mztake/demos/highway/highway-test.ss +++ b/collects/mztake/demos/highway/highway-test.ss @@ -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 \ No newline at end of file + +(start/resume radar-program) #| Start the process for highway.ss |# \ No newline at end of file diff --git a/collects/mztake/demos/misc/exception-test.ss b/collects/mztake/demos/misc/exception-test.ss index e0b077b8d2..e83b7277dc 100644 --- a/collects/mztake/demos/misc/exception-test.ss +++ b/collects/mztake/demos/misc/exception-test.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) \ No newline at end of file diff --git a/collects/mztake/demos/misc/first-class-test.ss b/collects/mztake/demos/misc/first-class-test.ss index eb641bb32f..1026e8384e 100644 --- a/collects/mztake/demos/misc/first-class-test.ss +++ b/collects/mztake/demos/misc/first-class-test.ss @@ -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) \ No newline at end of file diff --git a/collects/mztake/demos/montecarlo/montecarlo-test.ss b/collects/mztake/demos/montecarlo/montecarlo-test.ss index 1b5a6e0d2b..f455c7389b 100644 --- a/collects/mztake/demos/montecarlo/montecarlo-test.ss +++ b/collects/mztake/demos/montecarlo/montecarlo-test.ss @@ -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 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 draws only the points that are deemed *not* within - a radius of 200 pixels from the center of the window. -|# + 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 |# diff --git a/collects/mztake/demos/montecarlo/montecarlo.ss b/collects/mztake/demos/montecarlo/montecarlo.ss index 71915312c2..b05444e0b1 100644 --- a/collects/mztake/demos/montecarlo/montecarlo.ss +++ b/collects/mztake/demos/montecarlo/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)) \ No newline at end of file diff --git a/collects/mztake/demos/random/random screenshot.jpg b/collects/mztake/demos/random/random screenshot.jpg new file mode 100644 index 0000000000..f8bc9c8af6 Binary files /dev/null and b/collects/mztake/demos/random/random screenshot.jpg differ diff --git a/collects/mztake/demos/random/random-Xs-test.ss b/collects/mztake/demos/random/random-Xs-test.ss index 72e8912157..2c306b29ba 100644 --- a/collects/mztake/demos/random/random-Xs-test.ss +++ b/collects/mztake/demos/random/random-Xs-test.ss @@ -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)))) - ;; 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). + (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-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 \ No newline at end of file diff --git a/collects/mztake/demos/random/random-Xs.ss b/collects/mztake/demos/random/random-Xs.ss index 36c8b2c3fb..794c2fb9be 100644 --- a/collects/mztake/demos/random/random-Xs.ss +++ b/collects/mztake/demos/random/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)) \ No newline at end of file diff --git a/collects/mztake/demos/sine/sine-test.ss b/collects/mztake/demos/sine/sine-test.ss index f73e7bc7fd..3e9677992b 100644 --- a/collects/mztake/demos/sine/sine-test.ss +++ b/collects/mztake/demos/sine/sine-test.ss @@ -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 |# - (history-b 50 (changes (make-circle - (make-posn x sin-x) - 5 ; diameter - (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. -|# + (let ([x (+ 200 x)] + [sin-x (+ 200 (* 100 sin-x))]) + (history-b 50 (changes (make-circle + (make-posn x sin-x) + 5 + (if (< 200 sin-x) + (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 \ No newline at end of file +#| 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 |# \ No newline at end of file diff --git a/collects/mztake/demos/sine/sine.ss b/collects/mztake/demos/sine/sine.ss index 6ce9ab58ff..d152a4426c 100644 --- a/collects/mztake/demos/sine/sine.ss +++ b/collects/mztake/demos/sine/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)) \ No newline at end of file diff --git a/collects/mztake/doc.txt b/collects/mztake/doc.txt index 4eef70a85f..8602f2ec2d 100644 --- a/collects/mztake/doc.txt +++ b/collects/mztake/doc.txt @@ -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,9 +24,8 @@ 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 - ("highway.ss" [values-of-speed 3 4 bind 'speed])) + (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. + + Often used directly on ENTRY traces, counting how many + times ENTRY occured: (count-e entry-trace) + + Also useful to count how many times a BIND changed + by calling: (count-b (changes bind-trace)) -> (count-b b) +> (largest-val-b stream) +> (smallest-val-b stream) - Counts number of times a behavior's value - updates/changes (often used with BIND traces). + 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 ...) diff --git a/collects/mztake/private/useful-code.ss b/collects/mztake/private/useful-code.ss index 889f56f83c..9c4ac00d09 100644 --- a/collects/mztake/private/useful-code.ss +++ b/collects/mztake/private/useful-code.ss @@ -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 (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)) + (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)] + + [(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) @@ -35,4 +58,4 @@ ((and (list? x) (list? (first x))) (append (flatten (car x)) (flatten (cdr x)))) - (else (list x))))) + (else (list x))))) \ No newline at end of file