3 (declaim (optimize (speed 3) (safety 1)))
5 (defmacro with-measuring
((var measure-fn
) &body body
)
6 (let ((initial (gensym)))
7 `(let ((,initial
(,measure-fn
)))
9 (setf ,var
(- (,measure-fn
) ,initial
)))))
11 (defmacro measure-time
((var) &body body
)
13 (with-measuring (,var get-internal-real-time
)
15 (setf ,var
(coerce (/ ,var internal-time-units-per-second
)
18 (defmacro measure-conses
((var) &body body
)
19 `(with-measuring (,var total-bytes-allocated
)
22 (defun measure (fn &rest args
)
23 (declare (dynamic-extent args
))
24 (let ((bytes 0) (seconds 0) result
)
25 (measure-time (seconds)
26 (measure-conses (bytes)
27 (setf result
(apply fn args
))))
28 (values seconds bytes result
)))
30 (defun benchmark (name fn
&rest args
)
31 (declare (dynamic-extent args
))
32 (let ((seconds 0.0) (conses 0) result
)
34 (setf (values seconds conses result
)
35 (apply 'measure fn args
))))
36 (cond ((or (eq :time
*profiling
*)
37 (eq :space
*profiling
*))
38 (with-profiling (:type
*profiling
*) (do-it)))
39 ((eq :count
*profiling
*)
40 (with-profiling (:count t
) (do-it)))
43 (let ((date-stamp (get-universal-time)))
44 (ensure-directories-exist *benchmark-file
*)
46 (with-open-file (output *benchmark-file
*
48 :if-does-not-exist
:create
50 (with-standard-io-syntax
51 (let ((*print-readably
* nil
))
53 (format output
"\(~11,d ~20,s ~10,s ~10,s ~{~s~^ ~}~30,s ~s ~s\)"
55 seconds conses
*additional-markers
*
56 (if (symbolp fn
) fn
"<function>") args result
))))
58 (let ((pathname (merge-pathnames
61 :name
(format nil
"~a-~a-~a"
62 name
*profiling
* date-stamp
))
64 (format t
"~&Profiling output being sent to ~a" pathname
)
65 (with-open-file (output pathname
67 :if-does-not-exist
:create
69 (format output
"~&Profile data for ~a" name
)
70 (format output
"~& Total time: ~,2F; Total space: ~:d \(~d\)"
71 seconds conses conses
)
72 (format output
"~& Arguments:~{~& ~s,~^~}" args
)
73 (format output
"~%~%")
74 (when (or (eq :time
*profiling
*)
75 (eq :space
*profiling
*))
76 (prof:show-flat-profile
:stream output
)
77 (prof:show-call-graph
:stream output
))
78 (when (eq :count
*profiling
*)
79 (let ((*standard-output
* output
)
80 (*print-readably
* nil
))
81 (prof:show-call-counts
)))))))
82 (list seconds conses result
))))