335 lines
13 KiB
Plaintext
335 lines
13 KiB
Plaintext
|
|
[index entries: _debug_ _debugger_ _debugging_
|
|
_profile_ _profiler_ _profiling_
|
|
_coverage_ ]
|
|
|
|
_Errortrace_ is a stack-trace-on-exceptions/profiler/coverage tool for
|
|
MzScheme. Errortrace is not a complete debugger, and a real debugger
|
|
in DrScheme is expected eventually; meanwhile, using errortrace might
|
|
be better than MzScheme's limited stack-trace reporting.
|
|
|
|
Quick instructions
|
|
------------------
|
|
|
|
0) Throw away .zo versions of your source
|
|
|
|
1) Prefix your program with
|
|
(require (lib "errortrace.ss" "errortrace"))
|
|
or start MzScheme with the -M flag:
|
|
mzscheme -M errortrace
|
|
|
|
2) When an exception occurs, the exception handler prints something
|
|
like a stack trace, most recent contexts first
|
|
|
|
The errortrace module is strange; don't import it into another module.
|
|
Instead, the errortrace module is meant to be invoked from the
|
|
top-level, so that it can install an evaluation handler, exception
|
|
handler, etc.
|
|
|
|
To reuse parts of the code of errortrace, import _errortrace-lib.ss_.
|
|
It contains all of the names here but does not set the compilation
|
|
handler or the error display handler.
|
|
|
|
Exception Information
|
|
---------------------
|
|
|
|
Invoking the _errortrace.ss_ module sets the compilation handler to
|
|
instrument Scheme source code. It also sets the error display handler
|
|
to report source information for an exception, and it sets the
|
|
`use-compiled-file-paths' parameter to trigger the use of
|
|
errortrace-specific .zo files.
|
|
|
|
NOTE: errortrace has no effect on code loaded as compiled byte code
|
|
(i.e., from a .zo file) or native code (i.e., from a .dll or .so
|
|
file). But use the "--mode errortrace" flag to Setup PLT to create
|
|
.zo files with errortrace information.
|
|
|
|
Explicitly requiring "errortrace.ss" within a module is generally a
|
|
bad idea, since "errortrace.ss" sets various parameters.
|
|
|
|
Errortrace's instrumentation can be explicitly disabled via the
|
|
`instrumenting-enabled' boolean parameter. Instrumentation is on by
|
|
default. The `instrumenting-enabled' parameter affects only the way
|
|
that source code is compiled, not the way that exception information
|
|
is reported.
|
|
|
|
> (instrumenting-enabled) - returns #t if error tracing
|
|
instrumentation is enabled, #f otherwise
|
|
> (instrumenting-enabled on?) - enables/disables error tracing
|
|
instrumentation
|
|
|
|
The instrumentation for storing exception information slows most
|
|
programs by a factor of 2 or 3.
|
|
|
|
The `print-error-trace' procedure takes a port and exception and
|
|
prints the errortrace-collected debugging information contained in the
|
|
exception. It is used by the exception handler installed by
|
|
errortrace.
|
|
|
|
> (print-error-trace output-port exn) - prints the errortrace
|
|
information in `exn' to `output-port'.
|
|
|
|
The `error-context-display-depth' parameter controls how much context
|
|
errortrace's exception handler displays. The default value is 10000.
|
|
|
|
> (error-context-display-depth) - returns the current context display
|
|
depth
|
|
> (error-context-display-depth d) - sets the context display depth to
|
|
`d'
|
|
|
|
Profiling
|
|
---------
|
|
|
|
Errortrace's profiling instrumentation is off by default. Enable
|
|
profiling instrumentation with the `profiling-enabled' boolean
|
|
parameter (but setting `instrumentation-enabled' to #f also disables
|
|
profiling):
|
|
|
|
> (profiling-enabled) - returns #t if profiling instrumentation is
|
|
enabled, #f otherwise
|
|
> (profiling-enabled on?) - enables/disables profiling instrumentation
|
|
|
|
> (profiling-record-enabled) - returns #t if profiling info is
|
|
recorded for instrumented code, #f otherwise; the default is #t
|
|
> (profiling-record-enabled on?) - enables/disables the recording of
|
|
profiling info (independent of whether newly evaluated code is
|
|
instrumented)
|
|
|
|
Profiling records:
|
|
|
|
* the number of times a procedure was called.
|
|
|
|
* the number of milliseconds consumed by the procedure's body across
|
|
all calls (including the time consumed by any nested non-tail call
|
|
within the procedure, but not including time consumed by a
|
|
tail-call from the procedure).
|
|
|
|
* an inferred name for the procedure.
|
|
|
|
* the procedure's source in the form of a syntax object (which might,
|
|
in turn, provide a source location file and position).
|
|
|
|
* optionally, information about the procedure call path (i.e., a
|
|
stack trace) for every call to the procedure; collecting this
|
|
information is relatively expensive. Path information is collected
|
|
when the `profile-paths-enabled' boolean parameter is #t; the
|
|
default is #f, but setting the parameter to #t immediately affects
|
|
all procedure instrumented for profiling information:
|
|
|
|
> (profile-paths-enabled) - returns #t if profiling collects path
|
|
information, #f otherwise
|
|
> (profile-paths-enabled on?) - enables/disables collecting path
|
|
information for profiling
|
|
|
|
Profiling information is accumulated in a hash table. If a procedure
|
|
is redefined, new profiling information is accumulated for the new
|
|
version of the procedure, but the old information is also preserved.
|
|
|
|
To retrieve all profiling information accumulated so far, call
|
|
`get-profile-results':
|
|
|
|
> (get-profile-results) - returns a list of lists that contain:
|
|
|
|
* the number of times the procedure was called;
|
|
|
|
* the number of milliseconds of process time consumed by the
|
|
procedure;
|
|
|
|
* the inferred name or #f of the procedure;
|
|
|
|
* the syntax source of the procedure; and
|
|
|
|
* a list of unique call paths recorded while `profile-paths-enabled'
|
|
is set to #t. Each call path is a pair of a count (the number of
|
|
times the path occurred) and a list containing two-element lists;
|
|
each two-element list contains the calling procedure's name or
|
|
source expression and the calling procedure's source file or #f.
|
|
|
|
Depending of the source program, profiling usually induces a factor of
|
|
2 to 4 slowdown (in addition to any slowdown from the exception
|
|
information instrumentation).
|
|
|
|
> (output-profile-results paths? sort-time?)
|
|
|
|
Gets the current profile results and displays them. It optionally
|
|
shows paths information (if it is recorded) and sorts by either time
|
|
or call counts.
|
|
|
|
> (clear-profile-results)
|
|
|
|
Clears accumulated profile results.
|
|
|
|
Coverage
|
|
--------
|
|
|
|
Errortrace can produce coverage information in two flavors: both count
|
|
the number of times each expression in the source was used during
|
|
execution. The first flavor uses a simple approach, where each
|
|
expression is counted when executed; the second one uses the same
|
|
annotations that the profiler uses, so only function bodies are
|
|
counted. To see the difference between the two approaches, try this
|
|
program:
|
|
|
|
(define (foo x) (if x 1 2))
|
|
(equal? (foo #t) 1)
|
|
|
|
The first approach will produce exact results, but it is more
|
|
expensive; use it when you want to know how covered your code is (when
|
|
the expected counts are small). The second approach produces coarser
|
|
results (which, in the above case, will miss the `2' expression), but
|
|
is less expensive; use it when you want to use the counts for
|
|
profiling (when the expected counts are large).
|
|
|
|
> (coverage-counts-enabled [on?])
|
|
> (execute-counts-enabled [on?])
|
|
parameters that determine if the first (exact coverage) or second
|
|
(profiler-based coverage) are enabled. (Remember that setting
|
|
`instrumentation-enabled' to #f also disables both)
|
|
|
|
> (get-coverage-counts)
|
|
> (get-execute-counts)
|
|
returns a list of pairs, one for each instrumented expression. The
|
|
first element of the pair is a syntax object (usually containing
|
|
source location information) for the original expression, and the
|
|
second element of the pair is the number of times that the
|
|
expression has been evaluated. These elements are destructively
|
|
modified, so to take a snapshot you will need to copy them.
|
|
|
|
> (annotate-covered-file filename-path [display-string])
|
|
> (annotate-executed-file filename-path [display-string])
|
|
writes the named file to the current output port, inserting an
|
|
additional line between each source line to reflect execution counts
|
|
(as reported by `get-coverage-counts' or `get-execute-counts'). The
|
|
optional display string is used for the annotation: the first
|
|
character is used for expressions that were visited 0 times, the
|
|
second character for 1 time, ..., and the last character for
|
|
expressions that were visited more times. It can also be #t for a
|
|
maximal display ("012...9ABC...Z"), #f for a minimal display
|
|
("#-"). The default for `annotate-covered-file' is #f, and the
|
|
default for `annotate-executed-file' is "^.,".
|
|
|
|
_Re-using errortrace handlers_
|
|
-----------------------------------
|
|
|
|
The _errortrace-lib.ss_ module exports all of the exports of
|
|
"errortrace.ss", plus a few more. It does not install any handlers.
|
|
|
|
The addition exports are as follows:
|
|
|
|
> (errortrace-compile-handler stx immediate-eval?) - compiles `stx'
|
|
using the compilation handler that was active when the
|
|
"errortrace-lib.ss" module was executed, but first instruments the
|
|
code for errortrace information. The code is instrumented only if
|
|
the namespace is the same as when the module was executed. This
|
|
procedure is suitable for use as a compilation handler.
|
|
|
|
> (errortrace-error-display-handler string exn) - displays information
|
|
about the exception; this procedure is suitable for use as an error
|
|
display handler.
|
|
|
|
> (errortrace-annotate stx) - macro-expands and instruments the given
|
|
top-level form. If the form is a module named `errortrace-key', no
|
|
instrumentation is applied. This annotation function is used by
|
|
`errortrace-compile-handler'.
|
|
|
|
> (annotate-top stx) - like `errortrace-annotate', but without the
|
|
special case for `errortrace-key'. Also, if `stx' is a module
|
|
declaration, it is not enriched with imports to explicitly load
|
|
errortrace run-time support.
|
|
|
|
|
|
_Re-using errortrace stack tracing_
|
|
-----------------------------------
|
|
|
|
The errortrace collection also includes a _stacktrace.ss_ library. It
|
|
exports the _stacktrace@_ unit, its import signature
|
|
_stacktrace-imports^_, and its export signature _stacktrace^_.
|
|
|
|
The export signature contains these names:
|
|
|
|
> annotate : syntax boolean -> syntax
|
|
> annotate-top : syntax boolean -> syntax
|
|
> make-st-mark : syntax -> syntax
|
|
> st-mark-source : st-mark -> any
|
|
> st-mark-bindings : st-mark -> (listof (list syntax any))
|
|
|
|
The first two functions annotate expressions with errortrace
|
|
information. The `annotate-top' function should be called with a
|
|
top-level expression, and `annotate' should be called with a nested
|
|
expression (e.g., by `profile-point'). The boolean argument indicates
|
|
whether the expression is a transformer expression (#t) or a normal
|
|
expression (#f).
|
|
|
|
The `st-mark-source' and `st-mark-bindings' functions extract
|
|
information from a particular kind of value. The value must be
|
|
created by `make-st-mark'. `st-mark-source' extracts the value
|
|
originally provided to the expression-maker, and `st-mark-bindings'
|
|
returns local binding information (if available).
|
|
|
|
The import signature contains these names:
|
|
|
|
> with-mark : syntax syntax -> syntax
|
|
|
|
This procedure is called by `annotate' and `annotate-top' to wrap
|
|
expressions with `with-continuation-mark'. The first argument is
|
|
the source expression and the second argument is the expression to
|
|
be wrapped.
|
|
|
|
> test-coverage-enabled : (parameter boolean)
|
|
|
|
This parameter determines if the test coverage annotation is
|
|
inserted into the code. This parameter controls how compilation
|
|
happens -- it does not affect the dynamic behavior of the already
|
|
compiled code. If the parameter is set, calls to test-covered are
|
|
inserted into the code (and initialize-test-coverage-point is called
|
|
during compilation). If not, no calls to test-covered are inserted.
|
|
|
|
> test-covered : symbol -> void
|
|
|
|
During execution of the program, this is called for each point with
|
|
the key for that program point that was passed to
|
|
initialize-test-coverage-point.
|
|
|
|
> initialize-test-coverage-point : symbol syntax -> void
|
|
|
|
During compilation of the program, this function is called with each
|
|
sub-expression of the program. The first argument is a special key
|
|
used to identify this program point. The second argument is the
|
|
syntax of this program point.
|
|
|
|
> profile-key : symbol
|
|
|
|
only used for profiling paths.
|
|
|
|
> profiling-enabled : -> boolean
|
|
|
|
determines if profiling information is currently collected (affects
|
|
the behavior of compiling the code -- does not affect running code).
|
|
If this always returns #f, the other profiling functions are never
|
|
called.
|
|
|
|
> initialize-profile-point : symbol (union #f syntax[symbol]) syntax -> void
|
|
|
|
called as the program is compiled for each profiling point that
|
|
might be encountered during the program's execution. The first
|
|
argument is a key identifying this code. The second argument is the
|
|
inferred name at this point and the final argument is the syntax of
|
|
this expression.
|
|
|
|
> register-profile-start : symbol -> (union #f number)
|
|
|
|
Called when some profiled code is about to be executed. If the
|
|
result is a number, it is expected to be the current number of
|
|
milliseconds. The symbol is a key that is unique to this fragment
|
|
of code -- it is the same symbol passed to initialize-profile-point
|
|
for this code fragment.
|
|
|
|
> register-profile-done : symbol (union #f number) -> void
|
|
|
|
This function is called when some profiled code is finished
|
|
executing.
|
|
|
|
Note that register-profile-start and register-profile-done can be
|
|
called in a nested manner; in this case, the result of
|
|
register-profile-point should be #f.
|