AVX就是Intel提供的支持向量并行计算的C语言的一个库,所有的东西都在
gcc filename.c -mavx -mavx2 -mfma -msse -msse2 -msse3
还有一点需要说明AVX可以支持Intel的CPU也可以支持AMD的CPU,其实小编的CPU就是AMD的.
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微秒.