@c -*-texinfo-*- @c This is part of the GNU Guile Reference Manual. @c Copyright (C) 2013, 2015 Free Software Foundation, Inc. @c See the file guile.texi for copying conditions. @node Statprof @section Statprof @code{(statprof)} is a fairly simple statistical profiler for Guile. A simple use of statprof would look like this: @example (statprof-reset 0 50000 #t) (statprof-start) (do-something) (statprof-stop) (statprof-display) @end example This would reset statprof, clearing all accumulated statistics, then start profiling, run some code, stop profiling, and finally display a gprof flat-style table of statistics which will look something like this: @example % cumulative self self total time seconds seconds calls ms/call ms/call name 35.29 0.23 0.23 2002 0.11 0.11 - 23.53 0.15 0.15 2001 0.08 0.08 positive? 23.53 0.15 0.15 2000 0.08 0.08 + 11.76 0.23 0.08 2000 0.04 0.11 do-nothing 5.88 0.64 0.04 2001 0.02 0.32 loop 0.00 0.15 0.00 1 0.00 150.59 do-something ... @end example All of the numerical data with the exception of the calls column is statistically approximate. In the following column descriptions, and in all of statprof, "time" refers to execution time (both user and system), not wall clock time. @table @asis @item % time The percent of the time spent inside the procedure itself (not counting children). @item cumulative seconds The total number of seconds spent in the procedure, including children. @item self seconds The total number of seconds spent in the procedure itself (not counting children). @item calls The total number of times the procedure was called. @item self ms/call The average time taken by the procedure itself on each call, in ms. @item total ms/call The average time taken by each call to the procedure, including time spent in child functions. @item name The name of the procedure. @end table The profiler uses @code{eq?} and the procedure object itself to identify the procedures, so it won't confuse different procedures with the same name. They will show up as two different rows in the output. Right now the profiler is quite simplistic. I cannot provide call-graphs or other higher level information. What you see in the table is pretty much all there is. Patches are welcome :-) @section Implementation notes The profiler works by setting the unix profiling signal @code{ITIMER_PROF} to go off after the interval you define in the call to @code{statprof-reset}. When the signal fires, a sampling routine is run which looks at the current procedure that's executing, and then crawls up the stack, and for each procedure encountered, increments that procedure's sample count. Note that if a procedure is encountered multiple times on a given stack, it is only counted once. After the sampling is complete, the profiler resets profiling timer to fire again after the appropriate interval. Meanwhile, the profiler keeps track, via @code{get-internal-run-time}, how much CPU time (system and user -- which is also what @code{ITIMER_PROF} tracks), has elapsed while code has been executing within a statprof-start/stop block. The profiler also tries to avoid counting or timing its own code as much as possible. @section Usage @anchor{statprof statprof-active?}@defun statprof-active? Returns @code{#t} if @code{statprof-start} has been called more times than @code{statprof-stop}, @code{#f} otherwise. @end defun @anchor{statprof statprof-start}@defun statprof-start Start the profiler.@code{} @end defun @anchor{statprof statprof-stop}@defun statprof-stop Stop the profiler.@code{} @end defun @anchor{statprof statprof-reset}@defun statprof-reset sample-seconds sample-microseconds count-calls? [full-stacks?] Reset the statprof sampler interval to @var{sample-seconds} and @var{sample-microseconds}. If @var{count-calls?} is true, arrange to instrument procedure calls as well as collecting statistical profiling data. If @var{full-stacks?} is true, collect all sampled stacks into a list for later analysis. Enables traps and debugging as necessary. @end defun @anchor{statprof statprof-accumulated-time}@defun statprof-accumulated-time Returns the time accumulated during the last statprof run.@code{} @end defun @anchor{statprof statprof-sample-count}@defun statprof-sample-count Returns the number of samples taken during the last statprof run.@code{} @end defun @anchor{statprof statprof-fold-call-data}@defun statprof-fold-call-data proc init Fold @var{proc} over the call-data accumulated by statprof. Cannot be called while statprof is active. @var{proc} should take two arguments, @code{(@var{call-data} @var{prior-result})}. Note that a given proc-name may appear multiple times, but if it does, it represents different functions with the same name. @end defun @anchor{statprof statprof-proc-call-data}@defun statprof-proc-call-data proc Returns the call-data associated with @var{proc}, or @code{#f} if none is available. @end defun @anchor{statprof statprof-call-data-name}@defun statprof-call-data-name cd @end defun @anchor{statprof statprof-call-data-calls}@defun statprof-call-data-calls cd @end defun @anchor{statprof statprof-call-data-cum-samples}@defun statprof-call-data-cum-samples cd @end defun @anchor{statprof statprof-call-data-self-samples}@defun statprof-call-data-self-samples cd @end defun @anchor{statprof statprof-call-data->stats}@defun statprof-call-data->stats call-data Returns an object of type @code{statprof-stats}. @end defun @anchor{statprof statprof-stats-proc-name}@defun statprof-stats-proc-name stats @end defun @anchor{statprof statprof-stats-%-time-in-proc}@defun statprof-stats-%-time-in-proc stats @end defun @anchor{statprof statprof-stats-cum-secs-in-proc}@defun statprof-stats-cum-secs-in-proc stats @end defun @anchor{statprof statprof-stats-self-secs-in-proc}@defun statprof-stats-self-secs-in-proc stats @end defun @anchor{statprof statprof-stats-calls}@defun statprof-stats-calls stats @end defun @anchor{statprof statprof-stats-self-secs-per-call}@defun statprof-stats-self-secs-per-call stats @end defun @anchor{statprof statprof-stats-cum-secs-per-call}@defun statprof-stats-cum-secs-per-call stats @end defun @anchor{statprof statprof-display}@defun statprof-display . _ Displays a gprof-like summary of the statistics collected. Unless an optional @var{port} argument is passed, uses the current output port. @end defun @anchor{statprof statprof-display-anomolies}@defun statprof-display-anomolies A sanity check that attempts to detect anomolies in statprof's statistics.@code{} @end defun @anchor{statprof statprof-fetch-stacks}@defun statprof-fetch-stacks Returns a list of stacks, as they were captured since the last call to @code{statprof-reset}. Note that stacks are only collected if the @var{full-stacks?} argument to @code{statprof-reset} is true. @end defun @anchor{statprof statprof-fetch-call-tree}@defun statprof-fetch-call-tree @verbatim Return a call tree for the previous statprof run. The return value is a list of nodes, each of which is of the type: @@code node ::= (@@var@{proc@} @@var@{count@} . @@var@{nodes@}) @@end code @end verbatim @end defun @anchor{statprof statprof}@defun statprof thunk [#:loop] [#:hz] [#:count-calls?] [#:full-stacks?] Profile the execution of @var{thunk}, and return its return values. The stack will be sampled @var{hz} times per second, and the thunk itself will be called @var{loop} times. If @var{count-calls?} is true, all procedure calls will be recorded. This operation is somewhat expensive. If @var{full-stacks?} is true, at each sample, statprof will store away the whole call tree, for later analysis. Use @code{statprof-fetch-stacks} or @code{statprof-fetch-call-tree} to retrieve the last-stored stacks. @end defun @anchor{statprof with-statprof}@defspec with-statprof args Profile the expressions in the body, and return the body's return value. Keyword arguments: @table @code @item #:loop Execute the body @var{loop} number of times, or @code{#f} for no looping default: @code{#f} @item #:hz Sampling rate default: @code{20} @item #:count-calls? Whether to instrument each function call (expensive) default: @code{#f} @item #:full-stacks? Whether to collect away all sampled stacks into a list default: @code{#f} @end table @end defspec @anchor{statprof gcprof}@defun gcprof thunk [#:loop] [#:full-stacks?] Do an allocation profile of the execution of @var{thunk}. The stack will be sampled soon after every garbage collection, yielding an approximate idea of what is causing allocation in your program. Since GC does not occur very frequently, you may need to use the @var{loop} parameter, to cause @var{thunk} to be called @var{loop} times. If @var{full-stacks?} is true, at each sample, statprof will store away the whole call tree, for later analysis. Use @code{statprof-fetch-stacks} or @code{statprof-fetch-call-tree} to retrieve the last-stored stacks. @end defun