Putting developer-defined DTrace probe points in an application

Well, it's been a while since blogging - time to post another example. As part of the Solaris 10 developer BOF at Usenix a couple of weeks ago, Liane asked me to put together a quick DTrace demo, so I cons'ed up a quick example of how to put static probes into an application. This technique is simple and can avoid the need for debug flags, conditional logging, etc in the application.

In order to have something to work with, I wrote a quick version of wc that I instrumented with two dtrace probe points.  These two probe points are defined in a file called simple_probes.d:

provider simple {
probe saw__word(int);
probe saw__line(int);
};

Note that dtrace treats double underscores specially in such definitions; they're converted to dash "-" characters in the finished probe names. Here's the source for the wc program, which I called simple.c:


#include <stdio.h>
#include <sys/sdt.h>

/\*
 \* simple example of defining sdt probes in a trivial program
 \* Sdt probes can often completely replace debug levels, optional
 \* log files, etc, in daemons... you can leverage the power of dtrace
 \* to make your server/application more readily debuggable.
 \*/

int
main(int argc, char \*argv[])
{
        int i;
        int characters, lines, words;
        characters = lines = words = 0;


        while (1) {

                if ((i = getchar()) == EOF) {
                        /\*
                         \* here we specify the name of the module,
                         \* the name of the probe (modulo mapping
                         \* '__' to '-') and pass in the parameter to be
                         \* traced which in this case is the number of
                         \* lines seen so far.
                         \*/
                        DTRACE_PROBE1(simple, saw__line, lines);
                        break;
                }

                characters++;

                if (i == '\\n') {
                        lines++;
                        DTRACE_PROBE1(simple, saw__line, lines);
                        continue;
                }

                if (isblank(i)) /\* eating white space \*/
                        continue;

                words++; /\* in a word now \*/

                while (1) {

                        if ((i = getchar()) == EOF) {
                                DTRACE_PROBE1(simple, saw__word, words);
                                break;
                        }

                        characters++;

                        if (i == '\\n') { /\* EOL? ends word implicitly \*/
                                DTRACE_PROBE1(simple, saw__word, words);
                                lines++;
                                DTRACE_PROBE1(simple, saw__line, lines);
                                break;
                        }

                        if (isblank(i)) { /\* white space ends words too \*/
                                DTRACE_PROBE1(simple, saw__word, words);
                                break;
                        }
                }
        }

        printf("%8d %8d %8d\\n", lines, words, characters);

        exit(0);
}

Now we need a makefile to process the code and build the executable:

CC=gcc
CFLAGS=-m64
DTRACE=dtrace

simple: simple_probes.o simple.o
$(CC) -o simple -m64 simple_probes.o simple.o

simple_probes.o: simple.o simple_probes.d
$(DTRACE) -G -64 -s simple_probes.d simple.o

Note that we use dtrace to build a .o file that defines our new probes,
and we link this into our (64 bit amd) application:

barts@cyber:/home/barts/demos 144% /usr/ccs/bin/make
gcc -m64  -c  simple.c
dtrace -G -64 -s simple_probes.d simple.o
gcc -o simple -m64 simple_probes.o simple.o
barts@cyber:/home/barts/demos 145%

We can now take a look at the probes we've added into our program with
dtrace:

# dtrace -P simple'$target' -c ./simple -l
   ID   PROVIDER            MODULE                          FUNCTION NAME
48630 simple19946            simple                              main saw-line
48631 simple19946            simple                              main saw-word
#

And we can now demonstrate the probes firing as follows.  First, running normally:

# echo "Hello World" | ./simple
       1        2       12
#

and now running with probes enabled from dtrace:

# echo "Hello World" | dtrace -P simple'$target' -c ./simple

dtrace: description 'simple$target' matched 2 probes
       1        2       12
CPU     ID                    FUNCTION:NAME
  0  48631                    main:saw-word
  0  48631                    main:saw-word
  0  48630                    main:saw-line
  0  48630                    main:saw-line
dtrace: pid 19917 has exited

Simple enough really, and this works with Forte, gcc, and Studio compilers for all Solaris platforms...

Hmmm... perhaps I should change the nscd to use this rather than generating log
files....



Comments:

antony

Posted by guest on February 06, 2008 at 05:21 PM PST #

Note that since Bart made this great post, the USDT methodology has been updated slightly as documented here:

http://blogs.sun.com/ahl/entry/user_land_tracing_gets_better

Posted by Adam Leventhal on October 13, 2008 at 02:43 AM PDT #

Post a Comment:
  • HTML Syntax: NOT allowed
About

An engineer's viewpoint on Solaris...

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today