英特尔AVX的性能比标量代码慢

时间:2018-09-03 13:27:57

标签: c intel sse simd avx

我正在尝试比较带有-O3标志的标量代码和Intel AVX(SIMD)代码的性能。

运行程序后,我发现它们之间存在巨大的性能差异。 我使用4个功能:
*总和
*数
*分钟
*最大
对于所有标量执行,我检索到的结果时间为0.000001秒(平均,每种情况下执行11次),而AVXSum,AVXMin,AVXMax的结果时间为0.043958秒(计数情况下,两次执行都得到相同的快速结果)。

我试图深入研究标量函数的汇编代码。令我惊讶的是,我发现gcc会为ScalarSum,ScalarCount,ScalarMin,ScalarMax生成相同的汇编代码。

由于发生RAW依赖关系,所以我期望执行时间会有所延迟。仔细查看分支未命中数,它们非常接近(即:AVXMin为772,548,846个分支丢失,平均为0.044221sec,ScalarMin为772,656,995个分支丢失平均为0.000000秒)。

输入(关系)是1024 * 1024 * 1024个元素的数组(rel_size)。 在主函数中,我初始化并随机化输入数组(rand()为用户,并实现了Fisher Yates算法)。我相信不会进行编译时间计算,但是我无法解释如此大的性能差异。

下面,我将为标量大小写附加生成的汇编代码(正如我提到的,所有情况都相同)。此外,我附加了AVXMin和ScalarMin C代码。

    .file   "scalarMin.c"  
    .section    .text.unlikely,"ax",@progbits  
.LCOLDB1:  
    .text  
.LHOTB1:  
    .p2align 4,,15  
    .globl  scalar_min  
    .type   scalar_min, @function
scalar_min:
.LFB38:
    .cfi_startproc
    pushq   %rbx
    .cfi_def_cfa_offset 16
    .cfi_offset 3, -16
    call    clock
    movq    %rax, %rbx
    call    clock
    pxor    %xmm0, %xmm0
    subq    %rbx, %rax
    popq    %rbx
    .cfi_def_cfa_offset 8
    cvtsi2sdq   %rax, %xmm0
    divsd   .LC0(%rip), %xmm0
    ret
    .cfi_endproc
.LFE38:
    .size   scalar_min, .-scalar_min
    .section    .text.unlikely
.LCOLDE1:
    .text
.LHOTE1:
    .section    .rodata.cst8,"aM",@progbits,8
    .align 8
.LC0:
    .long   0
    .long   1093567616
    .ident  "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609"
    .section    .note.GNU-stack,"",@progbits

Intel AVX Min功能:

double avx_min(int32_t** relation, int32_t rel_size){

  clock_t t;
  __m256i input_buffer;
  __m256i min = _mm256_set_epi32(INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX);
  t = clock();
  for(int i = 0 ; i < rel_size ; i += 8){
    input_buffer = _mm256_stream_load_si256((__m256i*)&(*relation)[i]);
    min = _mm256_min_epi32(min, input_buffer);
  }
  t = clock() - t;
  return ((double) t) /CLOCKS_PER_SEC;
}

标量最小值功能:

double scalar_min(int32_t** relation, int32_t rel_size){
  clock_t t;
  int32_t min = INT32_MAX;
  t = clock();
  for(int i = 0 ; i < rel_size ; i++){
    if( (*relation)[i] < min ){
     min = (*relation)[i];
    }
  }
  t = clock() - t;
  return ((double) t) /CLOCKS_PER_SEC;
}

在此先感谢您的帮助:)

0 个答案:

没有答案