Systems Performance 2nd Ed.



BPF Performance Tools book

Recent posts:
Blog index
About
RSS

DTrace Translators

25 Nov 2005

I originally posted this at http://bdgregg.blogspot.com/2005/11/dtrace-translators-while-teaching.html.

While teaching a DTrace class in Sydney, I've been asked about translators. They are quite useful, so I've prepared the following as a quick demo.

This is a DTrace program to trace the time() syscall, print the process, it's parent, it's grand-parent, and so on.

#!/usr/sbin/dtrace -s

/* Declare Translator */

typedef struct ancestory {
        string me;              /* my cmd */
        string p;               /* parent cmd */
        string gp;              /* grand-parent cmd */
        string ggp;             /* great-grand-parent cmd */
        string gggp;            /* great-great-grand-parent cmd */
} ancestory_t;

translator ancestory_t < struct _kthread *T > {

        /* fetch my details */
        me = T->t_procp->p_user.u_comm;

        /* fetch anscestor details if they exist */
        p = T->t_procp->p_parent != NULL ?
            T->t_procp->p_parent->p_user.u_comm :
            "<none>";
        gp = T->t_procp->p_parent != NULL ?
            T->t_procp->p_parent->p_parent != NULL ?
            T->t_procp->p_parent->p_parent->p_user.u_comm :
            "<none>" : "<none>";
        ggp = T->t_procp->p_parent != NULL ?
            T->t_procp->p_parent->p_parent != NULL ?
            T->t_procp->p_parent->p_parent->p_parent != NULL ?
            T->t_procp->p_parent->p_parent->p_parent->p_user.u_comm :
            "<none>" : "<none>" : "<none>";
        gggp = T->t_procp->p_parent != NULL ?
            T->t_procp->p_parent->p_parent != NULL ?
            T->t_procp->p_parent->p_parent->p_parent != NULL ?
            T->t_procp->p_parent->p_parent->p_parent->p_parent != NULL ?
            T->t_procp->p_parent->p_parent->p_parent->p_parent->p_user.u_comm :
            "<none>" : "<none>" : "<none>" : "<none>";
};

inline ancestory_t *ancestors = xlate <ancestory_t *> (curthread);

/* Main Program */

syscall::gtime:entry
{
        printf("%s, %s, %s, %s, %s", ancestors->me,
            ancestors->p, ancestors->gp, ancestors->ggp, ancestors->gggp);
}

The main program at the end is quite consise, it prints the details from "ancestors". The translator has walked the p_parent pointers carefully, returning "<none>" if the pointer is NULL. ("ancestors->me" is unnecessary since we have "execname", I've included it as a simple demonstration).

The output is:

# ./transdemo.d
dtrace: script './transdemo.d' matched 1 probe
CPU     ID                    FUNCTION:NAME
  0   6615                      gtime:entry bash, sh, bash, sshd, sshd
  0   6615                      gtime:entry date, bash, sh, bash, sshd
  0   6615                      gtime:entry bash, sh, bash, sshd, sshd
  0   6615                      gtime:entry nscd, init, sched, <none>, <none>
  0   6615                      gtime:entry nscd, init, sched, <none>, <none>
  0   6615                      gtime:entry nscd, init, sched, <none>, <none>
  0   6615                      gtime:entry nscd, init, sched, <none>, <none>
[...]

Without our careful pointer tests, the NULL parent pointers would have caused DTrace to print errors rather than our "<none>" keywords.

The "Declare Translator" section can be cut-n-pasted into a new .d file in /usr/lib/dtrace (eg, /usr/lib/dtrace/anscestors.d) where it will be automatically imported by every future DTrace script.

Take a look under /usr/lib/dtrace at the existing translator scripts, they are quite fascinating.