348 lines
12 KiB
Plaintext
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
|