Don’t import errortrace into another module and expect it to work on that module. Instead, the errortrace module is meant to be invoked from the top-level (as described in Quick Instructions) so it can install handlers. The functions documented in this chapter then can be used at the top-level. The functions also can be accessed by importing errortrace/errortrace-lib, which does not install any handlers.
By default, errortrace only instruments for stack-trace-on-exception. Profiling and coverage need to be enabled separately.
Also, profiling only records information about the time taken on the thread that compiled the code (more precisely, the thread that instruments the code via the errortrace-compile-handler).
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.
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.
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 (or #f) 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, a list of unique call paths (i.e. stack traces) recorded if profile-paths-enabled is set to #t. Each call path is a pair of
Collecting this information is relatively expensive.
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.
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).
The errortrace module also exports: