Tuesday Nov 27, 2007

Adding dtrace probes to user code (part 2)

Adam Leventhal pointed out in the comments to my post on adding dtrace userland probes that there is an improved approach to adding userland dtrace probes. He describes this approach on his blog.

The approach solves two problems. First, that C++ name mangling makes it hard to add dtrace probes for that language. Second, that code with dtrace probes inserted in it will not compile on systems that do not have the necessary dtrace support.

So going back to the example code, I'll try to show the problem and the solution. Here's app.cc:

#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);
}

When compiled with the C compiler the following symbols get defined:

$ cc -c app.cc
$ nm app.o
app.o:

[Index]   Value      Size    Type  Bind  Other Shndx   Name
...
[10]    |         0|       0|FUNC |GLOB |0    |UNDEF  |__dtrace_myapp___func_call
...

When compiled with the C++ compiler the following happens:

$ CC -c app.cc
$ nm app.o
app.o:

[Index]   Value      Size    Type  Bind  Other Shndx   Name
...
[7]     |         0|       0|FUNC |GLOB |0    |UNDEF  |__1cbA__dtrace_myapp___func_call6FLL_v_
...

Because the call to the dtrace probe is not declared as being extern 'C' the compiler mangles the C++ function name.

The new approach that Adam describes involves dtrace preprocessing the probe description file to generate a header file, and the including the header file in the source code. The big advantage of having the header file is that it's now possible to declare the dtrace probes to have extern 'C' linkage, and avoid the name mangling issue. The syntax for preprocessing the probe description file is:

$ dtrace -h -s probes.d

This generates the following header file:

/\*
 \* Generated by dtrace(1M).
 \*/

#ifndef _PROBES_H
  #define _PROBES_H

  #include <unistd.h>

  #ifdef  __cplusplus
    extern "C" {
  #endif

  #if _DTRACE_VERSION
    #define MYAPP_FUNC_CALL(arg0, arg1)  __dtrace_myapp___func_call(arg0, arg1)
    #define MYAPP_FUNC_CALL_ENABLED()    __dtraceenabled_myapp___func_call()
    extern void __dtrace_myapp___func_call(int, int);
    extern int __dtraceenabled_myapp___func_call(void);
  #else
    #define MYAPP_FUNC_CALL(arg0, arg1)
    #define MYAPP_FUNC_CALL_ENABLED() (0)
  #endif

  #ifdef  __cplusplus
    }
  #endif

#endif  /\* _PROBES_H \*/

The other advantage is that the header file can protect the definitions of the dtrace probes with #if _DTRACE_VERSION; which enables the same source to be compiled on systems which do not support dtrace.

The source code needs to be modified to support this syntax:

#include &kt;stdio.h>
#include "probes.h"

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

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

The rest of the process is the same as before.

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
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