0.6.12.49:
[sbcl.git] / src / code / profile.lisp
index 4f4f9ab..524b5fd 100644 (file)
@@ -94,6 +94,7 @@
   (total (required-argument) :type single-float :read-only t))
 (defvar *overhead*)
 (declaim (type overhead *overhead*))
+(makunbound '*overhead*) ; in case we reload this file when tweaking
 \f
 ;;;; profile encapsulations
 
 ;;; inline.
 (defmacro fastbig- (x y)
   (once-only ((x x) (y y))
-    `(if (and (typep ,x 'fixnum)
-             (typep ,y 'fixnum))
+    `(if (and (typep ,x '(and fixnum unsigned-byte))
+             (typep ,y '(and fixnum unsigned-byte)))
+        ;; special case: can use fixnum arithmetic and be guaranteed
+        ;; the result is also a fixnum
         (- ,x ,y)
+        ;; general case
         (- ,x ,y))))
 (defmacro fastbig-1+ (x)
   (once-only ((x x))
        (let ((dticks 0)
             (dconsing 0)
             (inner-enclosed-profiles 0))
-        ;;(declare (type unsigned-byte dticks dconsing))
-        ;;(declare (type unsigned-byte inner-enclosed-profiles))
+        (declare (type unsigned-byte dticks dconsing))
+        (declare (type unsigned-byte inner-enclosed-profiles))
         (aver (typep dticks 'unsigned-byte))
         (aver (typep dconsing 'unsigned-byte))
         (aver (typep inner-enclosed-profiles 'unsigned-byte))
         (multiple-value-prog1
-            (let ((start-ticks (get-internal-ticks))
-                  (start-consing (get-bytes-consed))
-                  (*enclosed-ticks* 0)
-                  (*enclosed-consing* 0)
-                  (*enclosed-profiles* 0))
+            (let* ((start-ticks (get-internal-ticks))
+                   (*enclosed-ticks* 0)
+                   (*enclosed-consing* 0)
+                   (*enclosed-profiles* 0)
+                   (nbf-pcounter *n-bytes-freed-or-purified-pcounter*)
+                   ;; Typically NBF-PCOUNTER will represent a bignum.
+                   ;; In general we don't want to cons up a new
+                   ;; bignum for every encapsulated call, so instead
+                   ;; we keep track of the PCOUNTER internals, so
+                   ;; that as long as we only cons small amounts,
+                   ;; we'll almost always just do fixnum arithmetic.
+                   ;; (And for encapsulated functions which cons
+                   ;; large amounts, then a single extra consed
+                   ;; bignum tends to be proportionally negligible.)
+                   (nbf0-integer (pcounter-integer nbf-pcounter))
+                   (nbf0-fixnum (pcounter-fixnum nbf-pcounter))
+                   (dynamic-usage-0 (sb-kernel:dynamic-usage)))
               (declare (inline pcounter-or-fixnum->integer))
               (multiple-value-prog1
                   (multiple-value-call encapsulated-fun
                                        (sb-c:%more-arg-values arg-context
                                                               0
                                                               arg-count))
-                (let ((*computing-profiling-data-for* encapsulated-fun))
-                  (setf dticks (fastbig- (get-internal-ticks) start-ticks)
-                        dconsing (fastbig- (get-bytes-consed) start-consing))
+                (let ((*computing-profiling-data-for* encapsulated-fun)
+                      (dynamic-usage-1 (sb-kernel:dynamic-usage)))
+                  (setf dticks (fastbig- (get-internal-ticks) start-ticks))
+                  (setf dconsing
+                        (if (and (eq (pcounter-integer nbf-pcounter)
+                                     nbf0-integer)
+                                 (eq (pcounter-fixnum nbf-pcounter)
+                                     nbf0-fixnum))
+                            ;; common special case where we can avoid
+                            ;; bignum arithmetic
+                            (- dynamic-usage-1
+                               dynamic-usage-0)
+                            ;; general case
+                            (- (get-bytes-consed)
+                               nbf0-integer
+                               nbf0-fixnum
+                               dynamic-usage-0)))
                   (setf inner-enclosed-profiles
                         (pcounter-or-fixnum->integer *enclosed-profiles*))
-                  (aver (not (minusp dconsing))) ; REMOVEME
-                  (aver (not (minusp inner-enclosed-profiles))) ; REMOVEME
                   (let ((net-dticks (fastbig- dticks *enclosed-ticks*)))
                     (fastbig-incf-pcounter-or-fixnum ticks net-dticks))
                   (let ((net-dconsing (fastbig- dconsing *enclosed-consing*)))
-                    (when (minusp net-dconsing) ; REMOVEME
-                      (unprofile-all)
-                      (error "huh? DCONSING=~S, *ENCLOSED-CONSING*=~S"
-                             dticks *enclosed-ticks*))
                     (fastbig-incf-pcounter-or-fixnum consing net-dconsing))
                   (fastbig-incf-pcounter-or-fixnum profiles
                                                    inner-enclosed-profiles))))
     (max raw-compensated 0.0)))
 
 (defun report ()
-  "Report results from profiling. The results are
-approximately adjusted for profiling overhead, but when RAW is true
-the unadjusted results are reported. The compensation may be somewhat
-inaccurate when bignums are involved in runtime calculation, as in
-a very-long-running Lisp process."
+  "Report results from profiling. The results are approximately adjusted
+for profiling overhead. The compensation may be rather inaccurate when
+bignums are involved in runtime calculation, as in a very-long-running
+Lisp process."
   (declare #.*optimize-external-despite-byte-compilation*)
   (unless (boundp '*overhead*)
     (setf *overhead*
@@ -425,10 +448,14 @@ a very-long-running Lisp process."
 ;;;; overhead estimation
 
 ;;; We average the timing overhead over this many iterations.
-(defconstant +timer-overhead-iterations+
-  50 ; REMOVEME
-  ;;50000
-  )
+;;;
+;;; (This is a variable, not a constant, so that it can be set in
+;;; .sbclrc if desired. Right now, that's an unsupported extension
+;;; that I (WHN) use for my own experimentation, but it might
+;;; become supported someday. Comments?)
+(declaim (type unsigned-byte *timer-overhead-iterations*))
+(defparameter *timer-overhead-iterations*
+  500000)
 
 ;;; a dummy function that we profile to find profiling overhead
 (declaim (notinline compute-overhead-aux))
@@ -437,14 +464,15 @@ a very-long-running Lisp process."
 
 ;;; Return a newly computed OVERHEAD object.
 (defun compute-overhead ()
+  (format *debug-io* "~&measuring PROFILE overhead..")
   (flet ((frob ()
           (let ((start (get-internal-ticks))
                 (fun (symbol-function 'compute-overhead-aux)))
-            (dotimes (i +timer-overhead-iterations+)
+            (dotimes (i *timer-overhead-iterations*)
               (funcall fun fun))
             (/ (float (- (get-internal-ticks) start))
                (float +ticks-per-second+)
-               (float +timer-overhead-iterations+)))))
+               (float *timer-overhead-iterations*)))))
     (let (;; Measure unprofiled calls to estimate call overhead.
          (call-overhead (frob))
          total-overhead
@@ -462,14 +490,16 @@ a very-long-running Lisp process."
          (setf internal-overhead
                (/ (float time)
                   (float +ticks-per-second+)
-                  (float +timer-overhead-iterations+))))
+                  (float *timer-overhead-iterations*))))
        (unprofile compute-overhead-aux))
-      (make-overhead :call call-overhead
-                    :total total-overhead
-                    :internal internal-overhead))))
+      (prog1
+         (make-overhead :call call-overhead
+                        :total total-overhead
+                        :internal internal-overhead)
+       (format *debug-io* "done~%")))))
 
 ;;; It would be bad to compute *OVERHEAD*, save it into a .core file,
-;;; then load old *OVERHEAD* value from the .core file into a
+;;; then load the old *OVERHEAD* value from the .core file into a
 ;;; different machine running at a different speed. We avoid this by
 ;;; erasing *CALL-OVERHEAD* whenever we save a .core file.
 (pushnew (lambda ()