diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2016-10-29 06:02:54 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2016-10-29 06:02:54 -0700 |
commit | 7322e0e52f4c8a0bc5311ffc3a5488826f37b96e (patch) | |
tree | 2c02f20cc43a4fc0f886aace153a897a0911bd21 | |
parent | f24104801a4a50ebdc5231755a62d1124e381c91 (diff) | |
download | txr-7322e0e52f4c8a0bc5311ffc3a5488826f37b96e.tar.gz txr-7322e0e52f4c8a0bc5311ffc3a5488826f37b96e.tar.bz2 txr-7322e0e52f4c8a0bc5311ffc3a5488826f37b96e.zip |
Adding function tracing support.
New variable *trace-output*, and macros trace and untrace.
* lisplib.c (trace_set_entries, trace_instantiate): new static
functions.
(dlt_register): Register new functions to auto-load trace
module.
* share/txr/stdlib/trace.tl: New file.
* txr.1: Documented.
-rw-r--r-- | lisplib.c | 16 | ||||
-rw-r--r-- | share/txr/stdlib/trace.tl | 50 | ||||
-rw-r--r-- | txr.1 | 62 |
3 files changed, 128 insertions, 0 deletions
@@ -371,6 +371,21 @@ static val build_instantiate(val set_fun) return nil; } +static val trace_set_entries(val dlt, val fun) +{ + val name[] = { + lit("*trace-output*"), lit("trace"), lit("untrace"), nil + }; + set_dlt_entries(dlt, name, fun); + return nil; +} + +static val trace_instantiate(val set_fun) +{ + funcall1(set_fun, nil); + load(format(nil, lit("~atrace.tl"), stdlib_path, nao)); + return nil; +} val dlt_register(val dlt, val (*instantiate)(val), @@ -403,6 +418,7 @@ void lisplib_init(void) #endif dlt_register(dl_table, awk_instantiate, awk_set_entries); dlt_register(dl_table, build_instantiate, build_set_entries); + dlt_register(dl_table, trace_instantiate, trace_set_entries); } val lisplib_try_load(val sym) diff --git a/share/txr/stdlib/trace.tl b/share/txr/stdlib/trace.tl new file mode 100644 index 00000000..9cf6729c --- /dev/null +++ b/share/txr/stdlib/trace.tl @@ -0,0 +1,50 @@ +(defvar *trace-output* *stdout*) + +(defvar sys:*trace-hash* (hash)) +(defvar sys:*trace-level* -1) + +(defun sys:trace-enter (name args) + (format *trace-output* "~*a(~s ~s\n" (* sys:*trace-level* 2) "" name args)) + +(defun sys:trace-leave (name val) + (format *trace-output* "~*a ~s)\n" (* sys:*trace-level* 2) "" val)) + +(defun sys:trace (names) + (cond + ((null names) (hash-keys sys:*trace-hash*)) + (t + (each ((n names)) + (unless [sys:*trace-hash* n] + (let* ((name n) + (prev (symbol-function n)) + (hook (lambda (. args) + (let ((abandoned t) + (sys:*trace-level* (succ sys:*trace-level*))) + (unwind-protect + (progn + (sys:trace-enter name args) + (let ((val (apply prev args))) + (sys:trace-leave name val) + (set abandoned nil) + val)) + (if abandoned + (sys:trace-leave name :abandoned))))))) + (set [sys:*trace-hash* n] prev) + (set (symbol-function n) hook))))))) + +(defun sys:untrace (names) + (flet ((disable (name) + (let ((prev (del [sys:*trace-hash* name]))) + (when prev + (set (symbol-function name) prev))))) + (if names + (each ((n names)) + (disable n)) + (dohash (n v sys:*trace-hash*) + (disable n))))) + +(defmacro trace (. names) + ^(sys:trace ',names)) + +(defmacro untrace (. names) + ^(sys:untrace ',names)) @@ -46479,6 +46479,68 @@ This variable holds the absolute path name of the directory which holds the executable file of the current process. This path includes the trailing slash. +.SS* Function Tracing + +.coNP Special variable *trace-output* +.desc +The +.code *trace-output* +special variable holds a stream to which all trace output +is sent. Trace output consists of diagnostics enabled by the +.code trace +macro. + +.coNP Macros @ trace and @ untrace +.synb +.mets (trace << function-name *) +.mets (untrace << function-name *) +.syne +.desc +The +.code trace +and +.code untrace +macros control function tracing. + +When +.code trace +is called with one or more arguments, it considers each +argument to be the name of a global function. For each +function, it turns on tracing, if it is not already turned on. + +When +.code trace +is called with no arguments, it lists the names of functions +for which tracing is currently enabled. + +When +.code untrace +is called with one or more arguments, it considers each +argument to be the name of a global function. For each +function, it turns off tracing, if tracing is enabled. + +When +.code untrace +is called with no arguments, it disables tracing for all +functions. + +Tracing a function consists of printing a message prior to entry into the +function indicating its name and arguments, and another message upon leaving +the function indicating its return value, which is syntactically correlated +with the entry message, using a combination of matching and indentation. +These messages are posted to the +.code *trace-output* +stream. + +When traced functions call each other or recurse, these trace messages +nest. The nesting is detected and translated into indentation levels. + +Tracing works by replacing a function definition with a trace hook function, and +retaining the previous definition. The trace hook calls the previous definition +and produces the diagnostics around it. When +.code untrace +is used to disable tracing, the previous definition is restored. + .SH* INTERACTIVE LISTENER .SS* Overview |