Cilk_for和#pragma SIMD的区别和使用说明(1)

Cilk提供三个Cilk关键字表明那些代码能并行执行任务,他们是_Cilk_spawn, _Cilk_sync和_Cilk_for(或cilk_for,如果程序包含了cilk.h文件)。

Cilk_for表示一个循环包含的迭代可以被并行执行。通常它是指出一个循环允许不同的循环间隔并行运行;它是正常C/C++ for循环的替代者;这个说明将循环分解成若干个包含一个或者多个循环间隔的块。每一个块串行执行,并且在循环的执行过程中被衍生成块。

其语法规则如下:

                   Cilk_for (declaration; conditional expression; increment expression) body

Cilk 运行环境将一个cilk_for循环转换成对循环迭代的有效的分而治之的递归往复。Cilk_for循环样例包括:

                   Cilk_for (int I = begin; I < end; I += 2) f(i);

                   Cilk_for( T::iterator i(vec.begin()); I !=vec.end(); ++i) g(i);

一个合法的Cilk程序的串行化和相似的C/C++程序有相同的行为,而cilk_for的串行化就是将cilk_for换成for的结果。因此,一个cilk_for的循环必须是一个合法的C/C++ for循环,但是cilk_for循环有比C/C++的for 循环有更多的限制。因为循环体要并行执行,就必须修改控制变量而不是修改一个非本地变量,那样的话将导致数据竞争。Cilk常用reducer来防止竞争。

#pragma SIMD 是由C++和Fortran语言(这里用C++为例说明)支持的语言指示特性;它能更有效地使代码向量化执行。通常#pragma simd将强制性地对内循环进行向量化。你需要对一个循环添加#pragma指示标志,然后使用新的变异选项 -Qsimd(在MS Window) -simd(在Linux* OS)重新编译源代码。下面是一个小例子:

[D:/simd] cat example1.c

void add_floats(float *a, float *b, float *c, float *d, float *e, int n){

int i;

for (i=0; i<n; i++){

a[i] = a[i] + b[i] + c[i] + d[i] + e[i];

}

}

[D:/simd] icl example1.c -nologo -Qvec-report2

example1.c

D:\simd\example1.c(3): (col. 3) remark: loop was not vectorized: existence of vector dependence.

[D:/simd] cat example1.c

void add_floats(float *a, float *b, float *c, float *d, float *e, int n){

int i;

#pragma simd

for (i=0; i<n; i++){

a[i] = a[i] + b[i] + c[i] + d[i] + e[i];

}

}

[D:/simd] icl example1.c -nologo -Qvec-report2 -Qsimd

example1.c

D:\simd\example1.c(4): (col. 3) remark: LOOP WAS VECTORIZED.



由此可见Cilk_for和#pragma SIMD是针对C/C++ for 语句使用不同的策略进行并行化的方法;一个是使for 语句向量化,一个是使for语句并行化执行。所以,我们不能对同一条for 语句即进行cilk_for并行化又进行#pragma SIMD向量化。



续篇我将对上述两种方法的具体细节进行描述。

Para obter informações mais completas sobre otimizações do compilador, consulte nosso aviso de otimização.