Getting Started
DTrace helps you understand a software system by enabling you to dynamically modify
the operating system kernel and user processes to record additional data that you
specify at locations of interest, called probes. A probe is a location or
activity to which DTrace can bind a request to perform a set of
actions, like recording a stack trace, a timestamp, or the argument to a
function. Probes are like programmable sensors scattered all over your Solaris system in
interesting places. If you want to figure out what's going on, you use
DTrace to program the appropriate sensors to record the information that is of
interest to you. Then, as each probe fires, DTrace gathers the data
from your probes and reports it back to you. If you don't specify
any actions for a probe, DTrace will just take note of each time
the probe fires.
Every probe in DTrace has two names: a unique integer ID and
a human-readable string name. We're going to start learning DTrace by building some
very simple requests using the probe named BEGIN, which fires once each time you
start a new tracing request. You can use the dtrace(1M) utility's -n
option to enable a probe using its string name. Type the following command:
# dtrace -n BEGIN
After a brief pause, you will see DTrace tell you that one
probe was enabled and you will see a line of output indicating that
the BEGIN probe fired. Once you see this output, dtrace remains paused waiting for
other probes to fire. Since you haven't enabled any other probes and BEGIN
only fires once, press Control-C in your shell to exit dtrace and return
to your shell prompt:
# dtrace -n BEGIN
dtrace: description 'BEGIN' matched 1 probe
CPU ID FUNCTION:NAME
0 1 :BEGIN
^C
#
The output tells you that the probe named BEGIN fired once and both
its name and integer ID, 1, are printed. Notice that by default, the
integer name of the CPU on which this probe fired is displayed.
In this example, the CPU column indicates that the dtrace command was executing on
CPU 0 when the probe fired.
You can construct DTrace requests using arbitrary numbers of probes and actions. Let's
create a simple request using two probes by adding the END probe
to the previous example command. The END probe fires once when tracing is
completed. Type the following command, and then again press Control-C in your shell
after you see the line of output for the BEGIN probe:
# dtrace -n BEGIN -n END
dtrace: description 'BEGIN' matched 1 probe
dtrace: description 'END' matched 1 probe
CPU ID FUNCTION:NAME
0 1 :BEGIN
^C
0 2 :END
#
As you can see, pressing Control-C to exit dtrace triggers the END probe.
dtrace reports this probe firing before exiting.
Now that you understand a little bit about naming and enabling probes, you're
ready to write the DTrace version of everyone's first program, “Hello, World.” In
addition to constructing DTrace experiments on the command line, you can also write
them in text files using the D programming language. In a text editor,
create a new file called hello.d and type in your first D program:
Example 1-1 hello.d: Hello, World from the D Programming Language
BEGIN
{
trace("hello, world");
exit(0);
}
After you have saved your program, you can run it using the
dtrace -s option. Type the following command:
# dtrace -s hello.d
dtrace: script 'hello.d' matched 1 probe
CPU ID FUNCTION:NAME
0 1 :BEGIN hello, world
#
As you can see, dtrace printed the same output as before followed by
the text “hello, world”. Unlike the previous example, you did not have to wait
and press Control-C, either. These changes were the result of the actions you specified
for your BEGIN probe in hello.d. Let's explore the structure of your D
program in more detail in order to understand what happened.
Each D program consists of a series of clauses, each clause describing one
or more probes to enable, and an optional set of actions to perform
when the probe fires. The actions are listed as a series of statements
enclosed in braces { } following the probe name. Each statement ends with a
semicolon (;). Your first statement uses the function trace() to indicate that DTrace should
record the specified argument, the string “hello, world”, when the BEGIN probe fires, and
then print it out. The second statement uses the function exit() to indicate
that DTrace should cease tracing and exit the dtrace command. DTrace provides a set
of useful functions like trace() and exit() for you to call in
your D programs. To call a function, you specify its name followed by
a parenthesized list of arguments. The complete set of D functions is described
in Chapter 10, Actions and Subroutines.
By now, if you're familiar with the C programming language, you've probably realized
from the name and our examples that DTrace's D programming language is very
similar to C. Indeed, D is derived from a large subset of
C combined with a special set of functions and variables to help make
tracing easy. You'll learn more about these features in subsequent chapters. If you've
written a C program before, you will be able to immediately transfer most
of your knowledge to building tracing programs in D. If you've never written
a C program before, learning D is still very easy. You will understand
all of the syntax by the end of this chapter. But first, let's
take a step back from language rules and learn more about how DTrace
works, and then we'll return to learning how to build more interesting D
programs.