4

我正在使用 Cachegrind 来检索没有 libc 编译的静态程序的缓存未命中数(只是_start调用我的 main 函数和 asm 中的退出系统调用)。该程序是完全确定的,指令和内存引用不会从一次运行到另一次运行。缓存与作为替换策略的 LRU 完全关联。

但是,我注意到未命中的数量有时会发生变化。更具体地说,在我转到不同的目录之前,未命中的次数总是相同的:

 % cache=8 && valgrind --tool=cachegrind --I1=$((cache * 64)),$cache,64 --D1=$((cache * 64)),$cache,64 --L2=262144,4096,64 ./adpcm        
 ...
 ==31352== I   refs:      216,145,010
 ...
 ==31352== D   refs:      130,481,003  (95,186,001 rd   + 35,295,002 wr)
 ==31352== D1  misses:        240,004  (   150,000 rd   +     90,004 wr)
 ==31352== LLd misses:             31  (        11 rd   +         20 wr)

如果我一次又一次地执行相同的命令,我将继续得到相同的结果。但是如果我从不同的目录运行这个程序:

 % cd ..
 % cache=8 && valgrind --tool=cachegrind --I1=$((cache * 64)),$cache,64 --D1=$((cache * 64)),$cache,64 --L2=262144,4096,64 ./malardalen2/adpcm
 ...
 ==31531== I   refs:      216,145,010
 ...
 ==31531== D   refs:      130,481,003  (95,186,001 rd   + 35,295,002 wr)
 ==31531== D1  misses:        250,004  (   160,000 rd   +     90,004 wr)
 ==31531== LLd misses:             31  (        11 rd   +         20 wr)

我什至从不同的目录得到不同的结果。

我还用 Pin 工具做了一些实验,使用这个我不需要更改目录来获取不同的值。但似乎可能值的集合非常有限,并且与 Cachegrind 完全相同。

我的问题是:这种差异的根源是什么?

我的第一个提示是我的程序在内存中的对齐方式不同,因此,在之前的运行中存储在同一行中的一些变量不再存在。这也可以解释有限数量的组合。但我虽然缓存研磨(和 Pin)正在使用虚拟地址,但我假设操作系统(Linux)总是提供相同的虚拟地址。还有什么想法吗?

编辑:您可以猜到读取 LLd 未命中,该程序仅使用 31 个不同的缓存行。此外,缓存只能包含 8 个缓存行。因此,即使在现实中,这种差异也无法通过第二次填充缓存的想法来解释(在最大情况下,L1 中只能保留 8 行)。

编辑 2: Cachegrind 的报告不是基于实际的缓存未命中(由性能计数器给出),而是模拟的结果。基本上,它模拟缓存的行为以计算未命中的数量。由于结果只是暂时的,这完全没问题,并且允许更改缓存属性(大小、关联性)。

编辑 3:我使用的硬件是 Linux 3.2 x86_64 上的 Intel Core i7。编译标志是 -static 并且对于某些程序 -nostdlib (IIRC,我现在不在家)。

4

2 回答 2

5

Linux 为安全问题实施了“地址空间布局随机化”技术 ( http://en.wikipedia.org/wiki/Address_space_layout_randomization )。您可以像这样停用此行为:

echo -n "0" > /proc/sys/kernel/randomize_va_space

您可以通过以下示例进行测试:

#include <stdio.h>

int main() {
   char a;
   printf("%u\n", &a);
   return 0;
}

您应该始终打印相同的值。

前:

 % ./a.out
4006500239
 % ./a.out
819175583
 % ./a.out
2443759599
 % ./a.out
2432498159

后:

 % ./a.out
4294960207
 % ./a.out
4294960207
 % ./a.out
4294960207
 % ./a.out
4294960207

这也解释了不同数量的缓存未命中,因为在同一行中的两个变量现在可以在两个不同的行中。

编辑:这显然不能完全解决问题,但我认为这是原因之一。我会将赏金提供给任何可以帮助我解决此问题的人。

于 2013-07-01T14:04:51.543 回答
2

这似乎是 valgrind 中的一个已知行为:

我使用了输出缓存基地址的示例,我还禁用了布局随机化。

我运行了两次可执行文件,两次运行都得到了相同的结果:

D   refs:       40,649  (28,565 rd   + 12,084 wr)
==15016== D1  misses:     11,465  ( 8,412 rd   +  3,053 wr)
==15016== LLd misses:      1,516  ( 1,052 rd   +    464 wr)
==15016== D1  miss rate:    28.2% (  29.4%     +   25.2%  )
==15016== LLd miss rate:     3.7% (   3.6%     +    3.8%  )

villar@localhost ~ $ cache=8 && valgrind --tool=cachegrind --I1=$((cache * 64)),$cache,64 --D1=$((cache * 64)),$cache,64 --L2=262144,4096,64 ./a.out 

==15019== D   refs:       40,649  (28,565 rd   + 12,084 wr)
==15019== D1  misses:     11,465  ( 8,412 rd   +  3,053 wr)
==15019== LLd misses:      1,516  ( 1,052 rd   +    464 wr)
==15019== D1  miss rate:    28.2% (  29.4%     +   25.2%  )
==15019== LLd miss rate:     3.7% (   3.6%     +    3.8%  )

根据 cachegrind 文档(http://www.cs.washington.edu/education/courses/cse326/05wi/valgrind-doc/cg_main.html

另一件毫无价值的事情是结果非常敏感。更改 >valgrind.so 文件的大小、正在分析的程序的大小,甚至其名称的长度都会影响结果。变化会很小,但如果你的程序发生变化,不要指望完美的>可重复的结果。虽然这些因素意味着您不应该相信结果是超级准确的,但希望它们应该足够接近以便有用。

读完后,我更改了文件名并得到以下内容:

villar@localhost ~ $ mv a.out a.out2345345345
villar@localhost ~ $ cache=8 && valgrind --tool=cachegrind --I1=$((cache * 64)),$cache,64 --D1=$((cache * 64)),$cache,64 --L2=262144,4096,64 ./a.out2345345345 

==15022== D   refs:       40,652  (28,567 rd   + 12,085 wr)
==15022== D1  misses:     10,737  ( 8,201 rd   +  2,536 wr)
==15022== LLd misses:      1,517  ( 1,054 rd   +    463 wr)
==15022== D1  miss rate:    26.4% (  28.7%     +   20.9%  )
==15022== LLd miss rate:     3.7% (   3.6%     +    3.8%  )

将名称改回“a.out”给了我与以前完全相同的结果。

请注意,更改文件名或路径将更改堆栈的基础!!。这可能是阅读 Evgeny 先生在之前评论中所说的话后的原因

当您更改当前工作目录时,您也会更改相应的环境变量(及其长度)。由于所有环境变量的副本通常存储在堆栈的上方,因此您会获得不同的堆栈变量分配和不同数量的缓存未命中。(除了“PWD”之外,shell 还可以更改其他一些变量)。

编辑:文档还说:

程序启动/关闭调用了很多不感兴趣的函数,只会使输出复杂化。以某种方式排除这些会很好。

模拟缓存可能会跟踪程序的开始和结束,因为它是变化的来源。

于 2013-07-08T13:47:25.973 回答