Simple TRACE utility
authorDavid Vázquez <davazp@gmail.com>
Wed, 15 May 2013 09:10:37 +0000 (10:10 +0100)
committerDavid Vázquez <davazp@gmail.com>
Wed, 15 May 2013 09:10:37 +0000 (10:10 +0100)
src/misc.lisp
src/toplevel.lisp

index b3b24c1..3f4c5de 100644 (file)
        (prog1 (progn ,form)
          (setq ,end (get-internal-real-time))
          (format t "Execution took ~a seconds.~%" (/ (- ,end ,start) 1000.0))))))
+
+
+;;;; TRACE
+
+;;; This trace implementation works on symbols, replacing the function
+;;; with a wrapper. So it will not trace calls to the function if they
+;;; got the function object before it was traced.
+
+;;; An alist of the form (NAME FUNCTION), where NAME is the name of a
+;;; function, and FUNCTION is the function traced.
+(defvar *traced-functions* nil)
+(defvar *trace-level* 0)
+
+(defun trace-report-call (name args)
+  (dotimes (i *trace-level*) (write-string " "))
+  (format t "~a: ~S~%" *trace-level* (cons name args)))
+
+(defun trace-report-return (name values)
+  (dotimes (i *trace-level*) (write-string " "))
+  (format t "~a: ~S returned " *trace-level* name)
+  (dolist (value values) (format t "~S " value))
+  (format t "~%"))
+
+(defun trace-functions (names)
+  (if (null names)
+      (mapcar #'car *traced-functions*)
+      (dolist (name names names)
+        (if (find name *traced-functions* :key #'car)
+            (format t "`~S' is already traced.~%" name)
+            (let ((func (fdefinition name)))
+              (fset name (lambda (&rest args)
+                           (let (values)
+                             (trace-report-call name args)
+                             (let ((*trace-level* (+ *trace-level* 1)))
+                               (setq values (multiple-value-list (apply func args))))
+                             (trace-report-return name values)
+                             (values-list values))))
+              (push (cons name func) *traced-functions*))))))
+
+(defun untrace-functions (names)
+  (when (null names)
+    (setq names (mapcar #'car *traced-functions*)))
+  (dolist (name names)
+    (let ((func (cdr (find name *traced-functions* :key #'car))))
+      (if func
+          (fset name func)
+          (format t "~S is not being traced.~%" name)))))
+
+(defmacro trace (&rest names)
+  `(trace-functions ',names))
+
+(defmacro untrace (&rest names)
+  `(untrace-functions ',names))
index d148a47..ed0abfe 100644 (file)
@@ -75,8 +75,9 @@
           second set setf setq seventh sixth some string string-upcase string=
           stringp sublis subseq subst symbol-function symbol-name symbol-package
           symbol-plist symbol-value symbolp t tagbody tailp tenth third throw
-          time tree-equal truncate unless unwind-protect values values-list variable
-          vector-push-extend warn when write-line write-string zerop))
+          time trace tree-equal truncate unless untrace unwind-protect values
+          values-list variable vector-push-extend warn when write-line write-string
+          zerop))
 
 (setq *package* *user-package*)