Paul Hinker's Weblog

pageicon Monday Jun 19, 2006

Back in the saddle

I was fortunate enough to be asked to present the Sun Studio 11 and Multi-threading for Solaris 10 portions of a recent Solaris Developer's Bootcamp day in Huntsville, AL recently and got a chance to get my first look at some really interesting aspects of Solaris 10. Being an assembly coding bit-jockey, I sometimes don't keep up on the latest great going on in the Solaris. Pat Pinchera gave a 2 hour 'deep dive' presentation on Dtrace which was my first real exposure to the capability. My immediate thought was that this would be a fantastic addition to the instrumentation we (the Performance Library Group) are already doing with the interpose library (referenced some of my previous blog entries).

Digging through the copious documentation is daunting but fruitful. My first attempt was, of course, to try and write my own user level provider for a simple Fortran routine. Hmm, not much support for Fortran in the documentation. No mention of that venerable language on the website or in the blogs of the Dtrace guys. This is not to say you can't use dtrace on an application written in Fortran, just that writing your own provider for a Fortran subprogram is a bit of an exercise in manual name-mangling.

The simple example Pat presented consists of a simple dtrace script (named foobar.d)

provider foobar {
probe foo(int,int);
probe bar();
};

and the insertion of a dtrace probe macro into the routine to be probed (named probeable.c)

foo {
   ... 
   if(inp < 10) {
      val1 = inp^3;
   } else {
      val1 = inp^2;
   }
   ...
}

becomes 

#include < sys/sdt.h>
foo {
   ...
   if(inp < 10) {
      DTRACE_PROBE2(foobar,foo,inp,3);
      val1 = inp^3;
   } else {
   ...
}
The probe is compiled into your code in the following manner:

cc -c probeable.c
dtrace -G -32 -s foobar.d probeable.o
cc -o probeable foobar.o probeable.o

The dtrace command options are -G (which generates a .o file from a script and an object file), -32 which indicates a 32-bit application (-64 for a 64-bit application), and -s which indicates foobar.d is a script. The final call to cc links the object files into an executable. Your provided can be accessed using pid (e.g. foobar3324).

Looking at the macros in the /usr/include/sys/sdt.h include file it's easy to see what's going on. The probe macro DTRACE_PROBE2(foobar,foo,inp,3) becomes the function call __dtrace_foobar___foo(inp,3)

A straightforward conversion into Fortran results in the following : % cat probeable.f

subroutine foo(inp)
...
   if (inp < 10) then
      val1 = inp ** 3
   else
      val1 = inp ** 2
   endif

becomes

subroutine foo(inp)
...
   if (inp < 10) then
      call __dtrace_foobar___foo(inp,3)
      val1 = inp ** 3
   else
      val1 = inp ** 2
   endif
The above won't work for a number of reasons. First, Fortran places an underscore '_' at the end of references to subprograms. So, the call to __dtrace_foobar___foo(inp,3) generates an unsatisfied reference to __dtrace_foobar___foo_ in the object file. Dtrace gives you a clue to the problem when you try to compile the dtrace script (foobar.d) into the object file.

% f90 -c probeable.f

% dtrace -G -32 -s foobar.d probeable.o

dtrace: failed to link script foobar: no such probe foo_

There are two ways to handle this issue. First, add an underscore to the probe names in the foobar.d scrip file

% cat foobar.d

provider foobar {
   probe foo_(int, int);
   probe bar_();
};
The second way to handle the naming issue is to use the C pragma which tells the Fortran compiler not to add the underscore to the subprogram reference:
subroutine foo(inp)
C$pragma C(__dtrace_foobar___foo)
...
   if (inp < 10) then
      call __dtrace_foobar___foo(inp,3)
      val1 = inp ** 3
   else
      val1 = inp ** 2
   endif
% dtrace -G -32 -s foobar.d probeable.o
% f90 -o probeable probeable.o foobar.o
While the above compiles, you're likely to get some strange results when you run your example. This is because Fortran passes parameters by reference and C passes parameters by value. Again, there are two ways to handle the issue. First, use the Fortran (de facto standard) %val identifier on the parameters:
subroutine foo(inp)
C$pragma C(__dtrace_foobar___foo)
...
   if (inp < 10) then
      call __dtrace_foobar___foo(%val(inp),%val(3))
      val1 = inp ** 3
   else
      val1 = inp ** 2
   endif
Alternatively, you can create a F90 style interface for the probe function and describe the parameters as pass-by-value parameters. I'll show an example of this in a later entry.

Thanks for sloughing through to the end.

Comments:

Post a Comment:
Comments are closed for this entry.