我已经设置了 CPUPROFILE 环境变量和链接的 -lprofiler。为什么 gperftools 不启动探查器?
I've set the CPUPROFILE environment variable and linked -lprofiler. Why is gperftools not starting the profiler?
根据 gperftools 文档,可以使用以下任一方法启动探查器:
- 将
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()
的文件名(如果已设置(。
解决此问题所需的所有信息都分散在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()
从未被调用。
解决方法是在链接libprofiler.so
之前将 --no-as-needed
标志传递给ld
。 [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
- 为什么"do while"循环不断退出,即使条件计算结果为 false?
- 为什么在全局范围内使用"extern int a"似乎不行?
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 为什么会发生堆损坏
- 为什么使用 "this" 指针调用派生成员函数?
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 为什么比较运算符如此快速
- 为什么 Serial.println(<char[]>);返回随机字符?
- 为什么这个运算符<重载函数对 STL 算法不可见?
- 为什么不;名字在地图上是按顺序排列的吗
- 我的字符计数代码计算错误.为什么
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 为什么野牛仍在使用"int yylex(void)",却找不到"int yylex(YYS
- 为什么 std::unique 不调用 std::sort?
- 既然存在危险,为什么项目要使用-I include开关
- 我已经设置了 CPUPROFILE 环境变量和链接的 -lprofiler。为什么 gperftools 不启动探查器?