流固有降低了性能

use*_*358 5 assembly sse vectorization intrinsics avx

我正在玩_mm_stream_ps内在函数,我在理解其性能方面遇到了一些麻烦.

这是我正在使用的代码片段...流版本:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <omp.h>

#include <immintrin.h>

#define NUM_ELEMENTS 10000000L

static void copy_temporal(float* restrict x, float* restrict y)
{
   for(uint64_t i = 0; i < NUM_ELEMENTS/2; ++i){
      _mm_store_ps(y,_mm_load_ps(x));
      _mm_store_ps(y+4,_mm_load_ps(x+4));
      x+=8;
      y+=8;
   }
}
static void copy_nontemporal(float* restrict x, float* restrict y)
{
   for(uint64_t i = 0; i < NUM_ELEMENTS/2; ++i){
      _mm_stream_ps(y,_mm_load_ps(x));
      _mm_stream_ps(y+4,_mm_load_ps(x+4));
      x+=8;
      y+=8;
   }
}

int main(int argc, char** argv)
{
   uint64_t sizeX = sizeof(float) * 4 * NUM_ELEMENTS;
   float *x = (float*) _mm_malloc(sizeX,32);
   float *y = (float*) _mm_malloc(sizeX,32);

   //initialization
   for(uint64_t i = 0 ; i < 4 * NUM_ELEMENTS; ++i){
      x[i] = (float)rand()/RAND_MAX;
      y[i] = 0;
   }

   printf("%g MB allocated\n",(2 * sizeX)/1024.0/1024.0); 

   double start = omp_get_wtime();
   copy_nontemporal(x, y);
   double time = omp_get_wtime() - start;
   printf("Bandwidth (non-temporal): %g GB/s\n",((3 * sizeX)/1024.0/1024.0/1024.0)/time);

   start = omp_get_wtime();
   copy_temporal(x, y);
   time = omp_get_wtime() - start;
   printf("Bandwidth: %g GB/s\n",((3 * sizeX)/1024.0/1024.0/1024.0)/time);

   _mm_free(x);
   _mm_free(y);

   return 0;
}
Run Code Online (Sandbox Code Playgroud)

表现结果:

2.3 GHz Core i7 (I7-3615QM) (Laptop):
    305.176 MB allocated
    Bandwidth (non-temporal): 24.2242 GB/s
    Bandwidth: 21.4136 GB/s

Xeon(R) CPU E5-2650 0 @ 2.00GHz (cluster (exclusive job)):
    305.176 MB allocated
    Bandwidth (non-temporal): 8.33133 GB/s
    Bandwidth: 8.20684 GB/s
Run Code Online (Sandbox Code Playgroud)

让我感到困惑的是,我看到更好的性能 - 在Xeon CPU上(不在我的笔记本电脑上) - 如果我使用非对齐的加载和存储(即storeu_ps/loadu_ps):

305.176 MB allocated
Bandwidth (non-temporal): 8.30105 GB/s
Bandwidth: 12.7056 GB/s
Run Code Online (Sandbox Code Playgroud)

我希望流版本比非流版本更快 - 由于y的冗余负载.但是,测量显示流版本实际上比非流版本慢两倍.

你对此有什么解释吗?

使用的编译器:Intel 14.0.1; 编译器标志:-O3 -restrict -xAVX; 使用的CPU:Intel Xeon E5-2650;

谢谢.

use*_*358 0

正如 ScottD 指出的,问题的答案在于生成的汇编代码。显然,英特尔编译器足够智能,可以检测访问模式,并自动生成非临时负载,即使是临时版本也是如此。

这是编译器生成的临时版本的汇编代码:

..___tag_value___Z13copy_temporalPfS_.35:                       #
        xor       edx, edx                                      #22.4
        xor       eax, eax                                      #
..B2.2:                         # Preds ..B2.2 ..B2.1
        vmovups   xmm0, XMMWORD PTR [rax+rdi]                   #23.34
        inc       rdx                                           #22.4
        vmovntps  XMMWORD PTR [rax+rsi], xmm0                   #23.20
        vmovups   xmm1, XMMWORD PTR [16+rax+rdi]                #24.36
        vmovntps  XMMWORD PTR [16+rax+rsi], xmm1                #24.20
        vmovups   xmm2, XMMWORD PTR [32+rax+rdi]                #23.34
        vmovntps  XMMWORD PTR [32+rax+rsi], xmm2                #23.20
        vmovups   xmm3, XMMWORD PTR [48+rax+rdi]                #24.36
        vmovntps  XMMWORD PTR [48+rax+rsi], xmm3                #24.20
        add       rax, 64                                       #22.4
        cmp       rdx, 5000000                                  #22.4
        jb        ..B2.2        # Prob 99%                      #22.4
Run Code Online (Sandbox Code Playgroud)

仍然存在的问题如下:

为什么 CPU E5-2650 的非对齐临时版本比非临时版本性能更好(见上文)。我已经查看了生成的汇编代码,编译器确实生成了 vmovups 指令(由于不存在对齐)。