【发布时间】:2014-11-21 00:21:23
【问题描述】:
我最近一直在使用 perf,但得到了一些我无法理解的结果。 具体来说,数量或已停用的加载和存储与我的预期不符。
我确实编写了一个非常简单的微基准测试,以查看结果在一个非常简单的情况下是否有意义:
#include <stdio.h>
#define STREAM_ARRAY_SIZE 10000000
static double a[STREAM_ARRAY_SIZE],
b[STREAM_ARRAY_SIZE],
c[STREAM_ARRAY_SIZE];
int main(){
ssize_t j;
for (j=0; j<STREAM_ARRAY_SIZE; j++) {
a[j] = 1.0;
b[j] = 2.0;
c[j] = 0.0;
}
return 0;
}
我用 gcc 4.6.3 编译:
gcc -Wall -O benchmark.c -o benchmark
它确实会编译成一个非常简单的程序集(通过 objdump -d 获得)用于主程序:
00000000004004b4 <main>:
4004b4: b8 00 00 00 00 mov $0x0,%eax
4004b9: 48 be 00 00 00 00 00 movabs $0x3ff0000000000000,%rsi
4004c0: 00 f0 3f
4004c3: 48 b9 00 00 00 00 00 movabs $0x4000000000000000,%rcx
4004ca: 00 00 40
4004cd: ba 00 00 00 00 mov $0x0,%edx
4004d2: 48 89 34 c5 40 10 60 mov %rsi,0x601040(,%rax,8)
4004d9: 00
4004da: 48 89 0c c5 40 c4 24 mov %rcx,0x524c440(,%rax,8)
4004e1: 05
4004e2: 48 89 14 c5 40 78 e9 mov %rdx,0x9e97840(,%rax,8)
4004e9: 09
4004ea: 48 83 c0 01 add $0x1,%rax
4004ee: 48 3d 80 96 98 00 cmp $0x989680,%rax
4004f4: 75 dc jne 4004d2 <main+0x1e>
4004f6: b8 00 00 00 00 mov $0x0,%eax
4004fb: c3 retq
4004fc: 90 nop
4004fd: 90 nop
4004fe: 90 nop
4004ff: 90 nop
这三个 mov 应该对应于存储到内存中的三个不同向量。我希望退休的商店数量非常接近 30M 并且几乎没有负载,因为我只是在初始化三个数组。然而,这是我在 Sandy Bridge 机器上得到的结果:
$ perf stat -e L1-dcache-loads,L1-dcache-stores ./benchmark
Performance counter stats for './benchmark':
46,017,360 L1-dcache-loads
75,985,205 L1-dcache-stores
这是用于 Nehalem 机器的:
$ perf stat -e L1-dcache-loads,L1-dcache-stores ./benchmark
Performance counter stats for './benchmark':
45,255,731 L1-dcache-loads
60,164,676 L1-dcache-stores
对于每个针对内存的 mov 操作,已停用的加载和存储是如何计算的? 即使没有实际从内存中读取数据,为什么会有这么多负载?
【问题讨论】:
-
您是否尝试过缩放数组大小并检查它对结果的影响?如果它没有改变,它可能只是一个不相关的开销
-
负载与存储的比率保持不变,所以我肯定错过了如何协调 mov 与负载和存储。
-
作为一个数据点,在我的 AMD FX8350 上,这些值大约为
10*STREAM_ARRAY_SIZE负载,并且只是STREAM_ARRAY_SIZE存储(即预期的三分之一)。这更奇怪:) -
如果我错了,请纠正我,但这些事件不只计算 L1 中的加载/存储吗?你不可能把整个 10M 双打都放在那里,充其量你是在预取它们——
L1-dcache-prefetches说什么? -
尝试与优化比较 (
-O3)。然后使用_mm_stream_pd比较使用非临时存储。