一、概述
Cachegrind,它模拟CPU中的一级缓存I1,Dl和二级缓存,能够精确地指出程序中cache的丢失和命中。如果需要,它还能够为我们提供cache丢失次数,内存引用次数,以及每行代码,每个函数,每个模块,整个程序产生的指令数。这对优化程序有很大的帮助。
Cachegrind模拟程序与CPU的缓存层次结构和分支预测器(可选)的交互方式。它模拟具有独立的第一级指令和数据缓存(I1和D1)的CPU,支持二级缓存(L2)。这与许多CPU的配置完全匹配。
但是,一些新的CPU具有三级或四级缓存。对于这种情况,Cachegrind会模拟第一级L1和最后一级缓存。原因是L1高速缓存通常具有低关联性、最后一级缓存对程序运行时影响最大,因此模拟它们可以检测代码与此高速缓存主要交互情况。
Cachegrind收集以下统计信息(括号中给出了每个统计信息使用的缩写):
I 缓存读取(Ir,它等于执行的指令数),I1缓存读取未命中(I1mr)和LL缓存指令读取未命中(ILmr)。
D缓存读取(Dr等于内存读取的数量),D1缓存读取未命中(D1mr)和LL缓存数据读取未命中(DLmr)。
D缓存写入(Dw等于内存写入次数),D1缓存写入未命中(D1mw)和LL缓存数据写入未命中(DLmw)。
条件分支执行(Bc)和条件分支错误预测(Bcm)。
间接分支执行(Bi)和间接分支错误预测(Bim)。
注意,D1总访问量由D1mr+ 给出 D1mw,LL总访问量由ILmr+ DLmr+ 给出DLmw。
在现代CPU上,L1未命中通常将花费大约10个周期,LL未命中可能花费多达200个周期,并且分支错误预测的成本在10到30个周期。详细的缓存和分支分析对于了解程序如何与CPU进行交互以及如何使其更快地运行非常有用。
此外,由于每个执行的指令执行一次指令高速缓存读取,因此可以找出每行代码的指令数。
二、使用
1、例子main.c源码
#include <stdio.h>
int main()
{
printf("hello\n");
return 0;
}
2、编译
gcc -g main.c
3、检测命令
$ valgrind --tool=cachegrind ./a.out
4、打印信息
==5968== Cachegrind, a cache and branch-prediction profiler
==5968== Copyright (C) 2002-2013, and GNU GPL'd, by Nicholas Nethercote et al.
==5968== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==5968== Command: ./a.out
==5968==
--5968-- warning: L3 cache found, using its data for the LL simulation.
hello
==5968==
==5968== I refs: 106,417
==5968== I1 misses: 777
==5968== LLi misses: 765
==5968== I1 miss rate: 0.73%
==5968== LLi miss rate: 0.71%
==5968==
==5968== D refs: 40,230 (26,892 rd + 13,338 wr)
==5968== D1 misses: 1,760 ( 1,253 rd + 507 wr)
==5968== LLd misses: 1,555 ( 1,075 rd + 480 wr)
==5968== D1 miss rate: 4.3% ( 4.6% + 3.8% )
==5968== LLd miss rate: 3.8% ( 3.9% + 3.5% )
==5968==
==5968== LL refs: 2,537 ( 2,030 rd + 507 wr)
==5968== LL misses: 2,320 ( 1,840 rd + 480 wr)
==5968== LL miss rate: 1.5% ( 1.3% + 3.5% )
5、Cachegrind命令行选项
–I1=<size>,<associativity>,<line size>
指定1级指令高速缓存的大小,关联性和行大小。
–D1=<size>,<associativity>,<line size>
指定1级数据高速缓存的大小,关联性和行大小。
–LL=<size>,<associativity>,<line size>
指定最后一级缓存的大小,关联性和行大小。
–cache-sim=no|yes [yes]
启用或禁用缓存访问和未命中计数的收集。
–branch-sim=no|yes [no]
启用或禁用分支指令和错误预测计数的收集。默认情况下,这会被禁用,因为它会使Cachegrind减慢大约25%。注意:–cache-sim=no 和–branch-sim=no 不能同时使用。
–cachegrind-out-file=<file>
将配置文件数据写入 file而不是默认输出文件 cachegrind.out.<pid>。
6、cg_annotate命令行选项
-h --help
显示帮助信息。
–version
显示版本号。
–show=A,B,C [default: all, using order in cachegrind.out.<pid>]
指定要显示的事件(以及列顺序)。默认是使用cachegrind.out.<pid>文件中的所有内容 (并使用文件中的顺序)。配合–sort使用 。
–sort=A,B,C [default: order in cachegrind.out.<pid>]
指定逐个函数条目的排序所基于的事件。
–threshold=X [default: 0.1%]
设置阈值。
–auto=<no|yes> [default: no]
启用后,会自动注释可以找到的逐个功能摘要中提到的每个文件。还列出了无法找到的列表。
–context=N [default: 8]
在每个带注释的行之前和之后打印N行上下文。避免打印未执行的大部分源文件。使用大数字(例如100000)来显示所有源线。
-I
将目录添加到列表中以搜索文件。 可以提供多个-I/ --include选项来添加多个目录。
7、cg_merge命令行选项
-o outfile
将配置文件数据写入outfile 而不是标准输出。
8、cg_diff命令行选项
-h --help
显示帮助信息。
–version
显示版本号。
–mod-filename= [default: none]
用于消除文件中的微小差异。
–mod-funcname= [default: none]
和–mod-filename相似。用于删除某些编译器生成的自动生成函数的随机名称中的微小差异。