Library globals

Namespace globals . debug

View source

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).

addProbesToNamespace

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).

attributes

backtrace

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));

benchmark_time

dump

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.

isnan

local

print_rank

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.

proptrace

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].

removeProbesFromNamespace

string

tree

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.

bt

dumpN