首页 文章

Sandy Bridge上的32字节存储转发

提问于
浏览
8

在Agner Fog的优秀microarchitecture.pdf (section 9.14)我读到:

存储转发在以下情况下有效:[...]当写入128或256位后,读取相同大小和相同的地址,对齐16 .

另一方面,我阅读了英特尔架构优化参考手册(2.2.5.2 Intel Sandy Bridge,L1 DCache)

在以下情况下,存储无法转发到负载:[...]任何跨越32字节存储的16字节边界的负载 .

任何负载听起来像32字节加载..我写了以下简单的代码来测试这一点,似乎32字节存储 not 转发到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 回答

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

相关问题