views:

395

answers:

7

Say I have function that is called a LOT from many different places. So I would like to find out who calls this functions the most. For example, top 5 callers or who ever calls this function more than N times.

I am using AS3 Linux, gcc 3.4.

For now I just put a breakpoint and then stop there after every 300 times, thus brute-forcing it...

Does anyone know of tools that can help me?

Thanks

+2  A: 

Profiling helps.

Georg
I am usbng a profile oprofile, but it doesnt give me this level of information
vehomzzz
There are many that do. Danadam has suggested one in his answer.
Georg
+18  A: 

Compile with -pg option, run the program for a while and then use gprof. Running a program compiled with -pg option will generate gmon.out file with execution profile. gprof can read this file and present it in readable form.

danadam
And gprof2dot (http://code.google.com/p/jrfonseca/wiki/Gprof2Dot) can make that output into a nice graph ;-)
ChristopheD
+1  A: 

Since you mentioned oprofile in another comment, I'll say that oprofile supports generating callgraphs on profiled programs.

See http://oprofile.sourceforge.net/doc/opreport.html#opreport-callgraph for more details.

It's worth noting this is definitely not as clear as the callers profile you may get from gprof or another profiler, as the numbers it reports is the number of times oprofile collected a sample in which X is the caller for a given function, not the number of times X called a given function. But this should be sufficient to figure out the top callers of a given function.

Falaina
A: 

In addition to the aforementioned gprof profiler, you may also try the gcov code-coverage tool. Information on compiling for and using both should be included in the gcc manual.

Derrick Turk
+1  A: 

A somewhat cumbersome method, but not requiring additional tools:

#define COUNTED_CALL( fn, ...) do{ \
    fprintf( call_log_fp, "%s->%s\n", __FUNCTION__, #fn ) ; \
    (fn)(__VA_ARGS__) ; \
}while(0) ;

Then all calls written like:

int input_available = COUNTED_CALL( scanf, "%s", &instring ) ;

will be logged to the file associated to call_log_fp (a global FILE* which you must have initialised). The log for the above would look like:

main->scanf

You can then process that log file to extract the data you need. You could even write your own code to do the instrumentation which would make it perhaps less cumbersome.

Might be a bit ambiguous for C++ class member functions though. I am not sure if there is a __CLASS__ macro.

Clifford
You should probably use `#fn` to stringize the function name for `fprintf()` - not sure what kind of warnings will be caused if you don't.
Chris Lutz
Thanks, edited.
Clifford
+2  A: 

I wrote call logging example just for fun. A macro change the function call with an instrumented one.

include <stdio.h>. 

int funcA( int a, int b ){ return a+b; }

// instrumentation

void call_log(const char*file,const char*function,const int line,const char*args){
  printf("file:%s line: %i function: %s args: %s\n",file,line,function,args);
}

#define funcA(...) \ 
  (call_log(__FILE__, __FUNCTION__, __LINE__, "" #__VA_ARGS__), funcA(__VA_ARGS__)). 

// testing

void funcB(void){
  funcA(7,8);
}


int main(void){
  int x = funcA(1,2)+

          funcA(3,4);

  printf( "x: %i (==10)\n", x );

  funcA(5,6);

  funcB();
}

Output:

file:main.c line: 22 function: main args: 1,2
file:main.c line: 24 function: main args: 3,4
x: 10 (==10)
file:main.c line: 28 function: main args: 5,6
file:main.c line: 17 function: funcB args: 7,8
sambowry
Great!!!! I might implement something like that
vehomzzz
A: 

Once again, stack sampling to the rescue! Just take a bunch of "stackshots", as many as you like. Discard any samples where your function (call it F) is not somewhere on the stack. (If you're discarding most of them, then F is not a performance problem.)

On each remaining sample, locate the call to F, and see what function (call it G) that call is in. If F is recursive (it appears more than once on the sample) only use the topmost call.

Rank your Gs by how many stacks each one appears in.

If you don't want to do this by hand, you could make a simple tool or script. You don't need a zillion samples. 20 or so will give you reasonably good information.

By the way, if what you're really trying to do is find performance problems, you don't actually need to do all that discarding and ranking. In fact - don't discard the exact locations of the call instruction inside each G. Those can actually tell you a good bit more than just the fact that they were somewhere inside G.

P.S. This is all based on the assumption that when you say "calls it the most" you mean "spends the most wall clock time in calling it", not "calls it the greatest number of times". If you are interested in performance, fraction of wall clock time is more useful than invocation count.

Mike Dunlavey