Dtrace

dtrace is a tool on Mac OS X (and BSD) to log which system call are made by an application. It allows you to get an overview what an application is doing "behind the scenes".


 * DTrace User Guide by Oracle
 * DTrace Quick Start Guide by Oracle
 * Exploring OS X with dtrace by Mac OS X hints
 * Exploring Leopard with DTrace - How to use DTrace for debugging and exploration by MacTech Magazine

SystemTap is an alternative to dtrace for Linux kernels.

Examples
Here are a few example DTrace scripts, taken from the MacTech article

Print Open Files
syscall::open*:entry {   printf("%s %s\n", execname, copyinstr(arg0)); }
 * 1) !dtrace -qs

or

sudo dtrace -n 'syscall::open*:entry { trace(execname); trace(copyinstr(arg0)); }'

(Here, we use trace instead of printf, and don't use the -s flag that silence dtrace a bit, so we now see CPU, probe ID and function name too.)

To print only files for a given process ID (PID), call this script as openfiles.d 1234 (with 1234 the PID of some process):

pid$1::open*:entry {   printf("%s %s\n", execname, copyinstr(arg0)); }
 * 1) !dtrace -qs

To print only files for a process with the given name, call this script as openfiles.d "Safari": syscall::open*:entry / execname == $$1 / {    printf("%s\n", copyinstr(arg0)); }
 * 1) !/usr/sbin/dtrace -qs

To print all system calls (including file I/O), use dtruss:

dtruss myapplication

To print all opened files, use `iosnoop` or `opensnoop`:

opensnoop -n myapplication

Time Spend in Each Function
pid$1:::entry {    self->ts[probefunc] = timestamp; } pid$1:::return /self->ts[probefunc]/ {    @func_time[probefunc] = sum(timestamp - self->ts[probefunc]); self->ts[probefunc] = 0; }
 * 1) !/usr/sbin/dtrace -s

This script stores the timestamp in an array called ts for each function, and sums the total time spend. The self-> construct makes sure that each thread uses a different ts variable.

In order to print a histogram of the times, use the quantize aggregation function:

pid$1:::entry {    self->start = timestamp; } pid$1:::return {    @ = quantize(timestamp - self->start); }
 * 1) !/usr/sbin/dtrace -s

Count the Number of Function Calls
sudo dtrace -q -n 'syscall:::entry / execname == "thunderbird" / { @count_table[probefunc] = count; }'

Count the Number of Context Switches
On Solaris: sudo dtrace -n 'sysinfo:::pswitch { @[execname] = count; }'

On Mac OS X, I had to experiment a bit to find the correct function call: sudo dtrace -n 'fbt::*switch:entry { @[probefunc,execname] = count; }'

Print a Stack Trace
syscall::open:entry /pid == $1/ {    self->path = copyinstr(arg0); } syscall::open:return /self->path != NULL && arg1 == -1/ {    printf("open for ’%s’ failed", self->path); ustack; }
 * 1) !/usr/sbin/dtrace -s

General Syntax
DTrace rules are written in the D language. The general syntax of a rule is: probe descriptions / predicate / {   action statements }

The probe description is either a keyword like BEGIN or a 4-tuple written as provider:module:function:name</tt>. In here:


 * provider:Specifies the layer that is instrumented. E.g. "syscall"
 * module:Describes the module that is instrumented. E.g. "libsystem_c.dylib"
 * function:Describes the function that is instrumented. e.g. "open" or "open*"
 * name:Typically represents the location in the function, e.g. "entry" or "return"

Providers
Here are some interesting providers:

To display all possible providers, run:

dtrace -l | less

The less is there for a reason: my Mac OS X system has just over 270000 publishers.

Script Parameters
For scripts, it is recommended to use argument substitution for the PID:

pid$1:::entry {}
 * 1) !/usr/sbin/dtrace -s

Predicates
Typical predicates are:

Actions
Typical actions are:

Typical aggregate functions are:

Variables
Predefined variables you can access are: