racket/collects/mztake/doc.txt
Guillaume Marceau bf57c0e894 updated dox.txt
svn: r555
2005-08-06 00:58:08 +00:00

348 lines
12 KiB
Plaintext

============================================================
About MzTake
_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!). 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
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 signals (implemented as "event streams" and "behaviors"),
it is possible to respond to outside events concisely (without
using callbacks). Consider a MzTake script to monitor the
behavior of the program "highway.ss", in the demos directory
of the MzTake collection:
(define/bind (loc "highway.ss" 3 ) speed)
(printf-b "current speed: ~a" speed)
(set-running! (< speed 55))
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 third line
of "highway.ss". SPEED is a FrTime behavior that always
contains the *current* value of the variable named SPEED in
the target program.
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
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".
MzTake scripts are also powerful tools for building external
test suites. Whereas typical test cases may only assert that
the result of a computation is correct, MzTake scripts
can dynamically break open an execution, record inner state,
and *compute* with it. This allows you to confirm that the
intermediate steps which lead to a correct answer were
also correct. In the highway example, perhaps knowing the last ten speeds that
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 information -- we are
only interested in the last ten speeds, after all.
One possible solution:
(printf-b "last ten speeds: ~a" (history-b 10 (changes speed)))
HISTORY-B consumes a number and an event stream (CHANGES 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 SPEED. Though
this is is an improvement, we still can't *use* that list as
data to see what led to the exception. We might want to
puase the program when something goes awry.
(printf-b "last ten speeds: ~a" (history-b 10 (changes speed)))
(set-running! (< speed 55))
MzTake allows you to "pause" a target program anytime during
execution. Once paused, it becomes posssible to interactively
explore and compute with script variables. Once satisfied, you can easily resume
execution by typing "(set-running #t)", or end it
with "(kill)".
Finally, FrTime provides a rich animation library. Combined
with the MzTake debugger, it takes only a few lines to animate
your algorithms and see them in action, easily letting you
confirm (or refute!) that they are working correctly.
(display-shapes (make-speed-gauge (hold speed)))
============================================================
Demos
The demos directory contains a sub-directory for each of the demos.
For instance, the highway directory contains "highway.ss" and
"highway-mztake.ss". To run this demo, switch to the "FrTime" language
level from the "Experimental Languages" section of DrScheme's language
dialog, load "highway-mztake.ss", and click "Run". What you see is
generated by the debugging script. Each demo directory contains
the following two files: one is the program being debugged
(named after the directory), and the other is a file ending
in "...-mztake.ss" (the MzTake script).
./highway/highway-mztake.ss - The program simulates a very simple
speedometer, and the MzTake script
monitors it.
./sine/sine-mztake.ss - Plots values extracted from a program
which generates coordinates for a
single sine wave.
./random/random-mztake.ss - Tests the quality of Scheme's random
number generator with a histogram.
./exception/exception-mztake.ss - Demonstrates how MzTake catches exceptions.
./djikstra/dijkstra-mztake.ss - Debugs a buggy implementation of
Dijkstra's algorithm
============================================================
Functions
The demos demonstrate many ways to debug with MzTake using
FrTime, even if you are not very familiar with the language.
That said, in order to become more proficient in using MzTake,
you will want to learn more about the FrTime language.
You can refer to FrTime's own documentation by searching for
"frtime" in DrScheme's Help window. It explains how to use
time-varying behaviors and event streams in greater depth, and
also describes the many useful functions FrTime provides to work
with them.
============================================================
_Debugging with MzTake_
Conceptually, MzTake is a library for the FrTime languages
which provides
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.
MzTake itself defines the following functions:
_Installing Trace Points_
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.
> (define-mztake-process process-name
[target-filename trace-clause ...] ...)
> (kill)
Kills the process and releases all resources
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 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.
_Useful Functions for Time-Varying Values_
Note: FrTime uses a naming convention where functions which
return behaviors have names that end in "-b", and
functions that return event streams end in "-e".
Tips: When you have a behavior that you want to turn into
an event, use (changes behavior).
When you have an event that you want to be a
behavior, use (hold event)
MzTake defines a few functions on time-varying values
that are particularly useful when debugging:
> (history-e stream)
> (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-e n stream)
> (history-b n stream)
Keeps a list of the last n values of a behavior
Returns a list of at most n elements, where the
elements are the n last values seem on the stream,
in order, oldest first.
> (count-b stream)
Counts number of events seen on an eventstream.
Often used directly on ENTRY traces, counting how many
times ENTRY occured: (count-b entry-trace)
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 stream)
Matches a sequence of items in a list to the history
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 ...)
Displays the value of the behaviors with the given format,
using "~a" just like in Scheme's FORMAT function.
============================================================
Known Problems
* In general, you should not REQUIRE or use any functions on
acting on the structures of your target program in your
MzTake script.
ORIGINAL FILE:
(define-struct foo (a b))
(let ([x (make-foo 1 2)])
x)
MZTAKE SCRIPT:
(require "original-file.ss")
(define/bind (loc "original-file.ss" 3) x)
(foo-a x) ;; this will fail!
The target program and the MzTake will have different
instances of the struct, and the call to FOO-A will fail.
* The break button will *not* kill runaway client processes.
You must type (kill) or (kill-all).
* 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)
^ ^^^
Recommended syntax locations to use for trace points:
(define x 12)
(let ([x (add1 x)]) x)
^ ^^ ^ ^
* Don't rely entirely on MzTake to complain when you change
target code and your line/col locations in the script are out
of date. It can only raise an error if the locations are invalid.
* 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
as expected.
* Error handling is not perfect -- e.g., the little "bug"
buttons on syntax errors don't reference the correct code.
However, the messages that are printed are as accurate as
possible.
* On particularly fast computers, when running scripts with a
very high trace point density (traces are hit constantly,
potentially hundreds in a second, like in the Monte Carlo,
random-xs, and sine demos), the FrTime animation window may
appear unresponsive because of how fast it is redrawing.
* Currently, if you are running traces on two modules with the
same name, IN the same process, though in different directories,
there will probably be some sort of name-clash and strange error.
This will be fixed.
============================================================
Tips and Tricks
* If output seems difficult to read in the script, e.g. you ever
see "struct:signal" and a lot of garbage, try (print-struct #f)
before you do any printing, or use (value-now behavior-name) to
get a more usable/printable version of a FrTime behavior (the
caveat is that it is no longer 'reactive' and it may be out of
date after the moment it is processed).
* You can add trace points to first-class functions, and they
will send trace update from anywhere they are passed to and
invoked.
============================================================
Authors and Thanks
MzTake is an experimental debugger. It should enable new
debugging approaches that were not possible (easily) before.
Please send feedback to the PLT-Scheme mailing list:
http://www.plt-scheme.org/maillist/
We are eager to hear about how you are using MzTake!
Jonathan Spiro
Guillaume Marceau
Gregory Cooper
John Clements
Shriram Krishnamurthi
Please send bug reports to: jspiro@cs.brown.edu
---
Icons for MzTake come from the Gnome Project: Nautilus Emblems.
These are provided under the GPL license.
http://jimmac.musichall.cz/ikony.php3