svn: r146

This commit is contained in:
Jono Spiro 2004-08-05 20:32:09 +00:00
parent 40621f7288
commit 3ce041fcc0

View File

@ -1,43 +1,47 @@
============================================================
About MzTake
_MzTake_ is a _scripted debugger_ for PLT Scheme. It
helps programmers monitor the execution of a target
program as it unfolds. In the future, MzTake will
also let you interact with a paused program and
inspect its state.
_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.
MzTake scripts are written in the FrTime programming
language, which is bundled with DrScheme. The purpose of
FrTime is to support the implementation of reactive systems
in a functional style. The key abstraction it adds is a type
of value called a 'signal', which can change over time. FrTime
infers dataflow dependencies between signals and automatically
recomputes them when necessary.
language, which is bundled with DrScheme. FrTime supports the
implementation of reactive systems in a functional style.
The key abstraction it adds is a type of value called a 'signal',
which can change over time. FrTime infers dataflow dependencies
between signals and automatically recomputes them when necessary.
With siglans (implemented as "event streams" and "behaviors"),
With signals (implemented as "event streams" and "behaviors"),
it is possible to respond to outside events concisely (without
using callbacks). Consider the following MzTake script:
using callbacks). Consider a MzTake script to monitor the
behavior of the program "highway.ss", in the demos directory
of the MzTake collection:
(debug-process radar-program
("highway.ss" [values-of-speed 3 4 bind 'speed]))
(debug-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)
This code actually executes a target module in the file
"highway.ss" after installing a _trace point_ (also known
as a _watch point_) just before the Scheme syntax on the third
line (at the fourth column) of "highway.ss". "values-of-speed"
is is a FrTime event stream that always contains the *current*
This code executes a target module in the file "highway.ss"
after installing a _trace point_ (also known as a
_watch point_) just before the Scheme expression on the fourth
column of the third line of "highway.ss". VALUES-OF-SPEED
is a FrTime event stream that always contains the *current*
value (and potentially every past value) of the variable named
"speed", as it is bound at that point in execution/syntax.
SPEED, as it is bound to the values corresponding to that
syntactic location.
"printf-b" works like Scheme's printf" function, consuming a
PRINTF-B works like Scheme's PRINTF function, consuming a
format-string and fill-values, printing the result in
DrScheme's interaction pane. Whereas "printf" accumulates
outdated text on the screen, "printf-b" will replace old text
DrScheme's interaction pane. Whereas PRINTF accumulates
outdated text on the screen, PRINTF-B will replace old text
with updated text if any of the fill-values change. In this
invocation, it prints the current speed to screen, throughout
the execution of "highway.ss".
@ -54,30 +58,29 @@ elements in a list. We assert that all recorded speeds are
less than 55, otherwise we raise an exception:
(map-e (lambda (a-speed)
(when (>= a-speed 55) (raise 'too-fast!!)))
(when (>= a-speed 55) (raise 'too-fast!!)))
values-of-speed)
Of course, like most test suites, this only tells you
something went wrong. Perhaps knowing the last ten speeds that
led to this would prove useful. You could "printf" the value
led to this would prove useful. You could PRINTF the value
onto a new line each time, but after ten updates the screen
is already starting to fill up with useless data -- we are
only interested in the last ten speeds, afterall.
is already starting to fill up with information -- we are
only interested in the last ten speeds, after all.
One possible solution:
(printf-b "last ten speeds: ~a" (history-b 10 values-of-speed))
(map-e (lambda (a-speed)
(when (>= a-speed 55) (raise 'too-fast!!)))
(when (>= a-speed 55) (raise 'too-fast!!)))
values-of-speed)
"history-b" consumes a number and an event stream
("values-of-speed") and returns a FrTime behavior containing
a FIFO ordered list of the last ten values emitted on that
event stream. In this case, a list of the ten most recent
"speed"s seen during execution, up until the exception is raised.
This is an improvement, though, we still can't *use* that list
to see what led to the exception -- we just display them.
One possible solution:
HISTORY-B consumes a number and an event stream (VALUES-OF-SPEED),
returning a FrTime behavior containing a FIFO ordered list of
the last ten values emitted on that event stream. In this case,
HISTORY-B maintains a list of the ten most recent SPEEDS seen
on VALUES-OF-SPEED (up until the exception is raised). Though
this is is an improvement, we still can't *use* that list as
data to see what led to the exception. One possible solution:
(define last-ten (history-b 10 values-of-speed))
(printf-b "last ten speeds: ~a" last-ten)
@ -87,7 +90,7 @@ One possible solution:
MzTake allows you to "pause" a target program anytime during
execution. Once paused, it becomes trivial to interactively
explore and compute with script variables (such as "last-ten")
explore and compute with script variables (such as LAST-TEN)
in the interaction pane. Once satisfied, you can easily resume
execution by typing "(start/resume radar-program)", or end it
with "(kill radar-program)".
@ -105,7 +108,7 @@ confirm (or refute!) that they are working correctly.
Installing MzTake
MzTake is a DrScheme tool distributed as a self-installing
".PLT" file from the PLaneT Package Reposityory.
".PLT" file from the PLaneT Package Repository.
http://planet.plt-scheme.org/
@ -128,23 +131,25 @@ 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.
./demos/highway/highway-test.ss - a small MzTake example, shown above
./highway/highway-test.ss - a small MzTake example, shown above
./demos/sine/sine-test.ss - plots values extracted from the
running program
./sine/sine-test.ss - plots values extracted from the
running program
./demos/montecarlo/montecarlo-test.ss - visualizes the Monte Carlo integration
used to derive the value of pi
./montecarlo/montecarlo-test.ss - visualizes the Monte Carlo
integration used to derive the
value of pi
./demos/random/random-Xs-test.ss - tests the quality of Scheme's random
number generator with a histogram
./random/random-Xs-test.ss - tests the quality of Scheme's random
number generator with a histogram
./demos/misc/exception-test.ss - demonstrates how MzTake catches exceptions
./misc/exception-test.ss - demonstrates how MzTake catches exceptions
./demos/misc/first-class-test.ss - demonstrates how you can add multiple traces
to the same variable in a file to 'record' its
evolution, and how you can trace first-class
functions, such as those passed to map.
./misc/first-class-test.ss - demonstrates how you can add multiple
traces to the same variable in a file
to 'record' its evolution, and how you
can trace first-class functions, such
as those passed to map.
============================================================
@ -178,7 +183,7 @@ The model of the debugger is as follows:
Interaction and textual print-outs are provided in the
interaction pane.
* A MzTake process is like an operating system that runs a bunch of
* 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.
@ -196,7 +201,7 @@ The model of the debugger is as follows:
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 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.
@ -218,16 +223,16 @@ The model of the debugger is as follows:
(mztake-process p2
("more-my-stack-tests.ss")
((lib "my-stack.ss" "my-stack") [s-clear-p2 22 8 break]))
((lib "my-stack.ss" "my-stack") [s-clear-p2 22 8 ENTRY]))
This installs a break-trace at the function entry point for (clear).
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".
* Once all the processes are defined, (start/resume ...) is called on
each starting their execution.
* All the variables bound ("mztake-process"es, "bind"s, "break"s),
from all the different "mztake-process"es, are collected together by
* 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.
@ -237,7 +242,7 @@ The model of the debugger is as follows:
"process:exceptions", and "process:exited?".
* Lastly, proceses can be started, paused, resumed, and terminated.
See "start/resume", "pause", "kill", "kill-all".
See START/RESUME, PAUSE, KILL, KILL-ALL.
@ -247,8 +252,8 @@ MzTake itself defines the following functions:
_Installing Trace Points_
Currently, MzTake offers two types of traces: "break" and "bind".
Breaks are event streams that get a "#t" event ping every time the
Currently, MzTake offers two types of traces: ENTRY and BIND.
ENTRYs are event streams that get a "#t" event every time the
target program reaches the trace point. Binds are event streams that
ping the value of one or more variables when the trace point is reached.
@ -257,29 +262,29 @@ ping the value of one or more variables when the trace point is reached.
Where trace-clause is one of the following:
<1> [trace-name line-number column-number break]
<1> [trace-name line-number column-number ENTRY]
<2> [trace-name line-number column-number bind 'variable-name]
<3> [trace-name line-number column-number bind '(variable-name ...)]
"mztake-process" defines the variable process-name,
MZTAKE-PROCESS defines the variable process-name,
whose value is a MzTake process object. That object
can be passed to functions such as "start/resume", "kill",
can be passed to functions such as START/RESUME, KILL,
and "process:runtime/milliseconds", documented in the next
section.
"mztake-process" installs trace points in one or many files,
MZTAKE-PROCESS installs trace points in one or many files,
as indicated by the trace-clauses. The target-filename can
be any file specification accepted by the standard "require"
be any file specification accepted by the standard REQUIRE
syntax for modules:
* Absolute path:
(mztake-process p [(file "/home/me/test.ss") [brk 10 7 break]])
(mztake-process p [(file "/home/me/test.ss") [brk 10 7 ENTRY]])
* Relative path:
(mztake-process p ["../test.ss" [brk 10 7 break]])
(mztake-process p ["../test.ss" [brk 10 7 ENTRY]])
* Library path:
(mztake-process p [(lib “test.ss” “file-lib”) [brk 10 7 break]])
(mztake-process p [(lib "test.ss" "collect-dir") [brk 10 7 ENTRY]])
For each trace-clause in the call to mztake-process,
the trace-name is a variable name bound at the
@ -290,11 +295,11 @@ ping the value of one or more variables when the trace point is reached.
that event depends on which of the three kinds of
trace-clause was used, as follows:
<1> The value of the event is #t (a "break" trace).
<1> The value of the event is #t (an ENTRY trace).
<2> The value of the event is the value of variable-name,
in the target program, at the location of the
trace point (a "bind" trace).
trace point (a BIND trace).
<3> The value of the event is a list containing one
element for each variable name given. The value
@ -303,14 +308,14 @@ ping the value of one or more variables when the trace point is reached.
Trace points do not themselves pause the
program. Unless a MzTake process is suspended using
the pause function (below), execution resumes after
the PAUSE function (below), execution resumes after
the MzTake script processed the event.
[*] Valid locations to add traces to are almost
always one character to the left of open-parentheses, "(",
open-square-braces, "[", or to the left of the first
character of a symbol/name ("let" is a special exception,
see Known Issues for more information on tracing "let"):
character of a symbol/name (LET is a special exception,
see Known Problems for more information on tracing LET):
(code [more-code ...] ...)
^^ ^^ ^
@ -327,45 +332,45 @@ ping the value of one or more variables when the trace point is reached.
_Operations on MzTake Processes_
The following functions operate on MzTake processes, and
can be used interactively in the interactions pane.
The following functions operate on MzTake processes,
and can be used in the Interactions window.
> (start/resume process-name)
Start the execution and monitoring of the mztake-process,
process-name. If the process given to start/resume is already
running, and was paused with the function "pause" (below),
start/resume resumes its execution.
process-name. If the process given to START/RESUME is already
running, and was paused with the function PAUSE (below),
START/RESUME resumes its execution.
Script statements are executed top-down, sequentially.
In general, you want to call start/resume at the end of
the script, or in the interactions pane after you
start running the script. Otherwise, a race condition may
develop, and your script may miss events from the beginning
of the execution.
develop, where your script may miss events from the
beginning of the execution.
> (pause process)
Suspends the execution of the given mztake
process. Use start/resume to resume execution.
process. Use START/RESUME to resume execution.
> (kill process)
Kills the target process and releases all resources
it used -- you cannot start/resume after a kill.
it used -- you cannot START/RESUME after a KILL.
Closing a FrTime animation/graphics window will *not*
kill a running MzTake process. If it does not terminate
on its own, you may kill it with "(kill p-name)" or
"(kill-all)" in the interaction pane.
"(kill-all)" in the Interactions window.
> (kill-all)
kill-all kills all the processes currently running
under MzTake -- use this when it seems a process is
out of control and needs to be stopped immediately.
Has the same effect of calling kill on each process
you defined and start/resume'd in the script.
Has the same effect of calling KILL on each process
you defined and START/RESUME'd in the script.
> (process:exceptions process)
@ -378,14 +383,14 @@ can be used interactively in the interactions pane.
Returns a FrTime time-varying value which counts the
number of seconds elapsed in the execution of the
given process (not counting time spent suspended by
"pause"). Includes garbage-collection time.
PAUSE). Includes garbage-collection time.
> (process:runtime/milliseconds process)
Returns a FrTime time-varying value which counts the
number of milliseconds elapsed in the execution of the
given process (not counting time spent suspended by
"pause"). Includes garbage-collection time.
PAUSE). Includes garbage-collection time.
> (process:exited? process)
@ -410,12 +415,12 @@ that are particularly useful when debugging.
Counts number of event pings on an eventstream,
regardless of whether the value changes or not
(often used with "break" traces).
(often used with ENTRY traces).
> (count-b b)
Counts number of times a behavior's value
updates/changes (often used with "bind" traces).
updates/changes (often used with BIND traces).
> (sequence-match? seq evs)
@ -425,14 +430,14 @@ that are particularly useful when debugging.
> (printf-b format-string arg ...)
Displays the value of the behaviors with the given format,
using "~a" just like in Scheme's "format" function.
using "~a" just like in Scheme's FORMAT function.
============================================================
Known Issues
Known Problems
* In general, you should not "require" or use any methods
* In general, you should not REQUIRE or use any methods
in your MzTake script that were defined in any of the files
you are putting bind-traces on:
@ -453,10 +458,11 @@ Known Issues
* The break button will *not* kill runaway client processes.
You must type (kill process-name) or (kill-all).
* Some legal syntax locations, to add trace points to, do *not*
get triggered during execution, produce empty eventstreams.
These show up often in "let"s (the trace point being one line
above, and one character to the left of the carrot):
* Some legal syntax locations (used in setting trace points)
are unreachable during program execution (they do not get
triggered and produce empty eventstreams). So far, this only
shows up in LETs (the trace point being one line above,
and one character to the left of the carrot):
(define x 12)
(let ([x (add1 x)]) x)
@ -468,7 +474,7 @@ Known Issues
* Don't rely completely on MzTake to complain when you change
target code and your line/col locations in the script are out
of date. It will only raise an error if the locations are invalid.
of date. It can only raise an error if the locations are invalid.
* Order matters -- if you have more than one kind of trace at
an identical syntax location, the order that trace events get
@ -485,7 +491,7 @@ Known Issues
* MzTake has not been tested for stability if the target is using
multiple threads. This only applies to threaded modules
*with* traces on them -- other 'require'd modules will work
*with* traces on them -- other REQUIRE'd modules will work
as expected.
* Error handling is not perfect -- e.g., the little "bug"
@ -516,7 +522,7 @@ Tips and Tricks
* You may want to bind more than one variable at a certain point
so that you only get one change event -- otherwise, you will
get multiple change events even if at the same trace point
(see Known Issues).
(see Known Problems).
For instance, if you trace 'x and 'y separately:
* First 'x and 'y are up-to-date.
@ -551,7 +557,7 @@ Tips and Tricks
* Code such as (when (= num 100) (pause p)) pauses *after*
num reaches 100, the next time a trace point is hit.
However, the next point is not processed until you
"start/resume". See the random-xs demo.
START/RESUME. See the random-xs demo.
* When you pause a MzTake process, you can play with
current bindings and explore script code interactively.