正常的向量加如下:
void add(int8_t* a, int8_t* b, int8_t* c, int len)
{
for (int i = 0; i < len; i++)
{
c[i] = a[i]+b[i]
}
}
此时,我们可以使用neon这个库,去进行simd优化,但是neon只能在arm平台上运行,不能在x86平台上运行。
void add_simd(int8_t* a, int8_t* b, int8_t* c, int len)
{
//定义三个128bit寄存器;
int8x16_t a_, b_, c_;
//主体部分,以16循环
for (int i = 0; i < len/16*16; i+=16)
{
//128bit寄存器可以装16个8bit数,所以i+=16,一次性处理了16个数据;
a_ = vld1q_s8(a+i);
b_ = vld1q_s8(b+i);
//一次性对16个数进行加法
c_ = vaddq_s8(a_, b_);
//把16个8bit数一次性放回指针c里面;
vst1q_s8(c+i, c_);
}
//处理尾巴,剩下的不足16的单独处理
for (; i < len; i++)
{
c[i] = a[i] + b[i];
}
}
这时候就完成了simd级别的加速优化,主要是几个neon指令,vld1q_s8、vaddq_s8、vst1q_s8,具体可以在这里查看。
接下来我们进行并行化,主要是利用openmp库进行优化,具体如下:
void add_simd(int8_t* a, int8_t* b, int8_t* c, int len)
{
int8x16_t a_, b_, c_;
//openmp使用起来还是比较简单的,只需要加上这句话,他就可以对最近的一个for循环进行并行化。
#pragma omp parallel for
for (int i = 0; i < len/16*16; i+=16)
{
a_ = vld1q_s8(a+i);
b_ = vld1q_s8(b+i);
c_ = vaddq_s8(a_, b_);
vst1q_s8(c+i, c_);
}
for (; i < len; i++)
{
c[i] = a[i] + b[i];
}
}
具体详细的的应用可以参照这篇博客,是比较适合初学者阅读的。OpenMP用法大全(个人整理版)_ArrowYL的博客-CSDN博客_openmp
本只是简单的做了int8_t加法,其他数据类型类似,本展示一些其他数据类型代码如下:
void add_simd(float* a, float* b, float* c, int len)
{
float32x4_t a_, b_, c_;
#pragma omp parallel for
//这里特别要注意,此处以4为循环,因为128bit寄存器只能一次性处理4个32bit数,所以一次性只能处理4个数据。
for (int i = 0; i < len/4*4; i+=4)
{
a_ = vld1q_f32(a+i);
b_ = vld1q_f32(b+i);
c_ = vaddq_f32(a_, b_);
vst1q_f32(c+i, c_);
}
for (; i < len; i++)
{
c[i] = a[i] + b[i];
}
}