callgrind_annotate 默认不显示调用链,需用原始 callgrind.out 文件查 cfn= 行;启用调用追踪无需 --dump-instr=yes 或 --collect-jumps=yes,关键在于保留调试符号(-g)、禁用 strip 和内联优化(-o0),并确保异常实际被抛出和捕获。

callgrind_annotate 怎么看函数调用链
直接看 callgrind_annotate 输出默认不显示“谁调用了谁”,它只按自底向上(self cost)或自顶向下(inclusive cost)排序函数耗时。想查 fun2_throwError 又调用了哪些函数,得靠原始 callgrind 输出文件里的调用图信息,不是靠 annotate 本身。
必须用 --dump-instr=yes 和 --collect-jumps=yes 吗
不需要。查调用关系只要保证启用了调用追踪——这是 Callgrind 默认行为。关键参数是:--callgrind-out-file=callgrind.out.%p(带进程号避免覆盖),以及确保没加 --skip-plt 或 --skip-libraries=yes 这类会过滤掉标准库调用的选项。
-
--dump-instr=yes是为每条汇编指令计数,和调用链无关 -
--collect-jumps=yes用于分析跳转热点,比如间接调用、虚函数分发,一般调试调用链不用开 - 真正影响调用图完整性的,是是否链接了调试符号(
-g编译)、是否 strip 过二进制、以及 C++ 模板/内联函数是否被折叠
怎么从 callgrind.out.xxx 提取 fun2_throwError 的下游调用
用 callgrind_annotate 加 --auto=yes 和 --show=calling 参数:
callgrind_annotate --auto=yes --show=calling callgrind.out.12345 | grep -A 20 "fun2_throwError"
但更可靠的是用 callgrind_control 实时抓或直接读原始文件:
- 原始
callgrind.out.xxx是文本格式,搜索fn=fun2_throwError所在 block,下面紧跟着的cfn=xxx行就是它调用的函数名,calls=后是调用次数 - 如果看到
cfn=(below main),说明调到了栈底或系统函数,通常意味着没符号或被优化掉了 - C++ 异常抛出路径里常见
__cxa_throw、__cxxabiv1::__terminate等,这些不会出现在源码函数名里,但会出现在 cfn 行
为什么看不到 myException::what() 被调用
因为 what() 是在 catch 块里才被调用的,而你的测试代码里注释掉了整个 try-catch 循环。Callgrind 只记录实际执行的调用。哪怕你解除了注释,如果编译时开了 -O2 且 what() 是 inline 函数,它也可能被内联掉,不会单独成一个 fn= 条目。
要确保看到完整调用链,编译时至少加 -g -O0,并确认异常确实被抛出且被捕获——否则 fun2_throwError 之后的栈展开过程(包括 __cxa_rethrow、std::terminate)根本不会触发。











