2

根据gperftools 文档,可以使用以下任何方法启动分析器:

  1. CPUPROFILE环境变量设置为配置文件信息将保存到的文件名
  2. 执行上述操作,并设置CPUPROFILESIGNAL和发送适当的信号以启动或停止采样。
  3. 直接从您的ProfilerStart(filename)代码调用ProfileStop()

这三种方法也需要libprofiler.so链接。

当我尝试这个时,第三种方法有效,但是当我只是 set 时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()if 设置的文件名。

4

1 回答 1

6

解决这个问题所需的所有信息都分散在 Stack Overflow 中,但将它放在一个地方会很有用,所以现在它是。我已经包含了对解决此问题时发现有用的答案的参考,以防有人正在寻找更多信息。

在 gperftools 中,构造函数CpuProfiler检查CPUPROFILE并调用ProfilerStart(getenv("CPUPROFILE"))它是否已设置(加上或减去一些其他条件)。CpuProfiler声明Aprofiler.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是 volatile,编译器无法对其进行优化,因此链接器需要引入 libprofiler 进行定义。默认情况下,-lprofiler只引入实际出现在程序中的符号,在原始情况下,它们都没有,所以它根本没有链接库,也CpuProfiler()没有被调用。

解决方法是在链接之前将--no-as-needed标志传递给. [2]这会导致它链接库,无论它是否在程序中使用它(ld 手册页似乎建议这应该是默认行为,但它对我来说不是这样)。一旦我们加载了我们需要的东西,就会传递这个标志来关闭它。(顺便说一句,似乎是静态库[3]的等效选项)ldlibprofiler.so--as-needed--whole-archive

使分析适用于原始文件的编译命令:

$ 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
于 2015-11-12T01:06:58.687 回答