我不了解 cachegrind 与 perf 工具之间的缓存未命中计数
Posted
技术标签:
【中文标题】我不了解 cachegrind 与 perf 工具之间的缓存未命中计数【英文标题】:I don't understand cache miss count between cachegrind vs. perf tool 【发布时间】:2014-06-29 14:20:47 【问题描述】:我正在使用一个简单的微基准来研究缓存效果。 我认为如果 N 大于缓存大小,那么缓存在每个第一次读取缓存行时都会进行一次未命中操作。 在我的机器中,缓存行大小=64Byte,所以我认为完全缓存发生 N/8 未命中操作,缓存研磨表明。 但是,性能工具显示不同的结果。它仅发生 34,265 次缓存未命中操作。 我怀疑硬件预取,所以在Bios中关闭这个功能。无论如何,结果是一样的。 我真的不知道为什么 perf 工具的缓存未命中发生比“cachegrind”非常小的操作。 谁能给我一个合理的解释?
1。这是一个简单的微基准测试程序。
#include <stdio.h>
#define N 10000000
double A[N];
int main()
int i;
double temp=0.0;
for (i=0 ; i<N ; i++)
temp = A[i]*A[i];
return 0;
2。以下结果是 cachegrind 的输出:
==27612== Cachegrind, a cache and branch-prediction profiler
==27612== Copyright (C) 2002-2013, and GNU GPL'd, by Nicholas Nethercote et al.
==27612== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==27612== Command: ./test
==27612==
--27612-- warning: L3 cache found, using its data for the LL simulation.
==27612==
==27612== I refs: 110,102,998
==27612== I1 misses: 728
==27612== LLi misses: 720
==27612== I1 miss rate: 0.00%
==27612== LLi miss rate: 0.00%
==27612==
==27612== D refs: 70,038,455 (60,026,965 rd + 10,011,490 wr)
==27612== D1 misses: 1,251,802 ( 1,251,288 rd + 514 wr)
==27612== LLd misses: 1,251,624 ( 1,251,137 rd + 487 wr)
==27612== D1 miss rate: 1.7% ( 2.0% + 0.0% )
==27612== LLd miss rate: 1.7% ( 2.0% + 0.0% )
==27612==
==27612== LL refs: 1,252,530 ( 1,252,016 rd + 514 wr)
==27612== LL misses: 1,252,344 ( 1,251,857 rd + 487 wr)
==27612== LL miss rate: 0.6% ( 0.7% + 0.0% )
Generate a report File
--------------------------------------------------------------------------------
I1 cache: 32768 B, 64 B, 4-way associative
D1 cache: 32768 B, 64 B, 8-way associative
LL cache: 8388608 B, 64 B, 16-way associative
Command: ./test
Data file: cache_block
Events recorded: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
Events shown: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
Event sort order: Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
Thresholds: 0.1 100 100 100 100 100 100 100 100
Include dirs:
User annotated: /home/jin/1_dev/99_test/OI/test.s
Auto-annotation: off
--------------------------------------------------------------------------------
Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
--------------------------------------------------------------------------------
110,102,998 728 720 60,026,965 1,251,288 1,251,137 10,011,490 514 487 PROGRAM TOTALS
--------------------------------------------------------------------------------
Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw file:function
--------------------------------------------------------------------------------
110,000,011 1 1 60,000,003 1,250,000 1,250,000 10,000,003 0 0 /home/jin/1_dev/99_test/OI/test.s:main
--------------------------------------------------------------------------------
-- User-annotated source: /home/jin/1_dev/99_test/OI/test.s
--------------------------------------------------------------------------------
Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
-- line 2 ----------------------------------------
. . . . . . . . . .comm A,80000000,32
. . . . . . . . . .comm B,80000000,32
. . . . . . . . . .text
. . . . . . . . . .globl main
. . . . . . . . . .type main, @function
. . . . . . . . . main:
. . . . . . . . . .LFB0:
. . . . . . . . . .cfi_startproc
1 0 0 0 0 0 1 0 0 pushq %rbp
. . . . . . . . . .cfi_def_cfa_offset 16
. . . . . . . . . .cfi_offset 6, -16
1 0 0 0 0 0 0 0 0 movq %rsp, %rbp
. . . . . . . . . .cfi_def_cfa_register 6
1 0 0 0 0 0 0 0 0 movl $0, %eax
1 1 1 0 0 0 1 0 0 movq %rax, -16(%rbp)
1 0 0 0 0 0 1 0 0 movl $0, -4(%rbp)
1 0 0 0 0 0 0 0 0 jmp .L2
. . . . . . . . . .L3:
10,000,000 0 0 10,000,000 0 0 0 0 0 movl -4(%rbp), %eax
10,000,000 0 0 0 0 0 0 0 0 cltq
10,000,000 0 0 10,000,000 1,250,000 1,250,000 0 0 0 movsd A(,%rax,8), %xmm1
10,000,000 0 0 10,000,000 0 0 0 0 0 movl -4(%rbp), %eax
10,000,000 0 0 0 0 0 0 0 0 cltq
10,000,000 0 0 10,000,000 0 0 0 0 0 movsd A(,%rax,8), %xmm0
10,000,000 0 0 0 0 0 0 0 0 mulsd %xmm1, %xmm0
10,000,000 0 0 0 0 0 10,000,000 0 0 movsd %xmm0, -16(%rbp)
10,000,000 0 0 10,000,000 0 0 0 0 0 addl $1, -4(%rbp)
. . . . . . . . . .L2:
10,000,001 0 0 10,000,001 0 0 0 0 0 cmpl $9999999, -4(%rbp)
10,000,001 0 0 0 0 0 0 0 0 jle .L3
1 0 0 0 0 0 0 0 0 movl $0, %eax
1 0 0 1 0 0 0 0 0 popq %rbp
. . . . . . . . . .cfi_def_cfa 7, 8
1 0 0 1 0 0 0 0 0 ret
. . . . . . . . . .cfi_endproc
. . . . . . . . . .LFE0:
. . . . . . . . . .size main, .-main
. . . . . . . . . .ident "GCC: (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3"
. . . . . . . . . .section .note.GNU-stack,"",@progbits
--------------------------------------------------------------------------------
Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
--------------------------------------------------------------------------------
100 0 0 100 100 100 100 0 0 percentage of events annotated
3。以下结果是 perf 的输出:
$ sudo perf stat -r 10 -e instructions -e cache-references -e cache-misses -e L1-dcache-loads -e L1-dcache-load-misses -e L1-dcache-stores -e L1-dcache-store-misses -e LLC-loads -e LLC-load-misses -e LLC-prefetches ./test
Performance counter stats for './test' (10 runs):
113,898,951 instructions # 0.00 insns per cycle ( +- 12.73% ) [17.36%]
53,607 cache-references ( +- 12.92% ) [29.23%]
1,483 cache-misses # 2.767 % of all cache refs ( +- 26.66% ) [39.84%]
48,612,823 L1-dcache-loads ( +- 4.58% ) [50.45%]
34,256 L1-dcache-load-misses # 0.07% of all L1-dcache hits ( +- 18.94% ) [54.38%]
14,992,686 L1-dcache-stores ( +- 4.90% ) [52.58%]
1,980 L1-dcache-store-misses ( +- 6.36% ) [61.83%]
1,154 LLC-loads ( +- 61.14% ) [53.22%]
18 LLC-load-misses # 1.60% of all LL-cache hits ( +- 16.26% ) [10.87%]
0 LLC-prefetches [ 0.00%]
0.037949840 seconds time elapsed ( +- 3.57% )
更多实验结果(2014.05.13):
jin@desktop:~/1_dev/99_test/OI$ sudo perf stat -r 10 -e instructions -e r53024e -e r53014e -e L1-dcache-loads -e L1-dcache-load-misses -e r500f0a -e r500109 ./test
Performance counter stats for './test' (10 runs):
116,464,390 instructions # 0.00 insns per cycle ( +- 2.67% ) [67.43%]
5,994 r53024e <-- L1D hardware prefetch misses ( +- 21.74% ) [70.92%]
1,387,214 r53014e <-- L1D hardware prefetch requests ( +- 2.37% ) [75.61%]
61,667,802 L1-dcache-loads ( +- 1.27% ) [78.12%]
26,297 L1-dcache-load-misses # 0.04% of all L1-dcache hits ( +- 48.92% ) [43.24%]
0 r500f0a <-- LLC lines allocated [56.71%]
41,545 r500109 <-- Number of LLC read misses ( +- 6.16% ) [50.08%]
0.037080925 seconds time elapsed
在上面的结果中,“L1D 硬件预取请求”的数量似乎是 cachegrind 上的 D1 miss(1,250,000)。
在我的结论中,如果内存访问“流模式”,则启用 L1D 预取功能。由于 LLC 未命中信息,我无法检查从内存中加载了多少字节。
我的结论正确吗?
编者注:
(1) 根据cachegrind
的输出,OP 很可能是在使用没有优化的 gcc 4.6.3。
(2) perf stat
中使用的一些原始事件仅在 Nehalem/Westmere 上得到官方支持,所以我认为这就是 OP 正在使用的微架构。
(3) perf
忽略原始事件代码中最高有效字节(即第三个字节)中设置的位。 (虽然不是第三个字节的所有位都被忽略。)所以事件实际上是 r024e、r014e、r0f0a 和 r0109。
(4) r0f0a 和 r0109 事件是非核心事件,但是 OP 将它们指定为核心事件,这是错误的,因为perf
会将它们测量为核心事件。
【问题讨论】:
请您添加您使用的命令行好吗? gcc 及其选项 perf stat ... 抱歉回答迟了。命令行如下:#> sudo perf stat -r 10 -e instructions -e cache-references -e cache-misses -e L1-dcache-loads -e L1-dcache-load-misses -e L1-dcache-stores - e L1-dcache-store-misses -e LLC-loads -e LLC-load-misses -e LLC-prefetches ./test 你确定你的初始程序没有被编译器优化吗?具体来说,可以绕过主循环,因为 A[i] * A[i] 在迭代之间没有被保存(如果你对 temp 使用双精度数组,这应该可以解决问题)。我怀疑编译器正在优化您的微基准测试。 我遇到了同样的问题。您找出造成这种差异的原因了吗? 【参考方案1】:底线:您关于预取的假设是正确的,但您的解决方法不正确。
首先,正如 Carlo 所指出的,这个循环通常会被任何编译器优化。由于 perf 和 cachegrind 都显示 ~100M 指令确实退出,我猜你没有进行优化编译,这意味着行为不是很现实 - 例如,你的循环变量可能存储在内存中而不是寄存器中,添加毫无意义的内存访问和倾斜的缓存计数器。
现在,您的运行之间的区别在于,cachgrind 只是一个缓存模拟器,它不模拟预取,因此每次第一次访问一行都会按预期失败。另一方面,如您所见,真正的 CPU 确实具有硬件预取,因此第一次从内存中获取每一行时,它是通过预取完成的(感谢简单的流模式),而不是由实际的需求负载完成。这就是为什么 perf 错过了使用普通计数器计算这些访问的原因。
您可以看到,在启用预取计数器时,您会看到大致相同的 N/8 次预取(可能还有一些来自其他类型访问的额外预取)。
禁用预取器似乎是正确的做法,但是大多数 CPU 并没有提供过多的控制。您没有指定您使用的处理器类型,但如果它是 Intel 例如,您可以在此处看到只有 L2 预取由 BIOS 控制,而您的输出显示 L1 预取 - https://software.intel.com/en-us/articles/optimizing-application-performance-on-intel-coret-microarchitecture-using-hardware-implemented-prefetchers
搜索您的 CPU 类型的手册以查看存在哪些 L1 预取器,并了解如何解决它们。通常一个简单的步幅(大于单个缓存行)就足以欺骗他们,但如果这不起作用,您需要将访问模式更改为更加随机。您可以为此随机排列一些索引。
【讨论】:
您可以在命令行轻松禁用几乎所有预取器,包括大多数现代英特尔芯片上的两个 L1 预取器。见here。 @BeeOnRope,对。我回想当我写这篇文章时,MSR 是受支持的,但并不是所有的 BIOS 都有这个选项,所以你必须手动完成(并且拥有它的权限)。不想让答案复杂化以上是关于我不了解 cachegrind 与 perf 工具之间的缓存未命中计数的主要内容,如果未能解决你的问题,请参考以下文章