X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=contrib%2Fsb-sprof%2Fsb-sprof.lisp;h=d638443d072a7168d25947ad85ec1e8e8096a360;hb=fb8533122551bbb7aea669f40bc91c1211809b58;hp=fdeba626bfd086a0f44259590f517ad69a02edc7;hpb=8b64d57b865fec6ba082dda965146b5e8aa877b3;p=sbcl.git diff --git a/contrib/sb-sprof/sb-sprof.lisp b/contrib/sb-sprof/sb-sprof.lisp index fdeba62..d638443 100644 --- a/contrib/sb-sprof/sb-sprof.lisp +++ b/contrib/sb-sprof/sb-sprof.lisp @@ -84,9 +84,6 @@ ;;; ;;; Random ideas for implementation: ;;; -;;; * Show a disassembly of a function annotated with sampling -;;; information. -;;; ;;; * Space profiler. Sample when new pages are allocated instead of ;;; at SIGPROF. ;;; @@ -202,14 +199,14 @@ (defun topological-sort (dag) (let ((sorted ()) (dfn -1)) - (labels ((sort (v) + (labels ((rec-sort (v) (setf (vertex-visited v) t) (setf (vertex-dfn v) (incf dfn)) (dolist (e (vertex-edges v)) (unless (vertex-visited (edge-vertex e)) - (sort (edge-vertex e)))) + (rec-sort (edge-vertex e)))) (push v sorted))) - (map-vertices #'sort dag) + (map-vertices #'rec-sort dag) (nreverse sorted)))) ;;; Reduce graph G to a dag by coalescing strongly connected components @@ -372,18 +369,20 @@ ;;; comparison function Test. Assume each element to sort consists of ;;; Element-Size array slots, and that the slot Key-Offset contains ;;; the sort key. -(defun qsort (vec &key (test #'<) (element-size 1) (key-offset 0) +(defun qsort (vec &key (element-size 1) (key-offset 0) (from 0) (to (- (length vec) element-size))) - (declare (fixnum to from element-size) - (function test)) + (declare (type fixnum to from element-size key-offset)) + (declare (type (simple-array address) vec)) (labels ((rotate (i j) + (declare (fixnum i j)) (loop repeat element-size for i from i and j from j do (rotatef (aref vec i) (aref vec j)))) (key (i) (aref vec (+ i key-offset))) - (sort (from to) - (when (> to from) + (rec-sort (from to) + (declare (fixnum to from)) + (when (> to from) (let* ((mid (* element-size (round (+ (/ from element-size) (/ to element-size)) @@ -391,21 +390,31 @@ (i from) (j (+ to element-size)) (p (key mid))) - (declare (fixnum i j)) + (declare (fixnum mid i j)) (rotate mid from) (loop (loop do (incf i element-size) until (or (> i to) - (funcall test p (key i)))) + ;; QSORT used to take a test + ;; parameter which was funcalled + ;; here. This caused some consing, + ;; which is problematic since + ;; QSORT is indirectly called in + ;; an after-gc-hook. So just + ;; hardcode >, which would've been + ;; used for the test anyway. + ;; --JES, 2004-07-09 + (> p (key i)))) (loop do (decf j element-size) until (or (<= j from) - (funcall test (key j) p))) + ;; As above. + (> (key j) p))) (when (< j i) (return)) (rotate i j)) (rotate from j) - (sort from (- j element-size)) - (sort i to))))) - (sort from to) + (rec-sort from (- j element-size)) + (rec-sort i to))))) + (rec-sort from to) vec)) @@ -543,7 +552,7 @@ `(let ((*sampling* ,on)) ,@body)) -(defun sort-samples (&key test (key :pc)) +(defun sort-samples (&key (key :pc)) "Sort *Samples* using comparison Test. Key must be one of :Pc or :Return-Pc for sorting by pc or return pc." (declare (type (member :pc :return-pc) key)) @@ -551,7 +560,6 @@ (qsort *samples* :from 0 :to (- *samples-index* +sample-size+) - :test test :element-size +sample-size+ :key-offset (if (eq key :pc) 0 1)))) @@ -574,7 +582,7 @@ (fp (sb-vm::context-register scp #.sb-vm::ebp-offset)) (ra (sap-ref-32 (int-sap fp) (- (* (1+ sb-vm::return-pc-save-offset) - sb-vm::n-word-bytes))))) + sb-vm::n-word-bytes))))) (record (sap-int pc-ptr)) (record ra))))))) @@ -630,7 +638,7 @@ ;;; dynamic-space code objects. KEY being :PC means adjust pcs. (defun adjust-samples (key) (declare (type (member :pc :return-pc) key)) - (sort-samples :test #'> :key key) + (sort-samples :key key) (let ((sidx 0) (offset (if (eq key :pc) 0 1))) (declare (type sb-impl::index sidx)) @@ -663,8 +671,9 @@ (dolist (info *dynamic-space-code-info*) (setf (dyninfo-new-start info) (code-start (dyninfo-code info)))) - (adjust-samples :pc) - (adjust-samples :return-pc) + (progn + (adjust-samples :pc) + (adjust-samples :return-pc)) (dolist (info *dynamic-space-code-info*) (let ((size (- (dyninfo-end info) (dyninfo-start info)))) (setf (dyninfo-start info) (dyninfo-new-start info)) @@ -1013,7 +1022,7 @@ (format t "~& Count % Parts~%") (do-vertices (node call-graph) (when (cycle-p node) - (flet ((print (indent index count percent name) + (flet ((print-info (indent index count percent name) (format t "~&~6d ~5,1f ~11@t ~V@t ~s [~d]~%" count percent indent name index))) (print-separator) @@ -1022,9 +1031,9 @@ (samples-percent call-graph (cycle-count node)) (node-name node)) (dolist (v (vertex-scc-vertices node)) - (print 4 (node-index v) (node-count v) - (samples-percent call-graph (node-count v)) - (node-name v)))))) + (print-info 4 (node-index v) (node-count v) + (samples-percent call-graph (node-count v)) + (node-name v)))))) (print-separator) (format t "~2%"))) @@ -1036,7 +1045,7 @@ (print-cycles call-graph) (flet ((find-call (from to) (find to (node-edges from) :key #'call-vertex)) - (print (indent index count percent name) + (print-info (indent index count percent name) (format t "~&~6d ~5,1f ~11@t ~V@t ~s [~d]~%" count percent indent name index))) (format t "~& Callers~%") @@ -1048,10 +1057,10 @@ ;; Print caller information. (dolist (caller (node-callers node)) (let ((call (find-call caller node))) - (print 4 (node-index caller) - (call-count call) - (samples-percent call-graph (call-count call)) - (node-name caller)))) + (print-info 4 (node-index caller) + (call-count call) + (samples-percent call-graph (call-count call)) + (node-name caller)))) ;; Print the node itself. (format t "~&~6d ~5,1f ~6d ~5,1f ~s [~d]~%" (node-count node) @@ -1062,10 +1071,10 @@ (node-index node)) ;; Print callees. (do-edges (call called node) - (print 4 (node-index called) - (call-count call) - (samples-percent call-graph (call-count call)) - (node-name called)))) + (print-info 4 (node-index called) + (call-count call) + (samples-percent call-graph (call-count call)) + (node-name called)))) (print-separator) (format t "~2%") (print-flat call-graph :stream stream :max max @@ -1111,6 +1120,26 @@ ((nil))) graph)) +;;; Interface to DISASSEMBLE + +(defun add-disassembly-profile-note (chunk stream dstate) + (declare (ignore chunk stream)) + (unless (zerop *samples-index*) + (let* ((location + (+ (sb-disassem::seg-virtual-location + (sb-disassem:dstate-segment dstate)) + (sb-disassem::dstate-cur-offs dstate))) + (samples (loop for x from 0 below *samples-index* by +sample-size+ + summing (if (= (aref *samples* x) location) + 1 + 0)))) + (unless (zerop samples) + (sb-disassem::note (format nil "~A/~A samples" + samples (/ *samples-index* +sample-size+)) + dstate))))) + +(pushnew 'add-disassembly-profile-note sb-disassem::*default-dstate-hooks*) + ;;; silly examples (defun test-0 (n &optional (depth 0))