Namespace globals debug
debug.nas -- debugging helpers ------------------------------------------------------------------------------ debug.dump(<variable>) ... dumps contents of variable to terminal; abbreviation for print(debug.string(v)) debug.local([<frame:int>]) ... dump local variables of current or given frame debug.backtrace([<comment:string>], [<dump:bool=1>], [<skip_level:int=0>]} ... writes backtrace (similar to gdb's "bt full) dump=0: only call stack dump=1 (default): with local variables skip_level: remove this many levels from call stack debug.proptrace([<property [, <frames>]]) ... trace property write/add/remove events under the <property> subtree for a number of frames. Defaults are "/" and 2 frames (of which the first one is incomplete). debug.tree([<property> [, <mode>]) ... dump property tree under property path or props.Node hash (default: root). If <mode> is unset or 0, use flat mode (similar to props.dump()), otherwise use space indentation debug.bt() ... abbreviation for debug.backtrace() debug.string(<variable>) ... returns contents of variable as string debug.attributes(<property> [, <verb>]) ... returns attribute string for a given property. <verb>ose is by default 1, and suppressed the node's refcounter if 0. debug.isnan() returns 1 if argument is an invalid number (NaN), 0 if it's a valid number, and nil in all other cases debug.benchmark(<label:string>, <func> [, <repeat:int> [, <output:vector>]]) ... runs function <repeat> times (default: nil) and prints total execution time in seconds, prefixed with <label>, while adding results to <output>, or returning the only result if <repeat> is nil. debug.benchmark_time(<func> [, <repeat:int> [, <output:vector>]]) ... like debug.benchmark, but returns total execution time and does not print anything. debug.rank(<list:vector> [, <repeat:int>]) ... sorts the list of functions based on execution time over <repeat> samples (default: 1). debug.print_rank(<result:vector>, <names:int>) ... prints the <result> of debug.rank with <names> (which can be a vector of [name, func] or [func, name], or a hash of name:func). debug.printerror(<err-vector>) ... prints error vector as set by call() debug.warn(<message>, <level>) ... generate debug message followed by caller stack trace skipping <level> caller levels (default: 0). debug.propify(<variable>) ... turn about everything into a props.Node debug.Probe class ... base class to collect stats; details below debug.Breakpoint class ... conditional backtrace; details below debug.addProbeToFunc(label, func) ... wraps a function with a probe debug.findFunctions(ns, recursive=0) ... find all functions in a hash (namespace) debug.addProbesToNamespace(ns, label="", recursive=0) ... combines findFunctions and addProbeToFunc CAVE: this file makes extensive use of ANSI color codes. These are interpreted by UNIX shells and MS Windows with ANSI.SYS extension installed. If the color codes aren't interpreted correctly, then set property /sim/startup/terminal-ansi-colors=0
Sub-namespaces
emesary_deb
SPDX-License-Identifier: GPL-2.0-or-later NOTE! This copyright does *not* cover user models that use these Nasal services by normal function calls - this is merely considered normal use of the code, and does *not* fall under the heading of "derived work." ------------------------------------------------------------------------------- emesary.deb.nas - emesary debug helpers author: Henning Stahlke created: 06/2020 -------------------------------------------------------------------------------
Classes
Breakpoint
Breakpoint (BP) - do conditional backtrace (BT) controlled via property tree * count how often the BP was hit * do only a limited number of BT, avoid flooding the log / console Data can be viewed / modified in the prop tree /_debug/nas/bp/<myLabel>/* * tokens: number of backtraces to do; each hit will decrement this by 1 * hits: total number of hits == Example == var myBP = debug.Breakpoint.new("myLabel", 0); myBP.enable(4); # allow 4 hits, then be quiet #at the place of interest (e.g. in some loop or class method) insert: myBP.hit(); # do backtrace here if tokens > 0, reduce tokens by 1 myBP.hit(myFunction); # same but call myFunction instead of backtrace print(myBP.getHits()); # print total number of hits
Probe
Probe class - collect statistics; controlled via property tree Data can be viewed / modified in the prop tree /_debug/nas/probe/<myLabel>/* ./enable bool, ./reset bool, reset hit counters to 0 and _start_time to now ./hits[i] number of hits, by default i=0 -> hits secondary counters can be added under the same path with addCounter() ./time after generateStats() show how long the probe was enabled ./hps after generateStats() show avg. hits/second ./hitratio after generateStats() if two counters: hits[1]/hits[0] == Example == var myProbe = debug.Probe.new("myLabel").enable(); var cnt2 = myProbe.addCounter(); # create a 2nd counter #at the place of interest (e.g. in some loop or class method) insert: myProbe.hit(); # count how often this place in the code is hit if (condition) myProbe.hit(cnt2); # count how often condition is true print(myProbe.getHits()); print(myProbe.getHits(cnt2)/myProbe.getHits()); # print hit ratio
Tracer
Tracer - perform conditional backtraces / statistics controlled via property tree * backtraces are written to property tree * do only a limited number of BT, avoid flooding the log / console * trace statistics can be dumped to XML file Data can be viewed / modified in the prop tree /_debug/nas/trc/<myLabel>/* * tokens: number of backtraces to do; each hit will decrement this by 1 * hits: total number of hits == Example == var myBP = debug.Tracer.new("myLabel", 0); myBP.enable(4); # allow 4 hits, then be quiet #at the place of interest (e.g. in some loop or class method) insert: myBP.hit(); # do backtrace here if tokens > 0, reduce tokens by 1 myBP.hit(myFunction); # same but call myFunction instead of backtrace print(myBP.getHits()); # print total number of hits
Functions
addProbeToFunc
addProbeToFunc - wrap a function with a debug probe f: function to wrap with a debug probe (hit counter) label: description, passed to probe WARNING: call() currently breaks the call stack which affects backtrace and the use of caller(i>0). Do not use addProbeToFunc on functions which rely on caller (which is probably bad coding style, but allowed).
addTracerToFunc
addTracerToFunc - wrap a function with a debug breakpoint for tracing f: function to wrap with a tracer label: description, passed to breakpoint WARNING: call() currently breaks the call stack which affects backtrace and the use of caller(i>0). Do not use addTracerToFunc on functions which rely on caller (which is probably bad coding style, but allowed).
benchmark
Executes function fn "repeat" times and prints execution time in seconds. If repeat is an integer and an optional "output" argument is specified, each test's result is appended to that vector, then the vector is returned. If repeat is nil, then the function is run once and the result returned. Otherwise, the result is discarded. Examples: var test = func { getprop("/sim/aircraft"); } debug.benchmark("test()/1", test, 1000); debug.benchmark("test()/2", func setprop("/sim/aircraft", ""), 1000); var results = debug.benchmark("test()", test, 1000, []); print(" Results were:"); print(" ", debug.string(results));
dumpProbeStats
dump a sorted list of hit counters to console
findFunctions
scan a hash for function references ns: the hash to be searched recursive: if you want to search sub hashes (e.g. classes), set this to 1
funcname
According to the Nasal design doc funtions do not have unique internal names. Nevertheless you can sometimes find a matching symbol, so funcname may help to make debug output more helpful, but unfortunately you cannot rely on it.
printerror
print error vector as set by call(). By using call() one can execute code that catches "exceptions" (by a die() call or errors). The Nasal code doesn't abort in this case. Example: var possibly_buggy = func { ... } call(possibly_buggy, nil, var err = []); debug.printerror(err);
propify
Turn p into props.Node (if it isn't yet), or return nil.
rank
Executes each function in the list and returns a sorted vector with the fastest on top (i.e. first). Each position in the result is a vector of [func, time].
warn
like die(), but code execution continues. The level argument defines how many caller() levels to omit. One is automatically omitted, as this would only point to debug.warn(), where the event in question didn't happen.
Variables
bp
-- Init ----------------------------------------------------------------------- General purpose breakpoint for the lazy ones.