57a38f7b4a9185f2e113c79776ffa25671917b31
[sbcl.git] / pcounter.lisp
1 ;;;; PCOUNTERs
2 ;;;;
3 ;;;; a PCOUNTER is used to represent an unsigned integer quantity which
4 ;;;; can grow bigger than a fixnum, but typically does so, if at all,
5 ;;;; in many small steps, where we don't want to cons on every step.
6 ;;;; Such quantities typically arise in profiling, e.g. 
7 ;;;; total system consing, time spent in a profiled function, and
8 ;;;; bytes consed in a profiled function are all examples of such
9 ;;;; quantities. The name is an abbreviation for "Profiling COUNTER".
10 ;;;;
11 ;;;; It's not one of my more brilliant names, if you have a better
12 ;;;; suggestion, I might be interested. -- WHN 2001-06-22
13
14 (in-package "SB!IMPL")
15 \f
16 ;;;; basic PCOUNTER stuff
17
18 (/show0 "pcounter.lisp 16")
19
20 (defstruct (pcounter (:copier nil))
21   (integer 0 :type unsigned-byte)
22   (fixnum 0 :type (and fixnum unsigned-byte)))
23
24 (/show0 "pcounter.lisp 22")
25
26 (declaim (maybe-inline incf-pcounter))
27 (defun incf-pcounter (pcounter delta)
28   (aver (typep delta 'unsigned-byte))
29   (let ((sum (+ (pcounter-fixnum pcounter) delta)))
30     (cond ((typep sum 'fixnum)
31            (setf (pcounter-fixnum pcounter) sum))
32           (t
33            (incf (pcounter-integer pcounter) sum)
34            (setf (pcounter-fixnum pcounter) 0))))
35   pcounter)
36
37 (/show0 "pcounter.lisp 36")
38
39 ;;;(declaim (inline pcounter->integer)) ; FIXME: maybe inline when more stable
40 (defun pcounter->integer (pcounter)
41   (+ (pcounter-integer pcounter)
42      (pcounter-fixnum pcounter)))
43 \f
44 ;;;; operations on (OR PCOUNTER FIXNUM)
45 ;;;;
46 ;;;; When we don't want to cons a PCOUNTER unless we're forced to, we
47 ;;;; start with a FIXNUM counter and only create a PCOUNTER if the
48 ;;;; FIXNUM overflows.
49
50 (/show0 "pcounter.lisp 50")
51
52 (declaim (inline %incf-pcounter-or-fixnum))
53 (defun %incf-pcounter-or-fixnum (x delta)
54   (etypecase x
55     (fixnum
56      (let ((sum (+ x delta)))
57        (if (typep sum 'fixnum)
58            sum
59            (make-pcounter :integer sum))))
60     (pcounter
61      (incf-pcounter x delta))))
62   
63 (define-modify-macro incf-pcounter-or-fixnum (delta) %incf-pcounter-or-fixnum)
64
65 (/show0 "pcounter.lisp 64")
66
67 ;;; Trade off space for execution time by handling the common fast
68 ;;; (TYPEP DELTA 'FIXNUM) case inline and only calling generic
69 ;;; arithmetic as a last resort.
70 (defmacro fastbig-incf-pcounter-or-fixnum (x delta)
71   (let ((delta-sym (gensym "DELTA")))
72     `(let ((,delta-sym ,delta))
73        (aver (typep ,delta-sym 'unsigned-byte))
74        ;;(declare (type unsigned-byte ,delta-sym))
75        (if (typep ,delta-sym 'fixnum)
76            (incf-pcounter-or-fixnum ,x ,delta)
77            (incf-pcounter-or-fixnum ,x ,delta)))))
78
79 (/show0 "pcounter.lisp 80")
80
81 (declaim (maybe-inline pcounter-or-fixnum->integer))
82 (defun pcounter-or-fixnum->integer (x)
83   (etypecase x
84     (fixnum x)
85     (pcounter (pcounter->integer x))))
86
87 (/show0 "pcounter.lisp end")