向量化

http://blog.csdn.net/gengshenghong/article/details/7027186

参考手册:

http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011Update/compiler_c/index.htm

说明: 本系列文章为个人笔记,如有不正确之处,请参考官方相关文档,如果错误发现,我会尽量更新修改。另外,以下内容不保证对于所有版本的编译器都正确,编译器的实现也可能有一些变化之处,具体参考官方文档。

更多说明请参考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)自动向量化的选项和基本使用

  1. 基本向量化

/Qvec: 开启自动向量化功能,需要在O2以上使用。在O2以上,这是默认的向量化选项,默认开启的。此选项生成的代码能用于Intel处理器和非Intel处理器。向量化还可能受其他选项影响。由于此选项是默认开启的,所以不需要在命令行增加此选项。

/Qvec-reportn: 输出向量化报告。n取值为0到5.

  1. 针对指令集 (处理器) 的向量化

/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)向量化编程相关

  1. 编程指南:

来自于上面的参考文档原文:

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

  1. 影响向量化的因素

影响向量化的两大因素是硬件和代码风格。硬件来说,首先当然是指令集是否支持,这是直接影响向量化能否进行的,另外,还有和内存对齐相关的问题,也是影响向量化的,很多的SSE指令都要求内存是16字节对齐,如果不对齐,向量化会得到错误结果。代码风格来说,循环结构内的代码的风格会影响编译器的判断,特别有有些代码存在"歧义”,编译器无法确定用户的真实意图,就不得不放弃优化。对于这类问题,当然,一个可行的方法是使用前面的GAP功能来给出建议,对代码进行修改。

java -XX:-UseSuperWord

https://www.zhihu.com/question/50183397

http://www.infoq.com/cn/articles/x86-high-performance-programming-annotations-part01?utm_campaign=infoq_content&utm_source=infoq&utm_medium=feed&utm_term=global