AVX入门-并行计算高维向量

介绍AVX

​ AVX就是Intel提供的支持向量并行计算的C语言的一个库,所有的东西都在中.这个库跟正常的C标准库差不多.需要注意的是在编译AVX的时候一定要加编译参数-mavx和-mavx2.一般来说用到AVX的时候还会用到AVX的祖先SSE因此SSE的编译参数也要加上.用gcc编译的指令如下

gcc filename.c -mavx -mavx2 -mfma -msse -msse2 -msse3

​ 还有一点需要说明AVX可以支持Intel的CPU也可以支持AMD的CPU,其实小编的CPU就是AMD的.

AVX入门

​ AVX入门也就是教你怎么声明变量在这里提供一个中文的详细的介绍.还用一个github上面的代码示范

高维向量加法

目的

​ 测试计算 1 0 7 10^7 107维的向量加法使用AVX和普通for循环的速度差异

​ 实验测试的数据类型为双精度浮点数double类型,两个向量由 1 0 7 10^7 107个double类型数据组成.

代码:废话少说,上码

#include 
#include 
#include 
#include 
#include 
#define __VEC_LENGTH__ 10000000

double arr1[__VEC_LENGTH__];
double arr2[__VEC_LENGTH__];
double result[__VEC_LENGTH__];
__m256d vecarr1[__VEC_LENGTH__ / 4];
__m256d vecarr2[__VEC_LENGTH__ / 4];
__m256d temp[__VEC_LENGTH__ / 4];

//使用AVX计算10^7维向量加法,并返回i计算时间
long sum_avx(double *arr1, double *arr2, double *result);
//使用for循环计算向量加法,并返回计算时间
long sum_arr(double *arr1, double *arr2, double *result);

int main()
{
    srand(time(NULL));
    for(int i = 0; i < __VEC_LENGTH__; ++i)
    {
        arr1[i] = rand() / 1000;
        arr2[i] = rand() / 1000;
    }

    clock_t time1 = sum_avx(arr1, arr2, result);
    printf("Using avx takes %ld us\n",time1);
    clock_t time2 = sum_arr(arr1, arr2, result);
    printf("Using for loop takes %ld us\n", time2);

    return 0;
}

​ 以上是main函数和测试速度函数的签名,接下来定义定义两个测试速度的函数

long sum_avx(double *arr1, double *arr2, double *result)
{
    //数据转换为AVX向量
    for(int i = 0; i < __VEC_LENGTH__; i += 4)
    {
        vecarr1[i / 4] = _mm256_setr_pd(arr1[i], arr1[i + 1], arr1[i + 2], arr1[i + 3]);
        vecarr2[i / 4] = _mm256_setr_pd(arr2[i], arr2[i + 1], arr2[i + 2], arr2[i + 3]);
    }
	
    //测试的时间仅包括AVX向量加法的时间
    struct timeval tv1, tv2;
    gettimeofday(&tv1, NULL);
    for(int i = 0; i < __VEC_LENGTH__ / 4; ++i)
    {
        temp[i] = _mm256_add_pd(vecarr1[i], vecarr2[i]);
    }
    gettimeofday(&tv2, NULL);
	
    //数据转换为结果
    for(int i = 0; i < __VEC_LENGTH__ / 4; ++i)
    {
        result[i * 4] = temp[i][0];
        result[i * 4 + 1] = temp[i][1];
        result[i * 4 + 2] = temp[i][2];
        result[i * 4 + 3] = temp[i][3];
    }

    return (tv2.tv_sec - tv1.tv_sec) * 1000000 + tv2.tv_usec - tv1.tv_usec;
}

long sum_arr(double *arr1, double *arr2, double *result)
{
    struct timeval tv1, tv2;
    gettimeofday(&tv1, NULL);
    for(int i = 0; i < __VEC_LENGTH__; ++i)
    {
        result[i] = arr1[i] + arr2[i];
    }
    gettimeofday(&tv2, NULL);
    return (tv2.tv_sec - tv1.tv_sec) * 1000000 + tv2.tv_usec - tv1.tv_usec;
}

运行结果

1 2 3 4 5 均值
AVX实现加法(单位um) 62313 54756 53761 54281 58793 56780.8
普通数组实现(单位um) 136202 124101 76384 113546 126127 115272.0

可以得到最终加速比为2.03.之前再WSL系统上用clock获得的时间感觉特别不准,后来用gettimeofday再Windows上重新测了一遍,更新了这里的数据.

测试速度讨论

​ 在实际测试过程中部分时钟周期花费在将数组转换成AVX向量上,这部分时间不计入测试.对于使用AVX实现向量相加的程序,真正计入测试的时间只包括12500个4维double向量相加的时间.对于使用正常数组实现向量相加的程序,计入测试时间的部分也只有 1 0 7 10^7 107个double相加的时间.

​ 之所以对AVX忽略数据转换的时间是因为,在实际编程过程中整个程序可能都是AVX向量表示,不需要把普通数组转换成AVX的向量;对比多线程编程,只要使用多线程就一定要计算多线程声明初始化的时间,因此计算多线程的运行时间一定要把初始化的时间计算进去.

​ 测试的时间单位为 μ s \mu s μs微秒.

你可能感兴趣的:(AVX入门-并行计算高维向量)