added NAP-TIME to highway.ss

changed WHERE from a behavior to an event and updated sprofiler-mztake
accordingly

svn: r1617
This commit is contained in:
Greg Cooper 2005-12-15 01:29:48 +00:00
parent 5f88a3d5f3
commit 9206b90b8a
6 changed files with 105 additions and 114 deletions

View File

@ -2,7 +2,7 @@
(lib "animation.ss" "frtime")
(lib "useful-code.ss" "mztake"))
(define/bind (loc "highway.ss" 3) speed)
(define/bind (loc "highway.ss" 4) speed)
(printf-b "current speed: ~a" speed)

View File

@ -1,5 +1,6 @@
(module highway mzscheme
(let loop ([speed 0])
(sleep 1)
;; Generate some fake speeds readings:
(loop (+ speed 4))))
(let ([nap-time 0.8])
(let loop ([speed 0])
(sleep nap-time)
;; Generate some fake speeds readings:
(loop (+ speed 4)))))

View File

@ -10,10 +10,10 @@
(define pings (make-hash 'equal))
((changes (where))
. ==> . (match-lambda [(line function context rest ...)
(hash-table-increment! pings (list function context))]
[_ (void)]))
(for-each-e (where)
(match-lambda [(line function context rest ...)
(hash-table-increment! pings (list function context))]
[_ (void)]))
(define clicks (changes (quotient milliseconds 50)))

View File

@ -4,56 +4,57 @@
About MzTake
_MzTake_ is a _scripted debugger_ for PLT Scheme. It helps
_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
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
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
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. In
which can change over time. FrTime infers dataflow dependencies
between signals and automatically recomputes them when necessary. In
order to use MzTake, you will need to familiarize yourself with the
FrTime language by reading its own documentation.
With signals 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:
without using callbacks. Consider a MzTake script to monitor the
behavior of the program "highway-mztake.ss", in the demos directory of
the MzTake collection:
(require (lib "mztake.ss" "mztake"))
(define/bind (loc "highway.ss" 3) speed)
(printf-b "current speed: ~a" speed)
;; more code
(set-running! true)
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
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
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
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". The last line invokes SET-RUNNING!,
the execution of "highway.ss". The last line invokes SET-RUNNING!,
which lunches the execution of highway.ss
MzTake scripts are also powerful tools for building external
test suites. Whereas typical test cases may only assert that
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
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
also correct. In the highway example, perhaps knowing the last ten speeds
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.
@ -64,44 +65,30 @@ One possible solution:
HISTORY-B consumes an event stream (CHANGES SPEED) and an
optional number n, returning a FrTime behavior containing a
FIFO ordered list of the n values emitted on that event
stream. In this case, HISTORY-B maintains a list of the ten
stream. In this case, HISTORY-B maintains a list of the ten
most recent SPEEDS seen on SPEED.
We might want to pause the program when something goes awry. We do
this by exploiting the fact that SET-RUNNING! function consumes a
FrTime behavior. The value of a behavior can change over time, and
SET-RUNNING! monitor these changes. Whenever the behavior is true, the
target program runs, whenever it is false, the target program
pauses. We can indicate to MzTake to pause when the speed exceeds 55
We might want to pause the program when something goes awry. We do
this by exploiting the fact that the SET-RUNNING! function consumes a
FrTime behavior. The value of a behavior can change over time, and
SET-RUNNING! monitors these changes. Whenever the behavior is true,
the target program runs, and whenever it is false, the target program
pauses. We can indicate to MzTake to pause when the speed exceeds 55
as follow:
(printf-b "last ten speeds: ~a" (history-b (changes speed) 10))
(set-running! (< speed 55))
Once paused, it becomes possible to interactively explore the state of
the paused process. You can use the BIND function to reach into the
scope of the target process and read the value of the variable:
(bind (speed) (printf "the speed is ~a~n" speed))
This lines finds the variable named "speed" in the scope at the point
where the execution is paused, then binds its values to a variable
named "speed" in the MzTake script, then executes its body. In this
case, it print the value with PRINTF.
Since MzTake defines a #%top syntax, you can also directly type the
name of a variable. MzTake will first look in the scope in the MzTake
script. If the variable is not found, it will then in the target
process. So, the example above can be written as:
(printf "the speed is ~a~n" speed)
so long as the script itself does not declare a SPEED variable.
Once paused, it is possible to interactively explore the state of the
paused process. You may enter names of variables bound in the target
program, and MzTake will look up and return their values. For
example, typing 'nap-time' in the REPL while the program is paused
yields the value 0.8.
You can resume execution with "(set-running #t)", or
some other behavior, or end the execution altogether with "(kill)".
Finally, FrTime provides a rich animation library. Combined
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.
@ -116,10 +103,10 @@ confirm (or refute!) that they are working correctly.
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
"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
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).
@ -128,7 +115,7 @@ The demos are (starting with the simplest one):
./highway/highway-mztake.ss - The program simulates a very simple
speedometer, and the MzTake script
monitors it.
monitors it.
./sine/sine-mztake.ss - Plots values extracted from a program
which generates coordinates for a
@ -149,7 +136,7 @@ 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
"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.
@ -162,9 +149,9 @@ _Debugging with MzTake_
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
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.
derives from these "connections". FrTime then handles the rest.
MzTake defines the following functions and macros:
@ -174,24 +161,24 @@ _Installing Trace Points_
> (loc require-spec line-number column-number)
Creates a LOC structure containing the target file, the target line
number, and (optionally) the target column number. LOC structures
are consumed by TRACE and by DEFINE/BIND. The first argument to LOC
number, and (optionally) the target column number. LOC structures
are consumed by TRACE and by DEFINE/BIND. The first argument to LOC
is a file specification suitable for require, provided as a
datum. For instance, to install a trace point on the tenth line of
datum. For instance, to install a trace point on the tenth line of
the MzLib's list library, use:
(trace (loc '(lib "list.ss") 10) ...)
> (trace loc body ...)
Install a trace point at the location indicated by the LOC
value. The result is a FrTime event stream containing one value
each time the target reaches the location specified. To get the
value event, TRACE evaluates its body (once per event. During the
evaluation of the body, the target process is paused, and BIND is
available to inspect the state of the paused program.
Install a trace point at the location indicated by the LOC value.
The result is a FrTime event stream containing one value each time
the target reaches the location specified. To get the value event,
TRACE evaluates its body (once per event. During the evaluation of
the body, the target process is paused, and the body can inspect
the state of the paused program.
The body is optional. If no body is provided, the value #t is used
The body is optional. If no body is provided, the value #t is used
by default.
Unless SET-MAIN! is used, the first call to trace sets the file
@ -206,12 +193,14 @@ _Installing Trace Points_
When the target process is paused (or during the execution of a
trace body), BIND reaches in the lexical context at the point of
the pause (or of the trace point) and find the values for the
variables whose names are given. These values are then bound in the
body (in the MzTake script) to variable of the same name.
the pause (or of the trace point) and finds the values for the
variables whose names are given. These values are then bound in the
body (in the MzTake script) to the variables of the same name.
It is an error to call BIND while the target process is running.
You can use BIND to look up values of identifiers in the target
program that are shadowed by identifiers in the script.
> (bind* process symbol)
@ -221,16 +210,17 @@ _Installing Trace Points_
> (define/bind loc name ...)
Define the NAMEs the to behaviors reflecting the values of the
giving name in the target program, at the given
location. DEFINE/BIND is short for:
Define the NAMEs to behaviors reflecting the values of the
given names in the target program, at the given
location. DEFINE/BIND is short for:
(define name (hold (trace loc (bind (name) name))))
> (define/bind-e loc name ...)
Same as DEFINE/BIND, but returns an event stream instead of a behavior.
Same as DEFINE/BIND, but binds event streams to the names instead
of behaviors.
> (exceptions)
@ -252,21 +242,21 @@ _Installing Trace Points_
> (set-running! event)
> (set-running! event process)
Lunches the execution of the target process. Execution continues as
long as the given behavior is true (aka, any value beside #f), or
until an event comes on the given event stream with the value
#f. When execution pauses, the target remains on the line where the
paused occured. You can then inspect the state of the program with
BIND, or resume execution with another call to SET-RUNNING!.
Launches the execution of the target process. Execution continues
as long as the given behavior is true (aka, any value beside #f),
or until an event comes on the given event stream with the value
#f. When execution pauses, the target remains on the line where
the pause occured. You can then inspect the state of the program,
or resume execution with another call to SET-RUNNING!.
> (set-main! require-spec)
> (set-main! require-spec process)
Sets the file where execution begins when SET-RUNNING! is called
for the first time. When SET-MAIN! is not used explicitly,
for the first time. When SET-MAIN! is not used explicitly,
execution begins with the file specified in the first call to
trace. It is an error to call SET-RUNNING! without first calling
TRACE. It is an error to call SET-RUNNING! without first calling
either TRACE or SET-MAIN!.
@ -274,8 +264,8 @@ _Installing Trace Points_
> (where process)
Returns an event stream that contains one event for each expression
evaluated in the target process. Combined with HISTORY-B, this let
you record entire execution traces for the target program.
evaluated in the target process. Combined with HISTORY-B, this makes
it possible to record entire execution traces for the target program.
> (kill)
@ -283,9 +273,9 @@ _Installing Trace Points_
Kills the target process and releases all resources
it used -- you cannot resume after a KILL.
This will not stop of evaluation of the MzTake script, however. In
This will not stop evaluation of the MzTake script, however. In
particular, if the script depends on input the varies independently
of the target process, FrTime will continue to update them. You can
of the target process, FrTime will continue to update them. You can
use "Kill" command from DrScheme's "Scheme" menu to stop both the
MzTake script and its target process at once.
@ -303,20 +293,20 @@ _Installing Trace Points_
The CURRENT-PROCESS parameter gets or sets the process manipulated
by the MzTake function when they are not provided with a process
argument. The CURRENT-PROCESS parameter is initialized with a blank
argument. The CURRENT-PROCESS parameter is initialized with a blank
process, and you can create additional processes using the
CREATE-DEBUG-PROCESS function. Using more than one process at a
CREATE-DEBUG-PROCESS function. Using more than one process at a
time lets your MzTake run multiple programs different at once and
compare their output using a single script.
> (create-debug-process)
Creates a fresh blank debug process. Each debug process has its own
Creates a fresh blank debug process. Each debug process has its own
set of trace points, its own run trigger (set via SET-RUNNING!),
its own exceptions stream, etc. Each debug process run
its own exceptions stream, etc. Each debug process run
independently from the others, and they can be paused and killed
individually. All debug processes in a single MzTake script share
individually. All debug processes in a single MzTake script share
the same FrTime event space, and so it is possible to compare
output and traces between each of them.
@ -324,18 +314,18 @@ _Installing Trace Points_
> (current-policy policy)
Every file executed under MzTake can run either in fast mode or in
debuggable mode. The CURRENT-POLICY decides which.
debuggable mode. The CURRENT-POLICY decides which.
- debuggable mode: the file is instrumented with MzTake debugging
information. It can be the target of trace point and it generate
events on the WHERE stream. Execution can also be paused in the middle
of code running in debuggable mode. The instrumentation overhead
information. It can be the target of trace point and it generate
events on the WHERE stream. Execution can also be paused in the middle
of code running in debuggable mode. The instrumentation overhead
is considerable, however, of the order of 10x-20x slowdown.
- fast mode: the file is not instrumented, and runs at its normal
speed, but cannot be debugged. Inserting trace points into fast
speed, but cannot be debugged. Inserting trace points into fast
mode files after the beginning of the execution has no
effect. Also, pausing while executing a fast mode file will be
effect. Also, pausing while executing a fast mode file will be
delayed until execution reaches a debuggable mode file.
MzTake uses the following rules, in order, to decide between fast
@ -360,23 +350,23 @@ _Installing Trace Points_
string?
(listof (union path? string?)))))
A policy consist of a list of entries. Each entry is a pair
A policy consist of a list of entries. Each entry is a pair
specifying either fast mode or debuggable mode, then a directory,
or a list of directories. Files in these directories, or their
subdirectories will run under the given mode. The special symbol
or a list of directories. Files in these directories, or their
subdirectories will run under the given mode. The special symbol
'everything-else can be used instead of a directory, and this will
match any file. The policy is checked in order, and the first entry
match any file. The policy is checked in order, and the first entry
that applies to the given filename assign a mode the file.
The default policy run files of the directories specified by
CURRENT-LIBRARY-COLLECTIONS-PATHS in fast mode, and runs everything
else in debuggable mode. This poloicy is set as follow:
else in debuggable mode. This poloicy is set as follow:
(current-policy `((fast ,(current-library-collection-paths))
(debuggable everything-else)))
You can change this policy by calling the
CURRENT-POLICY function with a new policy as an argument. The
CURRENT-POLICY function with a new policy as an argument. The
policy is assigned to a process when the process lunches.
@ -394,7 +384,7 @@ Tips: When you have a behavior that you want to turn into
MzTake defines a few functions on time-varying values
that are particularly useful when debugging. You can require these
that are particularly useful when debugging. You can require these
functions with (require (lib "useful-code.ss" "mztake"))
> (history-e stream)
@ -432,8 +422,8 @@ functions with (require (lib "useful-code.ss" "mztake"))
> (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
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))
@ -473,7 +463,7 @@ Known Problems
* Some legal syntax locations (used in setting trace points)
are unreachable during program execution (they do not get
triggered and produce empty eventstreams). For instance,
triggered and produce empty eventstreams). For instance,
the name clause of a LET is never the current point of execution:
(define x 12)
@ -500,7 +490,7 @@ Known Problems
Authors and Thanks
MzTake is an experimental debugger. It should enable new
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/

View File

@ -115,7 +115,7 @@
[else (frp:send-synchronous-events (traces->events traces))])
;; With a where event to generate
(let ([where-event ((frp:signal-thunk (debug-process-where process)) #t)]
(let ([where-event (debug-process-where process)]
[w (map (compose syntax-local-infer-name mark-source) marks)])
(if no-traces?
(frp:send-synchronous-event where-event w)

View File

@ -31,7 +31,7 @@
[kill-all (-> void?)]
[set-running-e! ((frp:event?) (debug-process?) . opt-> . any)]
[set-running! ((frp:value-nowable?) (debug-process?) . opt-> . any)]
[where (() (debug-process?) . opt-> . frp:behavior?)]
[where (() (debug-process?) . opt-> . frp:event?)]
[current-policy (case-> (-> any)
(any/c . -> . void?))]
[current-process (case-> (-> debug-process?)
@ -76,7 +76,7 @@
(define where
(opt-lambda ([p (current-process)])
(unless (debug-process-where p)
(set-debug-process-where! p (frp:new-cell empty)))
(set-debug-process-where! p (frp:event-receiver)))
(debug-process-where p)))
(define current-process (make-parameter (create-debug-process)))