valgrind的cachegrind不直接输出缓存命中率,需手动计算:命中率 = 1 − (i1mr + d1mr + llmr) / (i1refs + d1refs + llrefs);必须指定--tool=cachegrind及真实cpu缓存参数,并用cg_annotate解析输出。

直接跑 cachegrind 会得到一堆数字,但没命中率
Valgrind 的 cachegrind 工具本身不输出“缓存命中率”这个值,只给原始计数:访问次数(I1refs、D1refs、LLrefs)和缺失次数(I1mr、D1mr、LLmr)。你要自己算:命中率 = 1 − (I1mr + D1mr + LLmr) / (I1refs + D1refs + LLrefs)。别指望 cachegrind 报告里有现成的百分比。
必须加 --tool=cachegrind,且建议固定缓存参数
默认参数可能和你真实 CPU 不符,导致分析失真。运行时至少要指定三级缓存配置:
-
--I1=32768,8,64:一级指令缓存 32KB、8 路组相联、64 字节块 -
--D1=32768,8,64:一级数据缓存同上 -
--LL=8388608,16,64:末级缓存(L3)8MB、16 路、64 字节块(按你 CPU 实际查,比如 Intel i7 常见 8–16MB) - 输出重定向用
--cachegrind-out-file=cg.out,方便后续处理
不加这些,cachegrind 会用模拟默认值,跟生产环境偏差可能很大。
cg_annotate 是唯一靠谱的汇总入口
别打开 cg.out 文件手动翻——它混着头信息和逐行统计,人眼无法解析。正确做法是:
- 先执行
cg_annotate cg.out --auto=yes | head -20看顶层汇总 - 关键字段在开头几行:
D1 misses、D1 reads、D1 writes这些才是计算 D1 命中率的原料 - 注意:
LL misses不是 L3 命中率分母,它是“所有未在 L1/L2 命中的访存总数”,不能直接除LL refs - 真正有意义的是 D1 层:命中数 = (
D1 reads+D1 writes) −D1 misses
编译和符号必须对得上,否则行号全是错的
cachegrind 依赖调试信息做源码映射,出错基本都栽在这儿:
- 编译必须带
-g,否则cg_annotate显示的行号是乱的或全为 ?? - 可以用
-O2,不影响缓存行为建模 - 禁用
-flto:LTO 会丢符号,cachegrind就关联不上函数和源码 - 内联函数的统计会归到调用点,不是函数定义处——这是工具限制,不是 bug
最常被忽略的是 -flto 和缓存参数不匹配这两点,一上来就跑出“命中率 99%”或者“全是 ?? 行”,八成卡在这儿。











