Adding dtrace probes to user code

The process of adding dtrace probes to userland code is described in the dynamic tracing guide. However, there's no better way of learning how to do it, than trying it out on a snippet of code.

Here's a short bit of code that calls a function twice, each time with different parameters. The plan is to insert a probe that can report the passed parameters.

#include <stdio.h>

void func(int a, int b)
{
  printf("a=%i, b=%i\\n",a,b);
}

void main()
{
  func(1,2);
  func(2,3);
}

The first change is to add the <sys/sdt.h> header file. This file has definitions for the DTRACE_PROBE<N> macro. N represents the number of parameters that are to be reported by the probe. In this case we are going to pass two parameters (a and b) to the probe. As well as the parameters that are to be passed to the dtrace probe, the macro takes the name to be used tof the application provide (in this case the name will be myapp) and the name of the probe (in this case func_call). The modified source code looks as follows:

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

void func(int a, int b)
{
  DTRACE_PROBE2(myapp,func_call,a,b);
  printf("a=%i, b=%i\\n",a,b);
}

void main()
{
  func(1,2);
  func(2,3);
}

The next step is to write a probe description file which dtrace will use to produce the probes. A full file would describe the stability of the probe in more detail, but a lightweight file just describes the probes defined by the provider application:

provider myapp
{
  probe func_call(int, int);
};

Having completed this, it's necessary to compile and link the application. Initially each source file needs to be compiled, and then before the application is linked, dtrace needs to be invoked to modify the object files, removing the calls to the probes, but leaving space for them to be reinserted. dtrace also needs to compile the probe description file into an object file. Finally the modified object files and the probe description file can be linked to produce the executable. As follows:

$ cc -c app.c
$ dtrace -G -32 -s probes.d app.o
$ cc probes.o app.o

The resulting code in the application looks like:

func()
        113a0:  9d e3 bf a0  save       %sp, -96, %sp
        113a4:  f0 27 a0 44  st         %i0, [%fp + 68]
        113a8:  f2 27 a0 48  st         %i1, [%fp + 72]
        113ac:  d0 07 a0 44  ld         [%fp + 68], %o0
        113b0:  01 00 00 00  nop
        113b4:  d2 07 a0 48  ld         [%fp + 72], %o1
        113b8:  11 00 00 45  sethi      %hi(0x11400), %o0
        113bc:  90 12 22 60  bset       608, %o0        ! 0x11660
        113c0:  d2 07 a0 44  ld         [%fp + 68], %o1
        113c4:  40 00 42 c7  call       printf  ! 0x21ee0
        113c8:  d4 07 a0 48  ld         [%fp + 72], %o2
        113cc:  81 c7 e0 08  ret
        113d0:  81 e8 00 00  restore

The nop at 0x113b0 is there for dtrace to dynamically patch with a call instruction that will enable the dtrace probe.

Finally, the following is an example of using the new probe:

$ more script.d
myapp$target:::func_call
{
  @[arg0,arg1]=count();
}
$ dtrace -s script.d -c a.out
dtrace: script 'script.d' matched 1 probe
a=1, b=2
a=2, b=3
dtrace: pid 22355 has exited

                1                2                1
                2                3                1

The script just aggregates the parameters used in the function call. When the application terminates the aggregation is printed out - showing the expected result of two calls to the routine each call with different parameters.

Comments:

Also see what I wrote on this back in 2005 :)

http://blogs.sun.com/tpenta/entry/dtrace_using_placing_sdt_probes

There are some flash demos in there too.

Also, if you check out the DTrace community you'll see the diffs of some code I'm doing up in the bourne shell to add DTrace probes to it.

Alan.

Posted by Alan Hargreaves on November 20, 2007 at 05:35 AM PST #

great post. But just so you know, this actually uses the deprecated method for creating a usdt provider -- yes, I know we need to update the documentation :-)

Posted by Adam Leventhal on November 21, 2007 at 12:25 AM PST #

Well Adam. You might want to get on that documentation then because otherwise folks might actually use this very nice post here as a starting point to writing a provider.

Posted by Ian Koenig on November 27, 2007 at 05:16 AM PST #

I think Adam describes the preferred approach here:
http://blogs.sun.com/ahl/entry/user_land_tracing_gets_better

It's quite neat in that it solves two problems, the first is that C++ assumes C++ linkage - so the probe names get mangled. The second is that it allows the code to compile on systems that are bereft of the benefit of dtrace.

Basically it uses the .d file to generate a header file that gets included into the source. The header file has the appropriate extern 'C' so that the names don't get mangled. It also has an ifdef _DTRACE_VERSION which allows the code to compile on systems without dtrace.

I'll write the preferred approach up shortly.

Posted by Darryl Gove on November 27, 2007 at 05:33 AM PST #

Post a Comment:
Comments are closed for this entry.
About

Darryl Gove is a senior engineer in the Solaris Studio team, working on optimising applications and benchmarks for current and future processors. He is also the author of the books:
Multicore Application Programming
Solaris Application Programming
The Developer's Edge

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
5
6
8
9
10
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today
Bookmarks
The Developer's Edge
Solaris Application Programming
Publications
Webcasts
Presentations
OpenSPARC Book
Multicore Application Programming
Docs