Predicates

Predicates are usually go in the beginning of the probe and allow to exclude unnecessary data from output, thus saving memory and processor time. Usually predicate is a conditional expression, so you can use C comparison operators in there such as ==, !=, >, >=, <, <= and logical operators && for logical AND, || for logical OR and ! for logical negation, alas with calling functions or actions.

In DTrace predicate is a separate language construct which is going in slashes / immediately after list of probe names. If it evaluated to true, probe is executed:

syscall::write:entry 
/pid == $target/
{
    printf("Written %d bytes", args[3]);
}

In SystemTap, however, there is no separate predicate language construct, but it supports conditional statement and next statement which exits from the probe, so combining them will give similar effect:

probe syscall.write {
    if(pid() != target())
        next;
    printf("Written %d bytes", $count);
}

Note that in SystemTap, probe will be omitted if condition in if statement is evaluated to true thus making this logic inverse to DTrace.

Starting with SystemTap 2.6, it supports mechanism similar to predicates which is called on-the-fly arming/disarming. When it is active, probes will be installed only when certain condition will become true. For example:

probe syscall.write if(i > 4) {
        printf("Written %d bytes", $count);
}

This probe will be installed when i becomes more than four.

$target in DTrace (macro-substitution) and target() context function in SystemTap have special meaning: they return PID of the process which is traced (command was provided as -c option argument or its PID was passed as -p/-x option argument). In these examples only write syscalls from traced process will be printed.

Warning

Sometimes, SystemTap may trace its consumer. To ignore such probes, compare process ID with stp_pid() which returns PID of consumer.

Sometimes, if target process forking and you need to trace its children, like with -f option in truss/strace, comparing pid() and even ppid() is not enough. In this case you may use DTrace subroutine progenyof() which returns non-zero (treated as true) value if current process is a direct or indirect child of the process which ID was passed as parameter. For example, progenyof(1) will be true for all userspace processes because they are all children to the init.

progenyof() is missing in SystemTap, but it can be simulated with task_*() functions and the following SystemTap script (these functions are explained in Process Management):

function progenyof(pid:long) {
    parent = task_parent(task_current());
    task = pid2task(pid);

    while(parent && task_pid(parent) > 0) {
        if(task == parent)
            return 1;

        parent = task_parent(parent);
    }
}

probe syscall.open { 
    if(progenyof(target())) 
            printdln(" ", pid(), execname(), filename);
}

Assume that 2953 is a process ID of bash interactive session, where we open child bash and call cat there:

root@lktest:~# bash
root@lktest:~# ps
    PID TTY          TIME CMD
    2953 pts/1    00:00:01 bash
    4794 pts/1    00:00:00 bash
    4800 pts/1    00:00:00 ps
root@lktest:~# cat /etc/passwd
[...]

cat is shown by this script even if it is not direct ancestor of bash process that we are tracing:

# stap ./progeny.stp -x 2953 | grep passwd
4801 cat /etc/passwd