- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
在 Agner Fog 的优秀 microarchitecture.pdf (section 9.14)我读到:
Store forwarding works in the following cases: [...] When a write of 128 or 256 bits is followed by a read of the same size and the same address, aligned by 16.
另一方面,Intel的架构优化引用手册(2.2.5.2 Intel Sandy Bridge,L1 DCache)我看过
Stores cannot forward to loads in the following cases: [...] Any load that crosses a 16-byte boundary of a 32-byte store.
任何负载听起来也像 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 对齐的内存位置和 vector 寄存器。当使用 AVX 指令集 (gcc -O3 -DTEST_AVX
) 编译时,在我的 2.7GHz i7-2620M 上执行时间为 3.1s。使用SSE2指令集时,时间为2.5s。我看过性能计数器。在 AVX 案例中,我每次迭代计算一个存储转发 block 事件(计数器 03H 02H LD_BLOCKS.STORE_FORWARD
)。对于 SSE2 情况,计数器读数为 0。
任何人都可以阐明这一点吗? SB 确实不支持将 32 字节存储转发到 32 字节加载吗?如果是后者,溢出 ymm
寄存器似乎是一件相当昂贵的事情..
最佳答案
毕竟在 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
递增,尽管没有发生阻塞。在使用计数器分析性能时应考虑到这一点。
关于c - Sandy Bridge 上的 32 字节存储转发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22146956/
我是一名优秀的程序员,十分优秀!