普通的累加
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结合起来加速。