在标量矩阵添加中使用vADDS代替添加剂的好处是什么?



我已经实现了标量矩阵加法内核。

#include <stdio.h>
#include <time.h>
//#include <x86intrin.h>
//loops and iterations:
#define N 128
#define M N
#define NUM_LOOP 1000000

float   __attribute__(( aligned(32))) A[N][M],
        __attribute__(( aligned(32))) B[N][M],
        __attribute__(( aligned(32))) C[N][M];
int main()
{
int w=0, i, j;
struct timespec tStart, tEnd;//used to record the processiing time
double tTotal , tBest=10000;//minimum of toltal time will asign to the best time
do{
    clock_gettime(CLOCK_MONOTONIC,&tStart);
    for( i=0;i<N;i++){
        for(j=0;j<M;j++){
            C[i][j]= A[i][j] + B[i][j];
        }
    }
    clock_gettime(CLOCK_MONOTONIC,&tEnd);
    tTotal = (tEnd.tv_sec - tStart.tv_sec);
    tTotal += (tEnd.tv_nsec - tStart.tv_nsec) / 1000000000.0;
    if(tTotal<tBest)
        tBest=tTotal;
    } while(w++ < NUM_LOOP);
printf(" The best time: %lf sec in %d repetition for %dX%d matrixn",tBest,w, N, M);
return 0;
}

在这种情况下,我已经用不同的编译器标志编辑了该程序,并且内部循环的组装输出如下:

gcc -O2 msse4.2:最佳时间:406490重复128x128矩阵

的0.000024 sec
movss   xmm1, DWORD PTR A[rcx+rax]
addss   xmm1, DWORD PTR B[rcx+rax]
movss   DWORD PTR C[rcx+rax], xmm1

gcc -O2 -mavx:最佳时间:1000001重复128x128矩阵

的0.000009 sec
vmovss  xmm1, DWORD PTR A[rcx+rax]
vaddss  xmm1, xmm1, DWORD PTR B[rcx+rax]
vmovss  DWORD PTR C[rcx+rax], xmm1

AVX版本gcc -O2 -mavx

__m256 vec256;
for(i=0;i<N;i++){   
    for(j=0;j<M;j+=8){
        vec256 = _mm256_add_ps( _mm256_load_ps(&A[i+1][j]) ,  _mm256_load_ps(&B[i+1][j]));
        _mm256_store_ps(&C[i+1][j], vec256);
            }
        }

SSE版本gcc -O2 -sse4.2 ::

__m128 vec128;
for(i=0;i<N;i++){   
    for(j=0;j<M;j+=4){
    vec128= _mm_add_ps( _mm_load_ps(&A[i][j]) ,  _mm_load_ps(&B[i][j]));
    _mm_store_ps(&C[i][j], vec128);
            }
        }

在标量程序中,msse4.2上的-mavx的加速度为2.7倍。我知道avx有效地改进了ISA,这可能是由于这些改进。但是,当我针对AVXSSE实施该程序时,加速度为3倍。问题是:当我对其进行矢量化时,AVX标量比SSE快2.7倍,速度为3倍(对于此问题而言,矩阵大小为128x128)。在标量模式下使用AVX和SSE时,这是否有意义,这是2.7倍的加速。但是矢量化方法必须更好,因为我在AVX中处理了八个元素,而SSE中的四个要素。如perf stat,所有程序的高速缓存失误少于4.5%。

使用gcc -O2linux mintskylake

更新:简短,标量AVX比标量-SSE快2.7倍,但AVX-256在矢量化时仅比SSE-128快3倍。我认为这可能是因为管道。在标量中,我有3个vec-ALU,在矢量化模式下可能无法使用。我可能会将苹果与橘子相比,而不是苹果与苹果,这可能是我无法理解原因的一点。

您要观察到的问题在这里说明。在Skylake系统上,如果AVX寄存器的上半部分是脏的,则在AVX寄存器上半部的非VEVS编码的SSE操作存在错误的依赖性。就您而言,您的GLIBC 2.23版本中似乎有一个错误。在我的Skylake系统上,Ubuntu 16.10和Glibc 2.24我没有问题。您可以使用

__asm__ __volatile__ ( "vzeroupper" : : : ); 

清洁AVX寄存器的上半部分。我认为您无法使用诸如_mm256_zeroupper之类的固有信息来解决此问题,因为GCC会说它是SSE代码并且无法识别固有的。选项-mvzeroupper也无法使用,因为GCC One再次认为它是SSE代码,并且不会发出vzeroupper指令。

顺便说一句,硬件有这个问题是微软的错。


更新:

其他人显然在Skylake上遇到了这个问题。在printfmemsetclock_gettime

之后已观察到它

如果您的目标是将128位操作与256位操作进行比较,则可以考虑使用-mprefer-avx128 -mavx(在AMD上特别有用)。但是,您将比较AVX256与AVX128,而不是AVX256与SSE。AVX128和SSE都使用128位操作,但它们的实现不同。如果您基准测试您使用的是您使用的。

最新更新