perf 是 linux 下最快上手的热点函数分析工具,通过 perf record -g 采集调用图、perf report -g --no-children 查看火焰图式调用链,需确保二进制含调试符号且未 strip。

用 perf 看热点函数(Linux 最快上手)
perf 是 Linux 下最轻量、最贴近内核的性能分析工具,不用改代码、不依赖编译器插桩,直接抓运行时真实开销。它适合快速定位「哪个函数吃 CPU 最凶」,比如你发现程序卡在某个循环里,但不确定是 process_data 还是 serialize_json 拖慢了。
- 先确保二进制带调试符号:
g++ -g -O2编译,别用-s去符号 - 运行:
perf record -g ./my_program(-g开启调用图,关键) - 分析:
perf report -g --no-children,按方向键展开看火焰图式调用链 - 常见坑:如果看到大量
[unknown],说明缺少 debuginfo(CentOS/RHEL 要装debuginfo-install包)或程序被 strip 过
Clang + llvm-profdata 做精确覆盖率加权分析
当你需要知道「某段 if 分支实际执行了多少次」「循环体里哪一行最热」,就得用基于采样的插桩方案。clang 的 -fprofile-instr-generate 生成的 profile 数据比 perf 更细,能对齐到源码行级,但代价是运行时有 5%–15% 性能损耗。
- 编译两遍:先
clang++ -fprofile-instr-generate -O2 foo.cpp -o foo - 运行一次采集:
./foo(会生成default.profraw) - 合并并转换:
llvm-profdata merge -output=default.profdata default.profraw - 重新编译带注释的报告:
clang++ -fprofile-instr-use=default.profdata -O2 -Rpass=loop-vectorize foo.cpp - 容易忽略的点:必须用同一套 clang/llvm 工具链生成和消费 profile;CMake 用户得关掉
CMAKE_CXX_FLAGS里可能存在的-DNDEBUG,否则断言优化会干扰分支计数
Valgrind 的 callgrind 适合小规模深度探查
callgrind 能给出每个函数调用次数、每次调用耗时、缓存命中率,甚至能模拟 CPU cache 行为。但它慢——通常是原速 20–50 倍,只适合跑几秒内能结束的 case,比如解析一个配置文件、处理单帧图像。
- 启动:
valgrind --tool=callgrind --dump-instr=yes --collect-jumps=yes ./my_program - 生成可读报告:
callgrind_annotate callgrind.out.1234 - 关键参数:
--cache-sim=yes打开 cache 模拟(会更慢),--branch-sim=yes看分支预测失败率 - 注意:C++ 模板实例化多时,
callgrind会把每个实例当独立函数统计,报告可能膨胀;遇到std::vector::push_back占比异常高,先检查是不是没预留容量
Windows 上用 VSDiagnostics.exe 或 WPA 替代 perf
Windows 没有原生 perf,但 Visual Studio 自带的诊断工具链足够用。关键是得用 Release 版本 + PDB 符号文件,否则看到的全是地址而不是函数名。
立即学习“C++免费学习笔记(深入)”;
- 在 VS 中:调试 → 性能探查器 → CPU 使用率(快捷键
Alt+F2) - 命令行方式(无 VS GUI):
VSDiagnostics.exe start -attachPID 1234 -profiler Microsoft-VisualStudio-PerformanceTools-CPU - 导出 ETL 后可用
Windows Performance Analyzer(WPA)打开,重点看Thread Time Stack和Module Load表 - 容易漏的配置:项目属性 → C/C++ → 常规 → 调试信息格式 必须设为
Program Database (/Zi),且链接器 → 调试 → 生成调试信息 必须为Yes (/DEBUG)
真正难的不是选哪个工具,而是让它们看到你想看的那部分行为——比如多线程下锁竞争、内存分配抖动、SIMD 指令未生效,这些都需要配合特定参数和上下文才能浮现。别指望一次跑完就出答案。











