向量化
Contents
向量化
http://blog.csdn.net/gengshenghong/article/details/7027186
参考手册:
说明: 本系列文章为个人笔记,如有不正确之处,请参考官方相关文档,如果错误发现,我会尽量更新修改。另外,以下内容不保证对于所有版本的编译器都正确,编译器的实现也可能有一些变化之处,具体参考官方文档。
更多说明请参考http://blog.csdn.net/gengshenghong/article/details/7034748中补充说明部分。
Summary:
Intel编译器提供了自动向量化的功能,能对程序进行一些自动的向量化优化。
(1)什么是向量化
所谓的向量化,简单理解,就是使用高级的向量化SIMD指令 (如SSE、SSE2等) 优化程序,属于数据并行的范畴。
更多理解,参考:
http://blog.csdn.net/gengshenghong/article/details/6953942
http://blog.csdn.net/gengshenghong/article/details/7007100
等。
(2)如何对代码进行向量化?
知道了向量化的目标是生成SIMD指令, 那么很显然, 要对代码进行向量化, 第一是依靠编译器来生成这些指令;第二是使用汇编或 Intrinsics 函数。Intel 编译器中, 利用其自动向量分析器 (auto-vectorizer) 对代码进行分析并生成SIMD指令。另外, 也会提供一些 pragmas 等方式使得用户能更好的处理代码来帮助编译器进行向量化。
编译器的自动向量化,简单理解,就是编译器对代码进行一些处理从而生成SIMD指令,一个最常见的可以进行向量化的例子就是for循环,这里简单的理解一下,如下代码片段:
#define N 4*10
float a[N], b[N], c[N];
for(int i = 0;i < N; i ++)
{
a[i] = b[i] + c[i];
}
对于上面的代码,假设float类型是4byte,即32bit。如果使用"传统"的指令,这个for循环至少需要经过40次浮点加法运算。那么,如果使用SSE指令 (128bit暂存器) ,那么一条指令能同事计算4个float,所以,上面的for循环可以只适用10次浮点加法运算就完成了。
说明: 这里只是简单说明一下向量化和SSE等指令集之间的关系,关于SIMD、SSE等的细节参考相关内容 (比如,SSE指令要求内存对齐等,后面向量化也会涉及到这一点)
(3)自动向量化的选项和基本使用
- 基本向量化
/Qvec: 开启自动向量化功能,需要在O2以上使用。在O2以上,这是默认的向量化选项,默认开启的。此选项生成的代码能用于Intel处理器和非Intel处理器。向量化还可能受其他选项影响。由于此选项是默认开启的,所以不需要在命令行增加此选项。
/Qvec-reportn: 输出向量化报告。n取值为0到5.
- 针对指令集 (处理器) 的向量化
/arch:code: 其中code表示指令集,比如IA32、SSE、SSE2、SSE3、SSSE3等等。后面的指令集一般是前面的指令集的扩展,比如,使用SSE3的时候,那么生成的代码会使用到IA32、SSE、SSE2和SSE3的指令。由于是针对指令集的优化,所以其生成的代码只能运行在支持相应指令集的处理器上。默认的是code使用的是SSE2。
/Qxcode: 其中code也是表示指令集,其取值类似于arch (不完全一样) ,但是/Qx选项生成的代码只能运行在Intel处理器上,它会使用Intel处理器的指令进行更进一步的优化。说明: /arch选择可以运行在兼容这些指令集的非Intel处理器上,/Qx只能运行在Intel处理器上,因为并不是所有的兼容同一指令集的处理器都能兼容所有的指令的。
/QxHost: 针对当前使用的主机处理器选择最优的指令集优化。
(4)向量化编程相关
- 编程指南:
来自于上面的参考文档原文:
Use:
•straight-line code (a single basic block)
•vector data only; that is, arrays and invariant expressions on the right hand side of assignments. Array references can appear on the left hand side of assignments.
•only assignment statements
Avoid:
•function calls (other than math library calls)
•unvectorizable operations (either because the loop cannot be vectorized, or because an operation is emulated through a number of instructions)
•mixing vectorizable types in the same loop (leads to lower resource utilization)
•data-dependent loop exit conditions (leads to loss of vectorization
you should avoid these common changes
•loop unrolling; the compiler does it automatically.
•decomposing one loop with several statements in the body into several single-statement loops
- 影响向量化的因素
影响向量化的两大因素是硬件和代码风格。硬件来说,首先当然是指令集是否支持,这是直接影响向量化能否进行的,另外,还有和内存对齐相关的问题,也是影响向量化的,很多的SSE指令都要求内存是16字节对齐,如果不对齐,向量化会得到错误结果。代码风格来说,循环结构内的代码的风格会影响编译器的判断,特别有有些代码存在"歧义”,编译器无法确定用户的真实意图,就不得不放弃优化。对于这类问题,当然,一个可行的方法是使用前面的GAP功能来给出建议,对代码进行修改。
java -XX:-UseSuperWord
Author -
LastMod 2017-08-15