mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-29 08:20:20 +02:00
Statprof always stores full stack traces
* 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.
This commit is contained in:
parent
ce47749045
commit
3f9f4a2d59
1 changed files with 190 additions and 111 deletions
|
@ -112,6 +112,7 @@
|
||||||
#:autoload (ice-9 format) (format)
|
#:autoload (ice-9 format) (format)
|
||||||
#:use-module (system vm vm)
|
#:use-module (system vm vm)
|
||||||
#:use-module (system vm frame)
|
#:use-module (system vm frame)
|
||||||
|
#:use-module (system vm debug)
|
||||||
#:use-module (system vm program)
|
#:use-module (system vm program)
|
||||||
#:export (statprof-active?
|
#:export (statprof-active?
|
||||||
statprof-start
|
statprof-start
|
||||||
|
@ -161,9 +162,9 @@
|
||||||
(define-record-type <state>
|
(define-record-type <state>
|
||||||
(make-state accumulated-time last-start-time sample-count
|
(make-state accumulated-time last-start-time sample-count
|
||||||
sampling-period remaining-prof-time profile-level
|
sampling-period remaining-prof-time profile-level
|
||||||
count-calls? gc-time-taken record-full-stacks?
|
call-counts gc-time-taken record-full-stacks?
|
||||||
stacks procedure-data inside-profiler?
|
stacks inside-profiler?
|
||||||
prev-sigprof-handler)
|
prev-sigprof-handler buffer buffer-pos)
|
||||||
state?
|
state?
|
||||||
;; Total time so far.
|
;; Total time so far.
|
||||||
(accumulated-time accumulated-time set-accumulated-time!)
|
(accumulated-time accumulated-time set-accumulated-time!)
|
||||||
|
@ -177,30 +178,39 @@
|
||||||
(remaining-prof-time remaining-prof-time set-remaining-prof-time!)
|
(remaining-prof-time remaining-prof-time set-remaining-prof-time!)
|
||||||
;; For user start/stop nesting.
|
;; For user start/stop nesting.
|
||||||
(profile-level profile-level set-profile-level!)
|
(profile-level profile-level set-profile-level!)
|
||||||
;; Whether to catch apply-frame.
|
;; Hash table mapping ip -> call count, or #f if not counting calls.
|
||||||
(count-calls? count-calls? set-count-calls?!)
|
(call-counts call-counts set-call-counts!)
|
||||||
;; GC time between statprof-start and statprof-stop.
|
;; GC time between statprof-start and statprof-stop.
|
||||||
(gc-time-taken gc-time-taken set-gc-time-taken!)
|
(gc-time-taken gc-time-taken set-gc-time-taken!)
|
||||||
;; If #t, stash away the stacks for future analysis.
|
;; If #t, stash away the stacks for future analysis.
|
||||||
(record-full-stacks? record-full-stacks? set-record-full-stacks?!)
|
(record-full-stacks? record-full-stacks? set-record-full-stacks?!)
|
||||||
;; If record-full-stacks?, the stashed full stacks.
|
;; If record-full-stacks?, the stashed full stacks.
|
||||||
(stacks stacks set-stacks!)
|
(stacks stacks set-stacks!)
|
||||||
;; A hash where the key is the function object itself and the value is
|
|
||||||
;; the data. The data will be a vector like this:
|
|
||||||
;; #(name call-count cum-sample-count self-sample-count)
|
|
||||||
(procedure-data procedure-data set-procedure-data!)
|
|
||||||
;; True if we are inside the profiler.
|
;; True if we are inside the profiler.
|
||||||
(inside-profiler? inside-profiler? set-inside-profiler?!)
|
(inside-profiler? inside-profiler? set-inside-profiler?!)
|
||||||
;; True if we are inside the profiler.
|
;; True if we are inside the profiler.
|
||||||
(prev-sigprof-handler prev-sigprof-handler set-prev-sigprof-handler!))
|
(prev-sigprof-handler prev-sigprof-handler set-prev-sigprof-handler!)
|
||||||
|
;; Stack samples.
|
||||||
|
(buffer buffer set-buffer!)
|
||||||
|
(buffer-pos buffer-pos set-buffer-pos!))
|
||||||
|
|
||||||
(define profiler-state (make-parameter #f))
|
(define profiler-state (make-parameter #f))
|
||||||
|
|
||||||
|
(define (fresh-buffer)
|
||||||
|
(make-vector 1024 #f))
|
||||||
|
|
||||||
|
(define (expand-buffer buf)
|
||||||
|
(let* ((size (vector-length buf))
|
||||||
|
(new (make-vector (* size 2) #f)))
|
||||||
|
(vector-move-left! buf 0 (vector-length buf) new 0)
|
||||||
|
new))
|
||||||
|
|
||||||
(define* (fresh-profiler-state #:key (count-calls? #f)
|
(define* (fresh-profiler-state #:key (count-calls? #f)
|
||||||
(sampling-period 10000)
|
(sampling-period 10000)
|
||||||
(full-stacks? #f))
|
(full-stacks? #f))
|
||||||
(make-state 0 #f 0 sampling-period 0 0 count-calls? 0 #f '()
|
(make-state 0 #f 0 sampling-period 0 0
|
||||||
(make-hash-table) #f #f))
|
(and count-calls? (make-hash-table))
|
||||||
|
0 #f '() #f #f (fresh-buffer) 0))
|
||||||
|
|
||||||
(define (ensure-profiler-state)
|
(define (ensure-profiler-state)
|
||||||
(or (profiler-state)
|
(or (profiler-state)
|
||||||
|
@ -212,88 +222,48 @@
|
||||||
(or (profiler-state)
|
(or (profiler-state)
|
||||||
(error "expected there to be a profiler state")))
|
(error "expected there to be a profiler state")))
|
||||||
|
|
||||||
(define-record-type call-data
|
|
||||||
(make-call-data proc call-count cum-sample-count self-sample-count)
|
|
||||||
call-data?
|
|
||||||
(proc call-data-proc)
|
|
||||||
(call-count call-data-call-count set-call-data-call-count!)
|
|
||||||
(cum-sample-count call-data-cum-sample-count set-call-data-cum-sample-count!)
|
|
||||||
(self-sample-count call-data-self-sample-count set-call-data-self-sample-count!))
|
|
||||||
|
|
||||||
(define (call-data-name cd) (procedure-name (call-data-proc cd)))
|
|
||||||
(define (call-data-printable cd)
|
|
||||||
(or (call-data-name cd)
|
|
||||||
(with-output-to-string (lambda () (write (call-data-proc cd))))))
|
|
||||||
|
|
||||||
(define (inc-call-data-call-count! cd)
|
|
||||||
(set-call-data-call-count! cd (1+ (call-data-call-count cd))))
|
|
||||||
(define (inc-call-data-cum-sample-count! cd)
|
|
||||||
(set-call-data-cum-sample-count! cd (1+ (call-data-cum-sample-count cd))))
|
|
||||||
(define (inc-call-data-self-sample-count! cd)
|
|
||||||
(set-call-data-self-sample-count! cd (1+ (call-data-self-sample-count cd))))
|
|
||||||
|
|
||||||
(define (accumulate-time state stop-time)
|
(define (accumulate-time state stop-time)
|
||||||
(set-accumulated-time! state
|
(set-accumulated-time! state
|
||||||
(+ (accumulated-time state)
|
(+ (accumulated-time state)
|
||||||
(- stop-time (last-start-time state)))))
|
(- stop-time (last-start-time state)))))
|
||||||
|
|
||||||
(define (get-call-data state proc)
|
|
||||||
(let ((k (cond
|
|
||||||
((program? proc) (program-code proc))
|
|
||||||
(else proc))))
|
|
||||||
(or (hashv-ref (procedure-data state) k)
|
|
||||||
(let ((call-data (make-call-data proc 0 0 0)))
|
|
||||||
(hashv-set! (procedure-data state) k call-data)
|
|
||||||
call-data))))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; SIGPROF handler
|
;; SIGPROF handler
|
||||||
|
|
||||||
;; FIXME: Instead of this messing about with hash tables and
|
|
||||||
;; frame-procedure, just record the stack of return addresses into a
|
|
||||||
;; growable vector, and resolve them to procedures when analyzing
|
|
||||||
;; instead of at collection time.
|
|
||||||
;;
|
|
||||||
(define (sample-stack-procs state stack)
|
(define (sample-stack-procs state stack)
|
||||||
(let ((stacklen (stack-length stack))
|
(when (record-full-stacks? state)
|
||||||
(hit-count-call? #f))
|
(set-stacks! state (cons stack (stacks state))))
|
||||||
|
|
||||||
(when (record-full-stacks? state)
|
(set-sample-count! state (+ (sample-count state) 1))
|
||||||
(set-stacks! state (cons stack (stacks state))))
|
|
||||||
|
|
||||||
(set-sample-count! state (+ (sample-count state) 1))
|
(let lp ((frame (stack-ref stack 0))
|
||||||
;; Now accumulate stats for the whole stack.
|
(buffer (buffer state))
|
||||||
(let loop ((frame (stack-ref stack 0))
|
(pos (buffer-pos state)))
|
||||||
(procs-seen (make-hash-table 13))
|
(define (write-sample sample)
|
||||||
(self #f))
|
(vector-set! buffer pos sample))
|
||||||
(cond
|
(define (continue pos)
|
||||||
((not frame)
|
(lp (frame-previous frame) buffer pos))
|
||||||
(hash-fold
|
(define (write-sample-and-continue sample)
|
||||||
(lambda (proc val accum)
|
(write-sample sample)
|
||||||
(inc-call-data-cum-sample-count!
|
(continue (1+ pos)))
|
||||||
(get-call-data state proc)))
|
(cond
|
||||||
#f
|
((= pos (vector-length buffer))
|
||||||
procs-seen)
|
(lp frame (expand-buffer buffer) pos))
|
||||||
(and=> (and=> self (lambda (proc)
|
((not frame)
|
||||||
(get-call-data state proc)))
|
(write-sample #f)
|
||||||
inc-call-data-self-sample-count!))
|
(set-buffer! state buffer)
|
||||||
((frame-procedure frame)
|
(set-buffer-pos! state (1+ pos)))
|
||||||
=> (lambda (proc)
|
(else
|
||||||
(cond
|
(let ((proc (frame-procedure frame)))
|
||||||
((eq? proc count-call)
|
(cond
|
||||||
;; We're not supposed to be sampling count-call and
|
((primitive? proc)
|
||||||
;; its sub-functions, so loop again with a clean
|
(write-sample-and-continue (procedure-name proc)))
|
||||||
;; slate.
|
((program? proc)
|
||||||
(set! hit-count-call? #t)
|
(write-sample-and-continue (frame-instruction-pointer frame)))
|
||||||
(loop (frame-previous frame) (make-hash-table 13) #f))
|
(proc (write-sample-and-continue proc))
|
||||||
(else
|
;; If proc is false, that would confuse our stack walker.
|
||||||
(hashq-set! procs-seen proc #t)
|
;; Ignore it.
|
||||||
(loop (frame-previous frame)
|
(else (continue pos))))))))
|
||||||
procs-seen
|
|
||||||
(or self proc))))))
|
|
||||||
(else
|
|
||||||
(loop (frame-previous frame) procs-seen self))))
|
|
||||||
hit-count-call?))
|
|
||||||
|
|
||||||
(define (reset-sigprof-timer usecs)
|
(define (reset-sigprof-timer usecs)
|
||||||
;; Guile's setitimer binding is terrible.
|
;; Guile's setitimer binding is terrible.
|
||||||
|
@ -330,17 +300,19 @@
|
||||||
;; Count total calls.
|
;; Count total calls.
|
||||||
|
|
||||||
(define (count-call frame)
|
(define (count-call frame)
|
||||||
(define state (existing-profiler-state))
|
(let ((state (existing-profiler-state)))
|
||||||
|
(unless (inside-profiler? state)
|
||||||
|
(accumulate-time state (get-internal-run-time))
|
||||||
|
|
||||||
(unless (inside-profiler? state)
|
(let* ((key (let ((proc (frame-procedure frame)))
|
||||||
(accumulate-time state (get-internal-run-time))
|
(cond
|
||||||
|
((primitive? proc) (procedure-name proc))
|
||||||
|
((program? proc) (program-code proc))
|
||||||
|
(else proc))))
|
||||||
|
(handle (hashv-create-handle! (call-counts state) key 0)))
|
||||||
|
(set-cdr! handle (1+ (cdr handle))))
|
||||||
|
|
||||||
(and=> (frame-procedure frame)
|
(set-last-start-time! state (get-internal-run-time)))))
|
||||||
(lambda (proc)
|
|
||||||
(inc-call-data-call-count!
|
|
||||||
(get-call-data state proc))))
|
|
||||||
|
|
||||||
(set-last-start-time! state (get-internal-run-time))))
|
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
|
@ -365,7 +337,7 @@ than @code{statprof-stop}, @code{#f} otherwise."
|
||||||
(let ((prev (sigaction SIGPROF profile-signal-handler)))
|
(let ((prev (sigaction SIGPROF profile-signal-handler)))
|
||||||
(set-prev-sigprof-handler! state (car prev)))
|
(set-prev-sigprof-handler! state (car prev)))
|
||||||
(reset-sigprof-timer (if (zero? rpt) (sampling-period state) rpt))
|
(reset-sigprof-timer (if (zero? rpt) (sampling-period state) rpt))
|
||||||
(when (count-calls? state)
|
(when (call-counts state)
|
||||||
(add-hook! (vm-apply-hook) count-call))
|
(add-hook! (vm-apply-hook) count-call))
|
||||||
(set-vm-trace-level! (1+ (vm-trace-level)))
|
(set-vm-trace-level! (1+ (vm-trace-level)))
|
||||||
#t)))
|
#t)))
|
||||||
|
@ -381,7 +353,7 @@ than @code{statprof-stop}, @code{#f} otherwise."
|
||||||
(- (assq-ref (gc-stats) 'gc-time-taken)
|
(- (assq-ref (gc-stats) 'gc-time-taken)
|
||||||
(gc-time-taken state)))
|
(gc-time-taken state)))
|
||||||
(set-vm-trace-level! (1- (vm-trace-level)))
|
(set-vm-trace-level! (1- (vm-trace-level)))
|
||||||
(when (count-calls? state)
|
(when (call-counts state)
|
||||||
(remove-hook! (vm-apply-hook) count-call))
|
(remove-hook! (vm-apply-hook) count-call))
|
||||||
;; I believe that we need to do this before getting the time
|
;; I believe that we need to do this before getting the time
|
||||||
;; (unless we want to make things even more complicated).
|
;; (unless we want to make things even more complicated).
|
||||||
|
@ -409,6 +381,108 @@ Enables traps and debugging as necessary."
|
||||||
#:full-stacks? full-stacks?))
|
#:full-stacks? full-stacks?))
|
||||||
(values))
|
(values))
|
||||||
|
|
||||||
|
(define-record-type call-data
|
||||||
|
(make-call-data name printable call-count cum-sample-count self-sample-count)
|
||||||
|
call-data?
|
||||||
|
(name call-data-name)
|
||||||
|
(printable call-data-printable)
|
||||||
|
(call-count call-data-call-count set-call-data-call-count!)
|
||||||
|
(cum-sample-count call-data-cum-sample-count set-call-data-cum-sample-count!)
|
||||||
|
(self-sample-count call-data-self-sample-count set-call-data-self-sample-count!))
|
||||||
|
|
||||||
|
(define (source->string source)
|
||||||
|
(format #f "~a:~a:~a"
|
||||||
|
(or (source-file source) "<current input>")
|
||||||
|
(source-line-for-user source)
|
||||||
|
(source-column source)))
|
||||||
|
|
||||||
|
(define (program-debug-info-printable pdi)
|
||||||
|
(let* ((addr (program-debug-info-addr pdi))
|
||||||
|
(name (or (and=> (program-debug-info-name pdi) symbol->string)
|
||||||
|
(string-append "#x" (number->string addr 16))))
|
||||||
|
(loc (and=> (find-source-for-addr addr) source->string)))
|
||||||
|
(if loc
|
||||||
|
(string-append name " at " loc)
|
||||||
|
name)))
|
||||||
|
|
||||||
|
(define (addr->pdi addr cache)
|
||||||
|
(cond
|
||||||
|
((hashv-get-handle cache addr) => cdr)
|
||||||
|
(else
|
||||||
|
(let ((data (find-program-debug-info addr)))
|
||||||
|
(hashv-set! cache addr data)
|
||||||
|
data))))
|
||||||
|
|
||||||
|
(define (addr->printable addr pdi)
|
||||||
|
(if pdi
|
||||||
|
(program-debug-info-printable pdi)
|
||||||
|
(string-append "#x" (number->string addr 16))))
|
||||||
|
|
||||||
|
(define (inc-call-data-cum-sample-count! cd)
|
||||||
|
(set-call-data-cum-sample-count! cd (1+ (call-data-cum-sample-count cd))))
|
||||||
|
(define (inc-call-data-self-sample-count! cd)
|
||||||
|
(set-call-data-self-sample-count! cd (1+ (call-data-self-sample-count cd))))
|
||||||
|
|
||||||
|
(define (stack-samples->procedure-data state)
|
||||||
|
(let ((table (make-hash-table))
|
||||||
|
(addr-cache (make-hash-table))
|
||||||
|
(call-counts (call-counts state))
|
||||||
|
(buffer (buffer state))
|
||||||
|
(len (buffer-pos state)))
|
||||||
|
(define (addr->call-data addr)
|
||||||
|
(let* ((pdi (addr->pdi addr addr-cache))
|
||||||
|
(entry (if pdi (program-debug-info-addr pdi) addr)))
|
||||||
|
(or (hashv-ref table entry)
|
||||||
|
(let ((data (make-call-data (and=> pdi program-debug-info-name)
|
||||||
|
(addr->printable entry pdi)
|
||||||
|
(and call-counts
|
||||||
|
(hashv-ref call-counts entry))
|
||||||
|
0
|
||||||
|
0)))
|
||||||
|
(hashv-set! table entry data)
|
||||||
|
data))))
|
||||||
|
|
||||||
|
(define (callee->call-data callee)
|
||||||
|
(cond
|
||||||
|
((number? callee) (addr->call-data callee))
|
||||||
|
((hashv-ref table callee))
|
||||||
|
(else
|
||||||
|
(let ((data (make-call-data
|
||||||
|
(cond ((procedure? callee) (procedure-name callee))
|
||||||
|
;; a primitive
|
||||||
|
((symbol? callee) callee)
|
||||||
|
(else #f))
|
||||||
|
(with-output-to-string (lambda () (write callee)))
|
||||||
|
(and call-counts (hashv-ref call-counts callee))
|
||||||
|
0
|
||||||
|
0)))
|
||||||
|
(hashv-set! table callee data)
|
||||||
|
data))))
|
||||||
|
|
||||||
|
(when call-counts
|
||||||
|
(hash-for-each (lambda (callee count)
|
||||||
|
(callee->call-data callee))
|
||||||
|
call-counts))
|
||||||
|
|
||||||
|
(let visit-stacks ((pos 0))
|
||||||
|
(cond
|
||||||
|
((< pos len)
|
||||||
|
;; FIXME: if we are counting all procedure calls, and
|
||||||
|
;; count-call is on the stack, we need to not count the part
|
||||||
|
;; of the stack that is within count-call.
|
||||||
|
(inc-call-data-self-sample-count!
|
||||||
|
(callee->call-data (vector-ref buffer pos)))
|
||||||
|
(let visit-stack ((pos pos))
|
||||||
|
(let ((callee (vector-ref buffer pos)))
|
||||||
|
(cond
|
||||||
|
((vector-ref buffer pos)
|
||||||
|
=> (lambda (callee)
|
||||||
|
(inc-call-data-cum-sample-count! (callee->call-data callee))
|
||||||
|
(visit-stack (1+ pos))))
|
||||||
|
(else
|
||||||
|
(visit-stacks (1+ pos)))))))
|
||||||
|
(else table)))))
|
||||||
|
|
||||||
(define (statprof-fold-call-data proc init)
|
(define (statprof-fold-call-data proc init)
|
||||||
"Fold @var{proc} over the call-data accumulated by statprof. Cannot be
|
"Fold @var{proc} over the call-data accumulated by statprof. Cannot be
|
||||||
called while statprof is active. @var{proc} should take two arguments,
|
called while statprof is active. @var{proc} should take two arguments,
|
||||||
|
@ -422,14 +496,18 @@ it represents different functions with the same name."
|
||||||
(lambda (key value prior-result)
|
(lambda (key value prior-result)
|
||||||
(proc value prior-result))
|
(proc value prior-result))
|
||||||
init
|
init
|
||||||
(procedure-data (existing-profiler-state))))
|
(stack-samples->procedure-data (existing-profiler-state))))
|
||||||
|
|
||||||
(define (statprof-proc-call-data proc)
|
(define (statprof-proc-call-data proc)
|
||||||
"Returns the call-data associated with @var{proc}, or @code{#f} if
|
"Returns the call-data associated with @var{proc}, or @code{#f} if
|
||||||
none is available."
|
none is available."
|
||||||
(when (statprof-active?)
|
(when (statprof-active?)
|
||||||
(error "Can't call statprof-proc-call-data while profiler is running."))
|
(error "Can't call statprof-proc-call-data while profiler is running."))
|
||||||
(get-call-data (existing-profiler-state) proc))
|
(hashv-ref (stack-samples->procedure-data (existing-profiler-state))
|
||||||
|
(cond
|
||||||
|
((primitive? proc) (procedure-name proc))
|
||||||
|
((program? proc) (program-code proc))
|
||||||
|
(else (program-code proc)))))
|
||||||
|
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
;; Stats
|
;; Stats
|
||||||
|
@ -452,7 +530,8 @@ none is available."
|
||||||
(all-samples (statprof-sample-count))
|
(all-samples (statprof-sample-count))
|
||||||
(secs-per-sample (/ (statprof-accumulated-time)
|
(secs-per-sample (/ (statprof-accumulated-time)
|
||||||
(statprof-sample-count)))
|
(statprof-sample-count)))
|
||||||
(num-calls (and (count-calls? state) (statprof-call-data-calls call-data))))
|
(num-calls (and (call-counts state)
|
||||||
|
(statprof-call-data-calls call-data))))
|
||||||
|
|
||||||
(vector proc-name
|
(vector proc-name
|
||||||
(* (/ self-samples all-samples) 100.0)
|
(* (/ self-samples all-samples) 100.0)
|
||||||
|
@ -504,22 +583,22 @@ optional @var{port} argument is passed, uses the current output port."
|
||||||
(sorted-stats (sort stats-list stats-sorter)))
|
(sorted-stats (sort stats-list stats-sorter)))
|
||||||
|
|
||||||
(define (display-stats-line stats)
|
(define (display-stats-line stats)
|
||||||
(if (count-calls? state)
|
(format port "~6,2f ~9,2f ~9,2f"
|
||||||
(format port "~6,2f ~9,2f ~9,2f ~7d ~8,2f ~8,2f "
|
(statprof-stats-%-time-in-proc stats)
|
||||||
(statprof-stats-%-time-in-proc stats)
|
(statprof-stats-cum-secs-in-proc stats)
|
||||||
(statprof-stats-cum-secs-in-proc stats)
|
(statprof-stats-self-secs-in-proc stats))
|
||||||
(statprof-stats-self-secs-in-proc stats)
|
(if (call-counts state)
|
||||||
(statprof-stats-calls stats)
|
(if (statprof-stats-calls stats)
|
||||||
(* 1000 (statprof-stats-self-secs-per-call stats))
|
(format port " ~7d ~8,2f ~8,2f "
|
||||||
(* 1000 (statprof-stats-cum-secs-per-call stats)))
|
(statprof-stats-calls stats)
|
||||||
(format port "~6,2f ~9,2f ~9,2f "
|
(* 1000 (statprof-stats-self-secs-per-call stats))
|
||||||
(statprof-stats-%-time-in-proc stats)
|
(* 1000 (statprof-stats-cum-secs-per-call stats)))
|
||||||
(statprof-stats-cum-secs-in-proc stats)
|
(format port " "))
|
||||||
(statprof-stats-self-secs-in-proc stats)))
|
(display " " port))
|
||||||
(display (statprof-stats-proc-name stats) port)
|
(display (statprof-stats-proc-name stats) port)
|
||||||
(newline port))
|
(newline port))
|
||||||
|
|
||||||
(if (count-calls? state)
|
(if (call-counts state)
|
||||||
(begin
|
(begin
|
||||||
(format port "~5a ~10a ~7a ~8a ~8a ~8a ~8@a\n"
|
(format port "~5a ~10a ~7a ~8a ~8a ~8a ~8@a\n"
|
||||||
"% " "cumulative" "self" "" "self" "total" "")
|
"% " "cumulative" "self" "" "self" "total" "")
|
||||||
|
@ -546,7 +625,7 @@ optional @var{port} argument is passed, uses the current output port."
|
||||||
statistics.@code{}"
|
statistics.@code{}"
|
||||||
(statprof-fold-call-data
|
(statprof-fold-call-data
|
||||||
(lambda (data prior-value)
|
(lambda (data prior-value)
|
||||||
(when (and (count-calls? state)
|
(when (and (call-counts state)
|
||||||
(zero? (call-data-call-count data))
|
(zero? (call-data-call-count data))
|
||||||
(positive? (call-data-cum-sample-count data)))
|
(positive? (call-data-cum-sample-count data)))
|
||||||
(simple-format #t
|
(simple-format #t
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue