cg_annotate 默认按指令缓存读取次数(Ir)降序排列函数;它需配合cachegrind输出文件使用,不直接解析原始.out文件,且Ir高不代表一定是性能瓶颈,需结合I1mr、Dr、D1mr等指标交叉分析。

怎么看 cachegrind 输出的函数调用排名
直接看 cachegrind.out.xxx 文件本身是没法直观看出“函数排名”的——它默认只记录每行指令的缓存访问统计,函数级聚合需要额外工具处理。真正的函数热点排名得靠 callgrind_annotate 或 cg_annotate(二者功能一致,后者更常用)来解析和排序。
cg_annotate 默认排序逻辑是什么
它按「指令缓存读取次数(Ir)」降序排列函数,这是最常用来衡量 CPU 热点的指标。但注意:Ir 不等于执行时间,也不直接反映 L1/L2 缓存命中率——它只是指令获取频次,高 Ir 函数未必是性能瓶颈,比如内联展开多、循环体大、或被高频调用的简单函数都容易上榜。
-
--auto=yes会自动尝试关联源码(需编译时加-g),否则只显示函数名或地址 -
--threshold=0.5可过滤掉贡献低于 0.5% 的函数(避免列表过长) - 想按数据缓存访问排,得用
--sort=D1mr(一级数据缓存缺失率)或--sort=Dr(数据读次数),但这些字段需在运行valgrind --tool=cachegrind --Cachegrind:dw=yes ...时显式开启
为什么有些函数没出现在排名里
常见原因有三个:函数被内联(gcc -O2 下很常见)、未带调试符号(-g 缺失导致 cg_annotate 无法识别函数边界)、或该函数根本没被执行到(cachegrind 只统计实际运行路径)。
- 确认是否内联:用
objdump -t your_binary | grep func_name查看符号是否存在;或临时加-fno-inline -O0重编译再测 - 检查输出文件是否真含数据:用
head -20 cachegrind.out.xxx看是否有events:行和非零的Ir计数 -
cg_annotate默认只显示 top N(通常是 20),加--inclusive=yes并配合--threshold=0才能看到所有函数(含被调用但自身不耗 Ir 的“胶水函数”)
真正值得关注的指标组合有哪些
单看 Ir 容易误判。实际排查时,要交叉比对几个字段:
-
Ir高 +I1mr(一级指令缓存缺失率)也高 → 指令局部性差,可能函数体过大或跳转分散 -
Dr高 +D1mr高 → 数据访问模式糟糕,考虑结构体对齐、遍历顺序(如 row-major vs col-major)、或缓存行伪共享 -
Dw(数据写次数)突增且D1mw(写缺失率)高 → 写分配策略影响大,可结合--cachegrind:dw=yes开启详细写统计
这些字段是否可用,取决于你运行 cachegrind 时有没有传对应开关。没开就看不到,不是工具没算——这点最容易忽略。


















