Intel Core i7处理器和缓存行为
我已经在Intel Core i7 CPU(32KB一级数据缓存和64B一级缓存线大小)上运行了以下汇编代码:(在每个4字节10000个元素的数组中迭代1000次) Perf提供以下统计信息:Intel Core i7处理器和缓存行为,c,performance,caching,assembly,intel,C,Performance,Caching,Assembly,Intel,我已经在Intel Core i7 CPU(32KB一级数据缓存和64B一级缓存线大小)上运行了以下汇编代码:(在每个4字节10000个元素的数组中迭代1000次) Perf提供以下统计信息: 10,135,716,950 L1-dcache-loads 601,544,266 L1-dcache-load-misses # 5.93% of all L1-dcache hits 4.747253821 seconds time elapsed 2,503,4
10,135,716,950 L1-dcache-loads
601,544,266 L1-dcache-load-misses # 5.93% of all L1-dcache hits
4.747253821 seconds time elapsed
2,503,436,639 L1-dcache-loads
123,835,666 L1-dcache-load-misses # 4.95% of all L1-dcache hits
0.629926637 seconds time elapsed
这完全有道理,因为我正在访问内存中的1000*10000=10000个元素,而缓存线为64B(向量中的元素为4B),这意味着每16个元素就有一个一级缓存未命中(因此大约62500000个一级缓存未命中)
现在,我已经“展开”了循环的一部分,代码是:
.cfi_startproc
mov edx, 1000
jmp .L2
.L3:
mov ecx, DWORD PTR v[0+eax*4]
mov ecx, DWORD PTR v[0+eax*4 + 4]
mov ecx, DWORD PTR v[0+eax*4 + 8]
mov ecx, DWORD PTR v[0+eax*4 + 12]
add eax, 4
cmp eax, 2500000
jl .L3
sub edx, 1
je .L4
.L2:
mov eax, 0
jmp .L3
.L4:
mov eax, 0
ret
.cfi_endproc
Perf how提供以下统计信息:
10,135,716,950 L1-dcache-loads
601,544,266 L1-dcache-load-misses # 5.93% of all L1-dcache hits
4.747253821 seconds time elapsed
2,503,436,639 L1-dcache-loads
123,835,666 L1-dcache-load-misses # 4.95% of all L1-dcache hits
0.629926637 seconds time elapsed
我不明白为什么
1) 一级缓存加载更少,因为我访问的数据量相同
2) 代码运行速度比第一个版本快6倍?我知道它有
关于无序执行和超标量执行,但我无法详细解释(我想确切了解是什么导致了这种加速)。坏消息-第二个错误;) 原始代码
.L3:
mov ecx, DWORD PTR v[0+eax*4]
add eax, 1
cmp eax, 10000000
jl .L3
第二版
.L3:
mov ecx, DWORD PTR v[0+eax*4]
mov ecx, DWORD PTR v[0+eax*4 + 4]
mov ecx, DWORD PTR v[0+eax*4 + 8]
mov ecx, DWORD PTR v[0+eax*4 + 12]
add eax, 4
cmp eax, 2500000 <- here
jl .L3
第二:
(2.500.000-4)*4+12 = 9.999.996
正好少4倍
只需将第二个示例修复为
cmp eax,10000000
。确定:(我已经修复了它。现在缓存命中和加载都正常了。但它的执行速度仍然更快:2.617806762秒。为什么?这只是因为它必须执行更少的跳转指令?展开通常会带来收益。第二件事我们不知道你有哪个i7。另外,如果你不总是加载到ecx,但不同的寄存器(前3个加载是“无效”,因为最后一个总是覆盖ecx,所以CPU可能会看到这一点,并在这里执行一些魔术)。同时检查如果展开8或16次会发生什么。