高性能计算学习笔记(二)

SIMD性能优化

什么是SIMD?

在字长为32位的常规处理器中,其算术逻辑单元、寄存器和数据通路都是为了32的计算设计的。因此,用一次操作得出一个结果的方式来处理8位或者16位元素的大数据集效率是极低的,对资源的浪费也是很严重的。SIMD能够将寄存器中的数据划分为多个元素,然后再对这些元素同时进行操作。
基于这个理念,ARM NEON技术设计孕育而出,主要用于加速高级多媒体、信号处理应用、嵌入式系统的处理过程。NEON包括一个全面的指令集,一个单独的寄存器配置文件和独立的执行硬件。相对较旧的寄存器支持8位、16位、32位及64位的整型数和单精度浮点数(32位),最新的处理器增加了寄存器的数量,加强了对浮点数的支持,目前可以支持双精度浮点数(64位)和完整的IEEE754操作。

向量化操作示例

假设一个数组内存放有若干元素值,向量化之后可以一次性将数组内的值根据向量长度一次性加载出来,进行求和操作,从而达到加速程序的效果。
高性能计算学习笔记(二)_第1张图片
ARM Neon向量化后代码示例

#include 

float vsum( float *v, int n){
	float32x4_t vs, vv;
	float s=0.0;
	int i;
	vs=vdupq_n_f32(0.0);
	for( i=0; i<n-4; i+=4){
		vv = vld1q_f32(&v [i] );
		vs += vv;
	}
	s=vs [0]+vs[1]+vs [2]+vs [3];
	for( ; i<n; i++){
		s+=v [i];
	}
	return s;
}

ARM Neon Intrinsic常用函数

函数 功能
vdupq_n_f32(float32_t value) 初始化value值为0.0
vld1q_f32(float32_t const *ptr) 读取内存,将指针ptr所指地址的值加载给返回值
vst1q_f32(float32_t const *ptr,float32x4_t val) 写入内存,将val的值写入指针ptr所指的内存地址中
vaddq_f32(float32x4_t a,float32x4_t b) 向量加法,进行a+b操作,返回对应类型的值
vmulq_f32(float32x4_t a,float32x4_t b) 向量乘法,进行a*b操作,返回对应类型的值
vfmaq_f32(float32x4_t a,float32x4_t b,float32x4_t c) 向量乘加计算,进行a+b*c操作,返回对应类型的值

编译器自动向量化

使用 -ftree-loop-vetorize、-ftree-slp-vectorize、-ftree-vectorize编译选项能让常规代码在编译后自动向量化。

  • -ftree-loop-vetorize可实现循环的向量化,与-ftree-vectorize一起连用。
  • -ftree-slp-vectorize可实现基本块的向量化,实现串行代码中的自动向量化,与-ftree-vectorize一起连用。
    同时还可以通过-fdump-tree-vect编译选项来生成编译器向量化的过程文件,找出程序代码中被向量化和未被向量化的基本代码块,从而可以快速定位需要手动向量化的代码块。

SIMD编译指导语句

1.omp simd(用于细粒度的循环体)

#pragma omp simd

2.子句:

  • collapse(n) 将多层(紧嵌套)循环的空间的迭代空间合并,扁平化成单层循环,再对其向量化,参数n指明合并的循环的层数
  • private(list) 将list中的变量私有化
  • reduction(reduction-identifier:list) 规约操作 +,-,*,&,|,^,&&,||
  • safelen(length) 指定向量依赖项的最大距离
  • simdlen(length) 指定向量通道数
#pragma omp simd safelen(4)
{
	for(int i=0;i<(N-4);i++){
		a[i] = a[i+4] + b[i] * c[i];
	}
}

NEON向量类型格式

<type><size>x<lanes>_t
<type>数据类型
<size>数据大小
<lanes>通道数

高性能计算学习笔记(二)_第2张图片

NEON内联函数命名规则

高性能计算学习笔记(二)_第3张图片

'v' 指明是vector向量指令,也就是NEON指令
'q' 指明是饱和指令,即后续的加法结果会自动饱和
'add' 指明是加法指令
'q' 指明操作寄存器宽度,为q时操作Q类寄存器,为128位
's16' 指明操作的基本单元位有符号16位整数,其最大表示范围为-32768~32767
<mod> 分别有q、h、d、r、p这五种模式
q表明饱和计算,算术操作发生溢出时,其结果自动为最大值或最小值
h表明减半操作
d表明double计算
r表明舍入计算,向右移位一位操作
p表明相邻元素求和操作
<operate>具体操作
加载:将数据从内存加载到寄存器,如ld
存储:将数据从寄存器转移到内存,如st
加/减法:c=a+b,如add,sub
乘/乘加法:c=a*b+d,如mul, mla, mls
逻辑判断:>,<,与或非,如eq,gt,and,or
位移
类型转换
标量填充:初始化向量,如dup

你可能感兴趣的:(学习,性能优化)