Sandy Bridge上的32字节存储转发

时间:2014-03-03 12:34:38

标签: c performance assembly intel performancecounter

在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寄存器似乎是一件相当昂贵的事情。

1 个答案:

答案 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会增加,但不会发生阻塞。在使用计数器分析性能时应考虑到这一点。