Often, probes will want to share data that cannot be represented as a simple scalar value. Much data is naturally tabular in nature, indexed by some tuple of thread numbers, processor ids, names, time, and so on. Systemtap offers associative arrays for this purpose. These arrays are implemented as hash tables with a maximum size that is fixed at startup. Because they are too large to be created dynamically for inidividual probes handler runs, they must be declared as global.
global a |
declare global scalar or array variable |
global b[400] |
declare array, reserving space for up to 400 tuples |
The basic operations for arrays are setting and looking up elements.
These are expressed in awk syntax: the array name followed by
an opening [ bracket, a comma-separated list of index
expressions, and a closing ] bracket. Each index expression
may be string or numeric, as long as it is consistently typed
throughout the script.
foo [4,"hello"] ++ |
increment the named array slot |
processusage [uid(),execname()] ++ |
update a statistic |
times [tid()] = get_cycles() |
set a timestamp reference point |
delta = get_cycles() - times [tid()] |
compute a timestamp delta |
Array elements that have not been set may be fetched, and return
a dummy null value (zero or an empty string) as appropriate. However,
assigning a null value does not delete the element: an explicit
delete statement is required. Systemtap provides syntactic sugar
for these operations, in the form of explicit membership testing and
deletion.
if ([4,"hello"] in foo) { } |
membership test |
delete times[tid()] |
deletion of a single element |
delete times |
deletion of all elements |
One final and important operation is iteration over arrays. This uses
the keyword foreach. Like awk, this creates a loop that
iterates over key tuples of an array, not just values. In
addition, the iteration may be sorted by any single key or the
value by adding an extra + or - code.
The break and continue statements work inside
foreach loops, too. Since arrays can be large but probe
handlers must not run for long, it is a good idea to exit iteration
early if possible. The limit option in the foreach
expression is one way. For simplicity, systemtap forbids any modification of an array while it is being iterated using a
foreach.
foreach ([a,b] in foo) { fuss_with(foo[a,b]) } |
simple loop in arbitrary sequence |
foreach ([a,b] in foo+ limit 5) { } |
loop in increasing sequence of value, stop after 5 |
foreach ([a-,b] in foo) { } |
loop in decreasing sequence of first key |