有没有办法找出C函数的顶级调用者?

时间:2009-09-24 20:31:12

标签: c++ c optimization code-analysis

假设我有来自许多不同地方的称为LOT的功能。所以我想找出谁最能称这个功能。例如,前5个呼叫者或曾经调用此功能超过N次。

我使用的是AS3 Linux,gcc 3.4。

现在我只是设置一个断点,然后每隔300次就停在那里,这样就可以强制它......

有谁知道可以帮助我的工具?

由于

7 个答案:

答案 0 :(得分:18)

使用-pg选项编译,运行程序一段时间,然后使用gprof。运行使用-pg选项编译的程序将生成带有执行配置文件的gmon.out文件。 gprof可以读取此文件并以可读的形式呈现。

答案 1 :(得分:2)

分析有帮助。

答案 2 :(得分:2)

我写了一个呼叫记录示例只是为了好玩。宏用函数调用函数调用函数调用。

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

输出:

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

答案 3 :(得分:1)

由于你在另一条评论中提到了oprofile,我会说oprofile支持在配置文件程序中生成调用图。

有关详细信息,请参阅http://oprofile.sourceforge.net/doc/opreport.html#opreport-callgraph

值得注意的是,这肯定不如您从gprof或其他探查器获得的调用者配置文件那样清晰,因为它报告的数字是oprofile收集样本的次数,其中X是给定函数的调用者,不是X称为给定函数的次数。但这应该足以找出给定函数的顶级调用者。

答案 4 :(得分:1)

一种有点麻烦的方法,但不需要额外的工具:

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

然后所有的电话都写成:

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

将被记录到与call_log_fp相关联的文件中(您必须初始化的全局FILE *)。上面的日志如下所示:

main->scanf

然后,您可以处理该日志文件以提取所需的数据。您甚至可以编写自己的代码来执行可能不那么麻烦的检测。

虽然可能对C ++类成员函数有点模棱两可。我不确定是否有__CLASS__宏。

答案 5 :(得分:0)

除了前面提到的gprof profiler之外,您还可以尝试使用gcov代码覆盖率工具。有关编译和使用两者的信息应包含在gcc手册中。

答案 6 :(得分:0)

再次stack sampling to the rescue!只需要一堆“stackshots”,尽可能多。丢弃任何样本,其中您的函数(称为F)不在堆栈的某个位置。 (如果丢弃大部分内容,那么F不是性能问题。)

在每个剩余的样本上,找到对F的调用,并查看该调用所在的函数(称之为G)。如果F是递归的(它在样本上出现多次),则只使用最顶层的调用。

根据每个人出现的筹码数量对你的Gs进行排名。

如果您不想手动执行此操作,则可以创建一个简单的工具或脚本。您不需要多个样本。 20左右会给你相当不错的信息。

顺便说一句,如果您真正想要做的是发现性能问题,那么您实际上并不需要做所有丢弃和排名。实际上 - 不要丢弃每个G内部的调用指令的确切位置。这些实际上可以告诉你的不仅仅是它们位于G内部的事实。

P.S。这完全基于这样的假设:当你说“最多叫它”时你的意思是“花费最多的挂钟时间来调用它”,而不是“把它称为最多次”。如果您对性能感兴趣,挂钟时间的一小部分比调用计数更有用。