(defvar *sampling-mode* :cpu
"Default sampling mode. :CPU for cpu profiling, :ALLOC for allocation
-profiling")
+profiling, and :TIME for wallclock profilgin.")
(declaim (type (member :cpu :alloc :time) *sampling-mode*))
(defvar *alloc-region-size*
(defvar *profiler-lock* (sb-thread:make-mutex :name "Statistical Profiler"))
(defvar *distribution-lock* (sb-thread:make-mutex :name "Wallclock profiling lock"))
+ #+sb-thread
(declaim (inline pthread-kill))
+ #+sb-thread
(define-alien-routine pthread-kill int (os-thread unsigned-long) (signal int))
;;; A random thread will call this in response to either a timer firing,
;;; This in turn will distribute the notice to those threads we are
;;; interested using SIGPROF.
(defun thread-distribution-handler ()
- (declare (optimize sb-c::merge-tail-calls))
+ (declare (optimize speed (space 0)))
(when *sampling*
#+sb-thread
(let ((lock *distribution-lock*))
(max-samples '*max-samples*)
(reset nil)
(mode '*sampling-mode*)
- (loop t)
+ (loop nil)
(max-depth most-positive-fixnum)
show-progress
(threads '(list sb-thread:*current-thread*))
If true (the default) repeatedly evaluate BODY. If false, evaluate
if only once."
(declare (type report-type report))
+ (check-type loop boolean)
`(let* ((*sample-interval* ,sample-interval)
(*alloc-interval* ,alloc-interval)
(*sampling* nil)
(unwind-protect
(progn
(start-profiling :max-depth ,max-depth :threads ,threads)
- (loop
- (when (>= (samples-trace-count *samples*)
- (samples-max-samples *samples*))
- (return))
- ,@(when show-progress
- `((format t "~&===> ~d of ~d samples taken.~%"
- (samples-trace-count *samples*)
- (samples-max-samples *samples*))))
- (let ((.last-index. (samples-index *samples*)))
- ,@body
- (when (= .last-index. (samples-index *samples*))
- (warn "No sampling progress; possibly a profiler bug.")
- (return)))
- (unless ,loop
- (return))))
+ ,(if loop
+ `(loop
+ (when (>= (samples-trace-count *samples*)
+ (samples-max-samples *samples*))
+ (return))
+ ,@(when show-progress
+ `((format t "~&===> ~d of ~d samples taken.~%"
+ (samples-trace-count *samples*)
+ (samples-max-samples *samples*))))
+ (let ((.last-index. (samples-index *samples*)))
+ ,@body
+ (when (= .last-index. (samples-index *samples*))
+ (warn "No sampling progress; possibly a profiler bug.")
+ (return))))
+ `(progn
+ ,@body)))
(stop-profiling))
,@(when report-p `((report :type ,report)))))
:mode mode))
(enable-call-counting)
(setf *profiled-threads* threads)
- (sb-sys:enable-interrupt sb-unix:sigprof #'sigprof-handler)
+ (sb-sys:enable-interrupt sb-unix:sigprof
+ #'sigprof-handler
+ :synchronous t)
(ecase mode
(:alloc
(let ((alloc-signal (1- alloc-interval)))
(if (and (consp name)
(member (first name)
'(sb-c::xep sb-c::tl-xep sb-c::&more-processor
- sb-c::varargs-entry
sb-c::top-level-form
- sb-c::hairy-arg-processor
sb-c::&optional-processor)))
(second name)
name)))
(with-profiling (:reset t :max-samples 1000 :report :graph)
(test-0 7)))
+(defun consalot ()
+ (let ((junk '()))
+ (loop repeat 10000 do
+ (push (make-array 10) junk))
+ junk))
+
+(defun consing-test ()
+ ;; 0.0001 chosen so that it breaks rather reliably when sprof does not
+ ;; respect pseudo atomic.
+ (with-profiling (:reset t :sample-interval 0.0001 :report :graph :loop nil)
+ (let ((target (+ (get-universal-time) 15)))
+ (princ #\.)
+ (force-output)
+ (loop
+ while (< (get-universal-time) target)
+ do (consalot)))))
+
;;; provision
(provide 'sb-sprof)