Previously, 'make-stack' calls with the inner and outer cuts arguments
would always return #f because 'call-thunk' wouldn't appear on the
stack.
* module/statprof.scm <top level>: Add self-assignment to 'call-thunk'.
* libguile/vm.h (SCM_VM_ABORT_HOOK): Rename from
SCM_VM_ABORT_CONTINUATION_HOOK.
* libguile/vm-engine.c (ABORT_HOOK):
* libguile/vm.c (invoke_abort_hook): Adapt to SCM_VM_ABORT_HOOK name
change.
(reset_vm_hook_enabled): New helper.
(VM_ADD_HOOK, VM_REMOVE_HOOK): New helper macros, replacing
VM_DEFINE_HOOK.
(scm_vm_add_abort_hook_x, scm_vm_remove_abort_hook_x)
(scm_vm_add_apply_hook_x, scm_vm_remove_apply_hook_x)
(scm_vm_add_return_hook_x, scm_vm_remove_return_hook_x)
(scm_vm_add_next_hook_x, scm_vm_remove_next_hook_x): New functions,
replacing direct access to the hooks. Allows us to know in a more
fine-grained way when to enable hooks.
(scm_set_vm_trace_level_x): Use reset_vm_hook_enabled to update the
individual hook_enabled flags.
* module/statprof.scm:
* module/system/vm/coverage.scm:
* module/system/vm/traps.scm:
* module/system/vm/vm.scm: Adapt VM hook users to the new API.
* module/system/vm/frame.scm: Add a comment about a case that we need to
handle in the future.
* module/statprof.scm (statprof-proc-call-data): Always use the program
code as the key, even for primitives.
* libguile/gsubr.c: Reimplement to store subr names and procedures in a
side table, and to allocate fresh vcode for each subr. This allows
JIT of subrs, moves to a uniform all-code-starts-with-instrument-entry
regime, and also allows statprof to distinguish between subrs based on
IP.
* libguile/gsubr.h (SCM_SUBRF, SCM_SUBR_NAME): Call out to functions,
now that these are in a side table.
(scm_subr_function, scm_subr_name): New exports.
(scm_i_primitive_name): New internal function, for looking up a
primitive name based on IP.
(scm_apply_subr): Take the subr index.
* libguile/vm-engine.c (subr-call):
* libguile/jit.c (compile_subr_call): Adapt to take index as arg.
* module/statprof.scm (sample-stack-procs, count-call):
(stack-samples->procedure-data): Update to always record IP in stack
samples and call counts.
* module/system/vm/frame.scm (frame-procedure-name): Simplify.
(frame-instruction-pointer-or-primitive-procedure-name): Removed.
* libguile/programs.h:
* libguile/programs.c (scm_primitive_code_name): New function.
* module/system/vm/program.scm (primitive-code-name): New export.
* module/statprof.scm: Remove most of the commentary, as it was
duplicated in the manual and was getting out of date.
(stats): Remove self-secs-per-call and cum-secs-per-call fields as
they can be computed from the other fields.
(statprof-call-data->stats): Adapt.
(statprof-stats-self-secs-per-call):
(statprof-stats-cum-secs-per-call): New functions.
(statprof-display/flat): Don't print the seconds-per-call fields, as
we are no longer stopping the clock around call counters. Anyway
these times were quite misleading.
(with-statprof): Deprecate. It took its keyword arguments at the
beginning; very complicated! Better to use the `statprof' function.
(`statprof' was introduced after `with-statprof' and then
`with-statprof' was adapted to use it.)
* doc/ref/statprof.texi (Statprof): Port this documentation away from
the automatically generated text and update it for the new interfaces
like #:display-style.
* module/system/base/syntax.scm (record-case): Remove comment that
referenced with-statprof. Add comment indicating that record-case
should be replaced.
* doc/ref/scheme-using.texi (Profile Commands): Update to mention
keyword arguments and to link to the statprof documentation.
* module/statprof.scm: Update commentary.
(count-call): Don't bother stopping and starting the timer. The
overhead of call counting perturbs timing too much already, and
somewhat paradoxically stopping and starting the timer takes too much
time.
(skip-count-call): New function.
(stack-samples->procedure-data, stack-samples->callee-lists): If we
are counting calls, skip any part of the stack that is inside
count-call.
* libguile/frames.h (scm_frame_num_locals, scm_frame_local_ref)
(scm_frame_local_set_x): Remove. As long as we are changing the
interface in a backward-incompatible way, we might as well remove
these.
* libguile/frames.c (scm_frame_num_locals, scm_frame_local_ref)
(scm_frame_local_set_x, scm_init_frames_builtins, scm_init_frames):
Arrange to make frame-local-ref et al private to frames.scm.
* module/system/vm/frame.scm: Load scm_init_frames_builtins extensions.
(frame-instruction-pointer-or-primitive-procedure-name): New public
function.
(frame-binding-ref, frame-binding-set!): Allow binding objects as
vars.
* module/system/repl/debug.scm (print-locals): Pass binding directly to
frame-binding-ref.
* module/statprof.scm (sample-stack-procs, count-call): Use new
frame-instruction-pointer-or-primitive-procedure-name function.
* module/statprof.scm (statprof-fetch-call-tree): Add #:precise? keyword
argument, defaulting to false. Search for cycles after computing
printable source locations instead of doing so over addresses -- it
could be that two addresses map to the same source location, and from
the user's perspective they are then indistinguishable in the
printout.
* module/statprof.scm (statprof-display/flat): Rename from
statprof-display. Use real format; we have it.
(statprof-display-anomalies): Likewise use real format.
(procedure=?): Remove unused function.
(collect-cycles): New helper.
(statprof-fetch-call-tree): Fix to root the trees correctly -- it was
interpreting them in the wrong order. Detect cycles so that it's not
so terrible. Use precise locations for source locations. Probably
need to add an option to go back to the per-function behavior.
(statprof-display/tree): New helper, uses statprof-fetch-call-tree to
display a profile in a nested tree.
(statprof-display): Add #:style argument, which can be `flat',
`anomalies', or `tree'.
(statprof): Add #:display-style argument, proxying to #:style,
defaulting to 'flat.
We need to be able to identify frames that are primitive applications
without assuming that slot 0 in a frame is an SCM value and without
assuming that value is the procedure being applied.
* libguile/gsubr.c (scm_i_primitive_code_p): New helper.
(scm_i_primitive_arity): Use the new helper.
* libguile/gsubr.h: Declare the new helper.
* libguile/programs.h:
* libguile/programs.c (scm_program_code_p): New function, replacing
scm_primitive_p.
(scm_primitive_call_ip): Fix FUNC_NAME definition.
* module/statprof.scm (sample-stack-procs, count-call): Identify
primitive frames from the IP, not the frame-procedure. Avoids the
assumption that slot 0 in a frame is a SCM value.
(statprof-proc-call-data): Adapt to primitive-code? change.
* module/system/vm/frame.scm (frame-call-representation): Identify
primitive frames from the IP, not the closure. Still more work to do
here to avoid assuming slot 0 is a procedure.
* module/system/vm/program.scm: Export primitive-code? instead of
primitive?.
(program-arguments-alist, program-arguments-alists): Identify
primitives from the code instead of the flags on the program. Not
sure this is a great change, but it does avoid having to define a
primitive? predicate in Scheme.
* doc/ref/api-debug.texi (Stack Capture): Update make-stack docs.
* libguile/programs.h:
* libguile/programs.c (scm_program_address_range): New internal
procedure.
* libguile/stacks.c (narrow_stack): Interpret a pair of integers as an
address range. If a cut is a procedure, attempt to resolve it to an
address range.
(scm_make_stack): Update docstring.
* module/system/vm/program.scm (program-address-range): New exported
procedure.
* module/statprof.scm (statprof, gcprof): Use program-address-range to
get the outer-cut, for efficiency.
* module/statprof.scm (profile-signal-handler): Bind in a letrec.
Otherwise the compiler may see the closure slot as dead, and the inner
stack cut won't work.
* module/statprof.scm (statprof-start, statprof-stop): Don't futz the vm
trace level when we aren't counting calls. With this change, statprof
now imposes no overhead on the measured program.
* module/statprof.scm (statprof-fold-call-data)
(statprof-proc-call-data): Add optional state arg.
(gcprof): Add optional port arg, and pass state arg explicitly.
(statprof-display-anomalies, statprof-display)
(statprof-call-data->stats): Pass state explicitly.
* module/statprof.scm (<state>): Add outer-cut member.
(fresh-profiler-state): Add outer-cut kwarg.
(sample-stack-procs): Stop when the stack-length is zero, which will
be before the frames run out if there is an outer cut.
(profile-signal-handler): Use the outer cut when capturing the stack.
(call-thunk): New helper, for use as an outer cut.
(statprof, gcprof): Call the thunk within call-thunk, and use
call-thunk as an outer cut.
* module/statprof.scm: Add a big ol' comment.
(sample-stack-procs): If slot 0 isn't a primitive, use the IP to
mark. In the future we will see more non-procedures in slot 0 as we
start to use call-label and tail-call-label.
* module/statprof.scm (call-data): Source is after printable.
(addr->printable): Just produce a name, without source. Anonymous
printables get "anon " prefixed.
(stack-samples->procedure-data): Adapt to call-data change.
(stats): Add "proc-source" element.
(statprof-call-data->stats): Give a source to the call-data.
(statprof-display): Print source also.
* module/statprof.scm (call-data): Add source member.
(stack-samples->procedure-data): Populate source member
(stats): Convert to record from vector.
(statprof-call-data->stats): Adapt to produce a record.
* module/statprof.scm (<state>): Remove record-full-stacks? and stacks
members. The stack trace buffer is sufficient.
(fresh-profiler-state): Adapt.
(sample-stack-procs): Don't save stacks.
(statprof-reset): Deprecate the full-stacks? argument.
(stack-samples->procedure-data): Remove a needless vector-ref.
(stack-samples->callee-lists): New helper.
(statprof-fetch-stacks): Use stack-samples->callee-lists.
(statprof-fetch-call-tree): Use stack-samples->callee-lists, and
implement our own callee->string helper.
(statprof, with-statprof, gcprof): Deprecate full-stacks? argument.
* module/statprof.scm (<state>): Instead of a boolean count-calls?,
treat the presence of a call-counts hash table as indicating a need to
count calls. That hash table maps callees to call counts. A "callee"
is either the IP of the entry of a program, the symbolic name of a
primitive, or the identity of a non-program.
New members "buffer" and "buffer-pos" replace "procedure-data".
We try to avoid analyzing things at runtime, instead just recording
the stack traces into a buffer. This will let us do smarter things
when post-processing.
(fresh-buffer, expand-buffer): New helpers.
(fresh-profiler-state): Adapt to <state> changes.
(sample-stack-procs): Instead of updating the procedure-data
table (which no longer exists), instead trace the stack into the
buffer.
(count-call): Update to update the call-counts table instead of the
procedure-data table.
(statprof-start, statprof-start): Adapt to call-counts change.
(call-data): Move lower in the file. Add "name" and "printable"
members, and no longer store a proc.
(source->string, program-debug-info-printable, addr->pdi)
(addr->printable): New helpers.
(stack-samples->procedure-data): New procedure to process stack trace
buffer into a hash table of the same format as the old procedure-data
table.
(statprof-fold-call-data, statprof-proc-call-data): Use
stack-samples->procedure-data instead of procedure-data.
(statprof-call-data->stats): Adapt to count-calls change.
(statprof-display, statprof-display-anomalies): Adapt.
* module/statprof.scm (statprof-start, statprof-stop): Take optional
state arg.
(statprof-reset): Return no values.
(statprof): Take port keyword arg. Since statprof-reset is now the
same as parameterizing profiler-state, there's no need to call
statprof-reset. Pass the state argument explicitly to statprof-start,
statprof-stop, and statprof-display.
* module/statprof.scm (<state>): Add field for the previous SIGPROF
handler.
(statprof-start, statprof-stop, statprof-reset): Instead of setting
the SIGPROF handler in statprof-reset, set it when the profiler
becomes active, and actually restore it when the profiler becomes
inactive.
* module/statprof.scm (statprof-display, statprof-display-anomalies)
(statprof-accumulated-time, statprof-sample-count)
(statprof-fetch-stacks, statprof-fetch-call-tree): Take optional state
argument.
(statprof-display-anomolies): Deprecate this mis-spelling.
(statprof): Just compute usecs for the period.
* module/statprof.scm (gcprof): No need to reset in gcprof; the fresh
profiler state and the parameterize handle that. Fix mistaken
set-vm-trace-level! as well.
* module/statprof.scm (<state>): The sampling frequency is actually a
period; label it as such, and express in microseconds instead of as a
pair. Likewise for remaining-prof-time.
(fresh-profiler-state): Adapt.
(reset-sigprof-timer): New helper.
(profile-signal-handler): Use the new helper.
(statprof-start): Use the new helper.
(statprof-stop): Here too.
(statprof-reset): Adapt to <state> change.
(gcprof): Set remaining prof time to 0.
* module/statprof.scm (profile-signal-handler): Don't bother detecting
if we were in a count-call call or not; it doesn't matter, and we
should accumulate time in any case.
* module/statprof.scm (fresh-profiler-state): accumulated-time and
gc-time-taken are in jiffies, not seconds, so they are exact.
(statprof-accumulated-time): Divide by 1.0 so that we get a flonum.
Also refactor use of assq to get the gc-time-taken.
* module/statprof.scm (get-call-data, sample-stack-procs): Take the
state as an argument.
(profile-signal-handler, count-call, statprof-proc-call-data)
(gcprof): Adapt.
* module/statprof.scm (statprof-reset, statprof-fold-call-data):
(statprof-proc-call-data, statprof-accumulated-time):
(statprof-sample-count): Refactor some things to use statprof-active?
instead of checking the profile level manually.
* module/statprof.scm (fresh-profiler-state): New helper.
(ensure-profiler-state): Use it.
(accumulate-time): No need to add 0.0 here.
(statprof-reset): Create a new state instead of mutating the existing
one.
* module/statprof.scm (existing-profiler-state): New helper, gets the
profiler state or fails if there is no state.
(sample-stack-procs, profile-signal-handler, count-call)
(statprof-fold-call-data, statprof-proc-call-data)
(statprof-call-data->stats, statprof-display)
(statprof-display-anomolies, statprof-accumulated-time)
(statprof-sample-count, statprof-fetch-stacks)
(statprof-fetch-call-tree): Use the new helper.
(statprof-active?): Don't create a state if there isn't one already.
* module/statprof.scm (<state>, profiler-state, ensure-profiler-state):
A mostly-mechanical refactor to encapsulate profiler state in a
parameter and a record instead of global variables.