Go to main content

Oracle® Solaris 11.3 DTrace (Dynamic Tracing) Guide

Exit Print View

Updated: July 2018
 
 

Adding Probes to an Application

DTrace probes for libraries and executables are defined in an ELF section in the corresponding application binary. This section describes how to define your probes, add them to your application source code, and augment your application's build process to include the DTrace probe definitions.

Defining Providers and Probes

You define DTrace probes in a .d source file which is then used when compiling and linking your application. First, select an appropriate name for your user application provider. The provider name you choose will be appended with the process identifier for each process that is executing your application code. For example, if you chose the provider name myserv for a web server that was executing as process ID 1203, the DTrace provider name corresponding to this process would be myserv1203. In your .d source file, add a provider definition similar to the following example:

provider myserv {
        ...
};

Next, add a definition for each probe and the corresponding arguments. The following example defines the two probes: probe_query_receive and probe query__respond. The first probe has two arguments, both of type string, and the second probe has no arguments. For more information about the probes in this example, see Choosing the Probe Points. The D compiler converts two consecutive underscores (__) in any probe name to a hyphen (-).

provider myserv {
        probe query__receive(string, string);
        probe query__respond();
};

You should add stability attributes to your provider definition so that consumers of your probes understand the likelihood of change in future versions of your application. For more information about the DTrace stability attributes, see DTrace Stability Mechanisms. Stability attributes are defined as shown in the following example:

Example 30  Using Statically Defined Application Probes With myserv.d
#pragma D attributes Evolving/Evolving/Common provider myserv provider
#pragma D attributes Private/Private/Unknown provider myserv module
#pragma D attributes Private/Private/Unknown provider myserv function
#pragma D attributes Evolving/Evolving/Common provider myserv name
#pragma D attributes Evolving/Evolving/Common provider myserv args

provider myserv {
        probe query__receive(string, string);
        probe query__respond();
};

Adding Probes to Application Code

After you define your probes in a .d file, you then augment your source code to indicate the locations that should trigger your probes. For example:

void
main_look(void)
{
        ...
        query = wait_for_new_query();
        process_query(query)
        ...
}

To add a probe site, add a reference to the DTRACE_PROBE() macro defined in <sys/sdt.h> as shown in the following example:

...
void
main_look(void)
{
        ...
        query = wait_for_new_query();
        DTRACE_PROBE2(myserv, query__receive, query->clientname, query->msg);
        process_query(query)
        ...
}

The suffix 2 in the macro name DTRACE_PROBE2 refers to the number of arguments that are passed to the probe. The first two arguments to the probe macro are the provider name and probe name and must correspond to your D provider and probe definitions. The remaining macro arguments are the arguments assigned to the DTrace arg0..9 variables (or the args[] array) when the probes fire. The application source code can contain multiple references to the same provider and probe name. If multiple references to the same probe are present in the source code, any of the macro references will cause the probe to fire.

Building Applications With Probes

You must augment the build process for your application to include the DTrace provider and probe definitions. A typical build process takes each source file and compiles it to create a corresponding object file. The compiled object files are then linked together to create the finished application binary, as shown in the following example:

cc -c src1.c
cc -c src2.c
...
cc -o myserv src1.o src2.o ...

To include DTrace probe definitions in your application, add appropriate Makefile rules to your build process to execute the dtrace command as shown in the following example:

cc -c src1.c
cc -c src2.c
...
dtrace -G -32 -s myserv.d src1.o src2.o ...
cc -o myserv myserv.o src1.o src2.o ...

The preceding dtrace command post-processes the object files generated by the preceding compiler commands and generates the object file myserv.o from myserv.d and the other object files. The dtrace -G option is used to link provider and probe definitions with a user application. The –32 option is used to build 32-bit application binaries. The –64 option is used to build 64-bit application binaries.

If a user-land object contains a very large number of statically-defined probes, then there may be a measurable delay when the object is first executed or loaded. In this case, you can use the lazyload option when building the object. For example:

# dtrace -x lazyload -G ...

Objects built in this way do not advertise their probes to the kernel until required to do so.

# dtrace -l | fgrep myserv

The preceding command might not show any results until after running. For example:

# dtrace -n myserv1203:::query-receive ...

You can also type the following command:

# dtrace -l -n myserv1203:::