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

介绍AVX

​ AVX就是Intel提供的支持向量并行计算的C语言的一个库,所有的东西都在<immintrin.h>中.这个库跟正常的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 <immintrin.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <sys/time.h>
#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;
}

运行结果
12345均值
AVX实现加法(单位um)623135475653761542815879356780.8
普通数组实现(单位um)13620212410176384113546126127115272.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微秒.

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
计算高维向量距离可以使用以下方法: 1. 欧几里得距离(Euclidean Distance):是最常用的距离度量方法,计算两个向量之间的欧几里得距离是将两个向量中每个对应的元素相减并平方,然后将所有结果相加,并对和进行平方根运算。即:d(x,y) = sqrt(sum(xi-yi)^2)。 2. 曼哈顿距离(Manhattan Distance):也称为城市街区距离,计算两个向量之间的曼哈顿距离是将两个向量中每个对应的元素相减并取绝对值,然后将所有结果相加。即:d(x,y) = sum(abs(xi-yi))。 3. 切比雪夫距离(Chebyshev Distance):计算两个向量之间的切比雪夫距离是将两个向量中每个对应的元素相减并取绝对值,然后选择其中的最大值。即:d(x,y) = max(abs(xi-yi))。 4. 闵可夫斯基距离(Minkowski Distance):是欧几里得距离和曼哈顿距离的一般化,当p=2时,就是欧几里得距离,当p=1时,就是曼哈顿距离。即:d(x,y) = (sum(abs(xi-yi)^p))^(1/p)。 5. 余弦相似度(Cosine Similarity):计算两个向量之间的余弦相似度是将两个向量进行内积运算,然后除以两个向量的模长的乘积。即:sim(x,y) = (x·y)/(||x||·||y||)。 其中,欧几里得距离和曼哈顿距离适用于连续性的特征向量,切比雪夫距离适用于离散性的特征向量,闵可夫斯基距离可以适用于连续性和离散性的特征向量,而余弦相似度则适用于文本分类等应用场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值