From ffd45198fa22045f4fce81330dcb245f3a5965a5 Mon Sep 17 00:00:00 2001 From: Jono Spiro Date: Fri, 6 Aug 2004 11:25:19 +0000 Subject: [PATCH] demos are updated based on feedback. a few "useful-code" functions were added and documented. svn: r149 --- collects/mztake/demos/highway/highway-test.ss | 34 ++-- collects/mztake/demos/misc/exception-test.ss | 7 +- .../mztake/demos/misc/first-class-test.ss | 8 +- .../demos/montecarlo/montecarlo-test.ss | 60 +++---- .../mztake/demos/montecarlo/montecarlo.ss | 7 +- .../mztake/demos/random/random screenshot.jpg | Bin 0 -> 65826 bytes .../mztake/demos/random/random-Xs-test.ss | 106 +++++++----- collects/mztake/demos/random/random-Xs.ss | 4 +- collects/mztake/demos/sine/sine-test.ss | 77 ++++----- collects/mztake/demos/sine/sine.ss | 4 +- collects/mztake/doc.txt | 152 ++++++++++++------ collects/mztake/private/useful-code.ss | 53 ++++-- 12 files changed, 311 insertions(+), 201 deletions(-) create mode 100644 collects/mztake/demos/random/random screenshot.jpg 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 0000000000000000000000000000000000000000..f8bc9c8af619c45edbc6b61a5bd24950ebb5c06a GIT binary patch literal 65826 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 .(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