根据gperftools documentation,可以使用以下任何方法启动探查器:
CPUPROFILE
环境变量设置为文件名,将个人资料信息保存到CPUPROFILESIGNAL
并发送相应的信号以开始或停止采样。ProfilerStart(filename)
和ProfileStop()
这三种方法都要求libprofiler.so
也要链接。
当我尝试这个时,第三种方法有效,但当我只设置CPUPROFILE
时,没有生成分析信息。
不起作用:
$ cat foo.c
#include <stdio.h>
int main(void) {
printf("Hello, world!\n");
}
$ gcc foo.c -std=c99 -lprofiler -g && CPUPROFILE=foo.prof ./a.out
Hello, world!
$ ls foo.prof
ls: cannot access foo.prof: No such file or directory
工作:
$ cat bar.c
#include <stdio.h>
#include <gperftools/profiler.h>
int main(void) {
ProfilerStart("bogus_filename");
printf("Hello, world!\n");
ProfilerStop();
}
$ gcc -std=c99 bar.c -lprofiler -g && CPUPROFILE=foo.prof ./a.out
Hello, world!
PROFILE: interrupts/evictions/bytes = 0/0/64
$ ls foo.prof
foo.prof
$ ls bogus_filename
ls: cannot access bogus_filename: No such file or directory
$ ./a.out
Hello, world!
PROFILE: interrupts/evictions/bytes = 0/0/64
$ ls bogus_filename
bogus_filename
请注意,正在读取CPUPROFILE
,因为它的值会覆盖传递给ProfileStart()
的文件名(如果已设置)。
答案 0 :(得分:5)
解决这个问题所需的所有信息都分散在Stack Overflow中,但将它放在一个地方会很有用,所以现在就是这样。我已经在解决这个问题时提到了我发现有用的答案,以防有人在寻找更多信息。
在gperftools中,CpuProfiler
的构造函数会检查CPUPROFILE
并调用ProfilerStart(getenv("CPUPROFILE"))
(如果已设置)(加上或减去其他一些条件)。在CpuProfiler
中声明profiler.cc
以确保调用该函数。 [1]当然,只有libprofiler.so
被链接才会发生这种情况。
以下代码揭示了问题:
$ cat baz.c
#include <stdlib.h>
#include <stdio.h>
#include <gperftools/profiler.h>
int main(void) {
volatile int i = 0;
if (i) ProfilerStop();
printf("Hello, world!\n");
return 0;
}
$ gcc -std=c99 baz.c -lprofiler -g && CPUPROFILE=foo.prof ./a.out
Hello, world!
PROFILE: interrupts/evictions/bytes = 0/0/64
实际上永远不能调用 ProfileStop()
,但由于i
是易失性的,编译器无法对其进行优化,因此链接器需要将libprofiler引入定义。默认情况下,-lprofiler
只会引入程序中实际出现的符号,原始情况下这些符号都不是,所以它根本没有链接库,CpuProfiler()
从来没有被叫过。
修复方法是在链接--no-as-needed
之前将ld
标记传递给libprofiler.so
。 [2]这导致它链接库,无论它是否在程序中使用它(ld手册页似乎表明这应该是默认行为,但它不是那样工作的为了我)。然后传递--as-needed
标志,一旦我们加载了我们需要的内容,就将其关闭。 (另外,--whole-archive
似乎是静态库[3])的等效选项
用于使分析工作原始文件的编译命令:
$ gcc -std=c99 foo.c -Wl,--no-as-needed,-lprofiler,--as-needed -g && CPUPROFILE=foo.prof ./a.out
Hello, world!
PROFILE: interrupts/evictions/bytes = 0/0/64