我已经设置了CPUPROFILE环境变量和链接的-lprofiler。为什么gperftools没有启动分析器?

时间:2015-11-12 01:06:59

标签: c++ ld gperftools

根据gperftools documentation,可以使用以下任何方法启动探查器:

  1. CPUPROFILE环境变量设置为文件名,将个人资料信息保存到
  2. 执行上述操作,并设置CPUPROFILESIGNAL并发送相应的信号以开始或停止采样。
  3. 直接从您的代码中调用ProfilerStart(filename)ProfileStop()
  4. 这三种方法都要求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()的文件名(如果已设置)。

1 个答案:

答案 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