The view from the Engine Room
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=gccNote that we use dtrace to build a .o file that defines our new probes,
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
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....
Posted at 07:00PM Apr 27, 2005 by barts in General | Comments[2]
Wednesday Apr 27, 2005