Callgrind默认全程采集,不支持运行时手动开关;需配合--instr-atstart=no和callgrind_control -i on/off实现按需采集,否则无法精准控制分析范围。

Callgrind 默认全程采集,不支持运行时手动开关
Callgrind 启动后默认从程序入口开始记录所有函数调用和指令计数,直到进程退出才写入 callgrind.out.PID 文件。它本身没有类似 callgrind_control 的“暂停/恢复”命令,也没有 API 或信号机制让你在代码里调用 start/stop —— 这点和 perf 或 gperftools 完全不同。
想只分析某段逻辑?用 --instr-atstart=no + callgrind_control
必须配合两个动作才能实现“按需采集”:
-
--instr-atstart=no:启动时不采集,避免污染前导初始化逻辑(如库加载、全局对象构造) - 在目标代码段前后插入
callgrind_control -i on和callgrind_control -i off
例如,在 C++ 中嵌入系统调用:
system("callgrind_control -i on");
// 你真正想分析的业务逻辑,比如 query.execute()
system("callgrind_control -i off");
注意:callgrind_control 必须在同个终端或能访问到目标进程的环境中执行;若程序是 daemon 或被 nohup 启动,需确保 callgrind_control 能找到对应 PID(可通过 callgrind_control -s 查看当前受控进程)。
常见错误:callgrind_control 找不到进程或无响应
原因通常是以下之一:
- 没加
--instr-atstart=no,Callgrind 已自行开始采集,callgrind_control失效 - 目标进程 UID 与执行
callgrind_control的用户不一致(如用sudo启动 valgrind,但普通用户执行 control 命令) - Valgrind 版本太老(callgrind_control 支持不完整;建议用
valgrind --version确认 - 进程已结束,但 control 命令仍发给旧 PID
替代方案:用 --dump-instr=yes + 多次 dump 切片分析
如果控制精度要求不高,可改用更稳定的方式:
- 启动时加
--dump-instr=yes --collect-jumps=yes - 在代码关键位置调用
CALLGRIND_DUMP_STATS宏(需包含valgrind/callgrind.h) - 每次调用会生成独立的
callgrind.out.PID.N文件,N 从 0 递增
示例:
#include <valgrind/callgrind.h> ... CALLGRIND_DUMP_STATS; // 写出当前统计到 callgrind.out.PID.0 do_something_expensive(); CALLGRIND_DUMP_STATS; // 写出增量到 callgrind.out.PID.1
这个方式不依赖外部命令,也不怕权限问题,但要注意宏会带来微小开销,且不能“暂停”,只是快照切片。
实际项目中,多数人卡在 callgrind_control 权限或启动参数遗漏上;真正稳定可控的还是 CALLGRIND_DUMP_STATS 配合宏,尤其当你无法保证运行环境一致性时。


















