在Agner Fog的出色microarchitecture.pdf (section 9.14)中,我读到了:
存储转发在以下情况下有效:[...]当写入128或256位后,读取相同大小和相同的地址,对齐16。
另一方面,英特尔的架构优化参考手册(2.2.5.2 Intel Sandy Bridge,L1 DCache)我读到了
在以下情况下,商店无法转发到负载:[...]任何跨越32字节存储的16字节边界的负载。
任何负载听起来也像是32字节加载..我编写了以下简单代码来测试它,并且似乎32位字节存储不转发到Sandy Bridge架构上的后续32字节加载。这是代码:
#include <stdlib.h>
#include <malloc.h>
int main(){
long i;
// aligned memory address
double *tempa = (double*)memalign(4096, sizeof(double)*4);
for(i=0; i<4; i++) tempa[i] = 1.0;
for(i=0; i<1000000000; i++){ // 1e9 iterations
#ifdef TEST_AVX
__asm__("vmovapd %%ymm12, (%0)\n\t"
"vmovapd (%0), %%ymm12\n\t"
:
:"r"(tempa));
#else
__asm__("movapd %%xmm12, (%0)\n\t"
"movapd (%0), %%xmm12\n\t"
:
:"r"(tempa));
#endif
}
}
循环中唯一做的是从/向4k对齐的存储器位置和向量寄存器进行读/写。使用AVX指令集(gcc -O3 -DTEST_AVX
)编译时,我的2.7GHz i7-2620M的执行时间为3.1秒。使用SSE2指令集时,时间为2.5秒。我看了一下性能指标。在AVX情况下,我计算每次迭代一次存储转发块事件(计数器03H 02H LD_BLOCKS.STORE_FORWARD
)。计数器为SSE2情况读取0。
有人可以对此有所了解吗? SB确实不支持将32字节存储转发到32字节加载吗?如果是后者,那么溢出ymm
寄存器似乎是一件相当昂贵的事情。
答案 0 :(得分:1)
毕竟,Sandy Bridge上似乎没有32字节负载的存储到负载阻塞。考虑以下修改后的循环体:
#ifdef TEST_AVX
__asm__("vmovapd %%ymm12, (%0)\n\t"
"vmovapd (%0), %%ymm13\n\t"
:
:"r"(tempa));
#else
__asm__("movapd %%xmm12, (%0)\n\t"
"movapd (%0), %%xmm13\n\t"
:
:"r"(tempa));
#endif
更改是目标寄存器 - 我现在使用两个不同的寄存器进行加载和存储,这样两条指令和后续迭代之间就没有依赖关系。在这种情况下,SSE版本每次迭代需要1个周期,而AVX版本需要2个周期。这与SB每个周期具有两个16字节负载的容量一致。因此,加载32个字节需要两个周期 - 没有停顿。
问题必须与计数器逻辑相关联。显然,在AVX情况下,LD_BLOCKS.STORE_FORWARD
会增加,但不会发生阻塞。在使用计数器分析性能时应考虑到这一点。