1.1 Getting Started

DTrace helps you understand a software system by enabling you to dynamically modify the operating system kernel 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 timestamp or the argument to a function. Probes are like programmable sensors scattered all over your Oracle Linux system in interesting places. If you want to figure out what is 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 do not specify any actions for a probe, DTrace just takes note each time the probe fires.

Every probe in DTrace has two names: a unique integer ID and a human-readable string name. We are 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 utility's -n option to enable a probe using its string name. Type the following command:

# dtrace -n BEGIN

DTrace tells you that a probe was enabled and you will see a line of output indicating the BEGIN probe fired. Once you see this output, dtrace remains paused waiting for other probes to fire. Since no other probes are enabled and BEGIN only fires once, press Ctrl-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. 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.

DTrace requests can be constructed using arbitrary numbers of probes and actions. Let us 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 Ctrl-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
  1      2                             :END 
#

Pressing Ctrl-C to exit dtrace triggers the END probe. dtrace reports this probe firing before exiting. 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:

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   
#

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 Ctrl-C. These changes were the result of the actions you specified for your BEGIN probe in hello.d. Let us 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 4, Actions and Subroutines.

By now, if you are familiar with the C programming language, you have 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 will learn more about these features in subsequent chapters. If you have written a C program before, you will be able to immediately transfer most of your knowledge to building tracing programs in D. If you have 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 us take a step back from language rules and learn more about how DTrace works, and then we will return to learning how to build more interesting D programs.