使用simd指令、openmp分别对向量规约,或者累加进行加速

 普通的累加

float accumulation(float* a, int len)
{
    float sum = 0;
    for (int i = 0; i < len; i++)
    {
        sum += a[i];
    }
    return sum;
}

假如了simd指令如下:

float accumulation_simd(float* a, int len)
{
    //定义两个128bit的寄存器,每个寄存器可以装4个32bit数据
    float32x4_t a_, b_;

    //vdupq_n_f32是设置一个val=0的float32x4_t 的数据,里面含有四个为0 float 的数据
    a_ = vdupq_n_f32(0.0);
    
    //128bit寄存器可以装4个32bit数,所以i+=4,一次性处理了4个数据;
    for (int i = 0; i < len/4*4; i+=4)
    {
        //向b_中加载4个数据
        b_ = vld1q_f32(a+i);

        //把b_累加到a_里面
        a_ = vaddq_f32(a_, b_);
    }

    float sum = 0.0;
    //我们把四个通道的数据依次累加到sum里面,主体的累加做完
    sum = vgetq_lane_f32(a, 0)+vgetq_lane_f32(a, 1)+vgetq_lane_f32(a, 2)+vgetq_lane_f32(a, 3);
    
    //不足4个数据的尾巴,则在最后单独累加到sum里面
    for (; i < len; i++)
    {
        sum += a[i];
    }
    return sum;
}

这里面,我们要了解这几个指令, vdupq_n_f32、vld1q_f32、vaddq_f32、vgetq_lane_f32。

vdupq_n_f32(0),返回出一个全是0的float32x4_t 的数据。

vld1q_f32(*ptr),从指针后面依次取四个float32数据,返回一个float32x4_t 数据。

vaddq_f32(float32x4_t , float32x4_t ),输入两个float32x4_t 数据,返回各个位置相加的一个float32x4_t 数据。

vgetq_lane_f32(float32x4_t ,lane)返回第lane个float32的数据。

具体大家可以参考这个网址,有十分详细的接口说明。Intrinsics – Arm Developer

以下是使用openmp进行加速:

float accumulation_openmp(float* a, int len)
{
    float sum;

    pragma omp parallel for reduction(+: sum) 

    for (int i = 0; i < len; i++)
    {
        sum += a[i];
    }
    
}

总的来说,还是比较简单的,openmp的使用是比较简单的,只需要加上#pragma omp parallel for reduction(+: sum) 这行,就会对最近的一个for循环进行规约操作,具体详细的的应用可以参照这篇博客,是比较适合初学者阅读的。OpenMP用法大全(个人整理版)_ArrowYL的博客-CSDN博客_openmp

博主下一篇会介绍一下怎么把openmp和simd结合起来加速。

下面是使用SIMD指令加速warpAffine带参数WARP_INVERSE_MAP例程的C++代码: ```c++ #include <opencv2/opencv.hpp> #include <emmintrin.h> using namespace cv; void warpAffineInverseMap(const Mat& src, Mat& dst, const Mat& M) { CV_Assert(M.rows == 2 && M.cols == 3); dst.create(src.size(), src.type()); int width = src.cols; int height = src.rows; int channels = src.channels(); int step = src.step; int dst_step = dst.step; float* src_data = (float*)src.data; float* dst_data = (float*)dst.data; __m128 m0 = _mm_set1_ps(M.at<double>(0, 0)); __m128 m1 = _mm_set1_ps(M.at<double>(1, 0)); __m128 m2 = _mm_set1_ps(M.at<double>(0, 1)); __m128 m3 = _mm_set1_ps(M.at<double>(1, 1)); __m128 m4 = _mm_set1_ps(M.at<double>(0, 2)); __m128 m5 = _mm_set1_ps(M.at<double>(1, 2)); for (int y = 0; y < height; ++y) { const float* src_row = src_data + y * step; float* dst_row = dst_data + y * dst_step; for (int x = 0; x < width; x += 4) { __m128 fx = _mm_set_ps((float)(x + 3), (float)(x + 2), (float)(x + 1), (float)x); __m128 fy = _mm_set1_ps((float)y); __m128 mx = _mm_add_ps(_mm_mul_ps(fx, m0), _mm_mul_ps(fy, m2)); __m128 my = _mm_add_ps(_mm_mul_ps(fx, m1), _mm_mul_ps(fy, m3)); __m128 mz = _mm_add_ps(_mm_add_ps(_mm_mul_ps(fx, m4), _mm_mul_ps(fy, m5)), _mm_set1_ps(1.0f)); __m128 rmx = _mm_div_ps(_mm_set1_ps(1.0f), mz); __m128 fx2 = _mm_mul_ps(mx, rmx); __m128 fy2 = _mm_mul_ps(my, rmx); __m128i ix = _mm_cvtps_epi32(fx2); __m128i iy = _mm_cvtps_epi32(fy2); __m128 fx3 = _mm_sub_ps(fx2, _mm_cvtepi32_ps(ix)); __m128 fy3 = _mm_sub_ps(fy2, _mm_cvtepi32_ps(iy)); __m128 w0 = _mm_mul_ps(_mm_sub_ps(_mm_set1_ps(1.0f), fx3), _mm_sub_ps(_mm_set1_ps(1.0f), fy3)); __m128 w1 = _mm_mul_ps(fx3, _mm_sub_ps(_mm_set1_ps(1.0f), fy3)); __m128 w2 = _mm_mul_ps(_mm_sub_ps(_mm_set1_ps(1.0f), fx3), fy3); __m128 w3 = _mm_mul_ps(fx3, fy3); __m128i i00 = _mm_add_epi32(_mm_mullo_epi32(iy, _mm_set1_epi32(step)), _mm_mullo_epi32(ix, _mm_set1_epi32(channels))); __m128i i10 = _mm_add_epi32(i00, _mm_set1_epi32(channels)); __m128i i01 = _mm_add_epi32(i00, _mm_set1_epi32(step)); __m128i i11 = _mm_add_epi32(i01, _mm_set1_epi32(channels)); __m128 v00 = _mm_loadu_ps(src_row + _mm_extract_epi32(i00, 0)); __m128 v10 = _mm_loadu_ps(src_row + _mm_extract_epi32(i10, 0)); __m128 v01 = _mm_loadu_ps(src_row + _mm_extract_epi32(i01, 0)); __m128 v11 = _mm_loadu_ps(src_row + _mm_extract_epi32(i11, 0)); __m128 v0 = _mm_add_ps(_mm_mul_ps(v00, w0), _mm_mul_ps(v10, w1)); __m128 v1 = _mm_add_ps(_mm_mul_ps(v01, w2), _mm_mul_ps(v11, w3)); __m128 v = _mm_add_ps(v0, v1); _mm_storeu_ps(dst_row + x, v); } } } ``` 这个函数使用了SSE指令集,可以大幅提高warpAffineInverseMap函数的速度。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值