callgrind默认不过滤标准库调用,导致90%输出为libc++/libstdc++函数;应使用--skip-plt=yes、--fn-skip=std::*等参数过滤,编译需加-g -o0 -fno-omit-frame-pointer,并优先分析“self”列。

Callgrind输出里90%都是libc++/libstdc++函数名
这不是你的代码有问题,是Callgrind默认没过滤标准库调用,std::string::append、malloc、operator new这些全被展开进来了。真实热点反而被埋在几百行系统调用下面。
- 加
--skip-plt=yes跳过PLT(Procedure Linkage Table)符号,能直接屏蔽掉大部分malloc、memcpy等glibc导出函数 - 用
--fn-skip=std::*或--fn-skip=__*匹配跳过C++标准库和编译器内部函数(注意空格) - 如果只关心自己写的模块,用
--fn-only=MyNamespace::*或--fn-only=main限定范围,其他一概不统计
callgrind_annotate看报告时找不到自己的函数
常见原因是编译时没带-g或用了-O2以上优化。Callgrind依赖调试符号定位源码行,优化会把函数内联、重排逻辑,导致callgrind_annotate显示的函数名是inlined from ...或者干脆变成???。
- 重新编译必须加
-g -O0,-fno-omit-frame-pointer也建议加上 -
callgrind_annotate默认按“总指令数”排序,但你真正要盯的是“自身指令数(self)”,加--auto=yes让它自动识别调用栈根节点 - 如果报告里只有地址没有函数名,运行前先确认
readelf -S ./your_program | grep debug有.debug_*段
用--dump-instr=yes后报告爆炸式增长
--dump-instr=yes会让Callgrind记录每条CPU指令的执行次数,数据量比默认大10–100倍,callgrind_annotate解析慢、内存吃紧,还容易让关键路径被稀释。
- 日常性能热点分析完全不需要它,去掉这个参数
- 真要查某段汇编行为,先用
--fn-only=YourHotFunction缩小范围,再加--dump-instr=yes - 生成的
callgrind.out.*文件默认不压缩,大项目建议加--compress-strings=yes
第三方库函数占高但又不能跳过
比如你用到了boost::filesystem或某个加密库,它们确实耗时,但你既不想跳过(否则看不到瓶颈在哪),又不想被淹没(全是库函数名)。这时候得靠后处理。
- 用
callgrind_annotate --inclusive=yes打开“包含子调用”的统计,这样你能看到my_save_to_disk()这一行就占了65%,点进去才看到底下是boost::filesystem::copy_file+write() - 配合
grep -v "std::\|__\|libc\|libpthread"临时过滤,但别删原始callgrind.out.*文件 - 真正要优化时,优先看“self”列数值大的函数——那是你代码里真正花时间的地方,不是它调用别人的开销
Callgrind本身不区分“谁写的代码”,它只忠实地记录指令流。你看到满屏库函数,往往说明你还没把关注点从“调用了什么”切换到“为什么调用这么多”。











