夏霏 2009.12

27
2009.12

Upload: osman

Post on 05-Jan-2016

58 views

Category:

Documents


0 download

DESCRIPTION

OpenMP 范例. OpenMP 范例. 夏霏 2009.12. ?. 1. 3. 2. OpenMP. Why OpenMP. CPU 核数扩展性. 方便性. 可移植性. OpenMP 例子. 反依赖的消除 循环依赖的消除 OpenMP 实现流水线. 反依赖的例子. int V[ VSIZE+1 ],i,U[VSIZE+1]; for (i=0; i

TRANSCRIPT

Page 1: 夏霏 2009.12

夏霏2009.12

Page 2: 夏霏 2009.12

Why OpenMP

1

CPU 核数扩展性

3

可移植性

2

方便性

OpenMP

Page 3: 夏霏 2009.12

OpenMP 例子

• 反依赖的消除

• 循环依赖的消除

• OpenMP 实现流水线

Page 4: 夏霏 2009.12

反依赖的例子 int V[ VSIZE+1 ],i,U[VSIZE+1];

for (i=0; i<VSIZE+1; i++) {

V[i]= i ;

U[i] = i ;

}

for(i=0;i<VSIZE;i++) U[i] = U[i] + U[i+1];

omp_set_num_threads(NUM_THREADS);

#pragma omp parallel for default(none) shared(V) private(i) schedule(static)

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

V[i] = V[i] + V[i+1];}

Page 5: 夏霏 2009.12

parallel forOpenMP 指令使用的格式为 # pragma omp 指令 [ 子句 [ 子句 ]…]

parallel for 就是一条指令,“指令” = “ 编译指导语句” private 子句

#pragma omp directive-name [clause, ...] newline

制导指令前缀。对所有的OpenMP 语句都需要这样的前缀。

OpenMP 制导指令。在制导指令前缀和子句之间必须有一个正确的 OpenMP 制导指令。

子句。在没有其它约束条件下,子句可以无序,也可以任意的选择。 这一部分也可以没有。

换行符。表明这条制导语句的终止。

Page 6: 夏霏 2009.12

parallel forparallel 指令的用法

parallel 是用来构造一个并行块的,也可以使用其他指令如 for 、 sections 等和它配合使用。

#pragma omp parallel [for | sections] [ 子句 [ 子句 ]…]

{

// 代码}

Page 7: 夏霏 2009.12

parallel forfor 指令的使用方法

for 指令则是用来将一个 for 循环分配到多个线程中执行。 for 指令一般可以和 parallel 指令合起来形成 parallel for 指令使用,也可以单独用在 parallel 语句的并行块中。

#pragma omp [parallel] for [ 子句 ]

for 循环语句

Page 8: 夏霏 2009.12

parallel for• parallel ,用在一个代码段之前,表示这段代码将被多

个线程并行执行

• for ,用于 for 循环之前,将循环分配到多个线程中并行执行,必须保证每次循环之间无相关性。

• parallel for , parallel 和 for 语句的结合,也是用在一个 for 循环之前,表示 for 循环的代码将被多个线程并行执行。 – SIMD

Page 9: 夏霏 2009.12

反依赖的例子"badloop.c "

int V[ VSIZE+1 ],i,U[VSIZE+1];

for (i=0; i<VSIZE+1; i++) {

V[i]= i ;

U[i] = i ;

}

for(i=0;i<VSIZE;i++) U[i] = U[i] + U[i+1];

omp_set_num_threads(NUM_THREADS);

#pragma omp parallel for default(none) shared(V) private(i) schedule(static)

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

V[i] = V[i] + V[i+1]; // 先读后写的反依赖关系}

Page 10: 夏霏 2009.12

反依赖处理 1

Parallelizing an inner loop with dependences

Backward dependency

for (i=0; i<size-1; i++) {

V[i] = V[i]+V[i+1];

}

Method: Eliminate dependences by duplicating data

Optimization: None, duplicate the full data

对引起反依赖关系的 V[i+1] 采用了数据冗余的作法,引入oldV 数组,从而解决先读后写的反依赖关系。

Page 11: 夏霏 2009.12

反依赖处理 1"loopA1.c"

#pragma omp parallel for default(none) shared(V,oldV) private(i) schedule(static)

for (i=0; i<VSIZE; i++) {oldV[i] = V[i] ;}

#pragma omp parallel for default(none) shared(V,oldV) private(i) schedule(static)

for (i=0; i<VSIZE-1; i++) {V[i] = V[i]+oldV[i+1];}

Page 12: 夏霏 2009.12

反依赖处理 2

• 采用的边界范围 limitL 和 limitR ,以及边界值 border ;首先,各线程读取各自的border (编号最大的一个线程出外),然后同步。

• 接着,各线程独立更新 limitL ~ limitR – 1 范围内的值,再更新 limitR 的值;再次同步!

Page 13: 夏霏 2009.12

反依赖处理 2"loopA2.c"

#pragma omp parallel default(none) shared(V,size) private(id,LimitL,LimitR,border,i)

{

id = omp_get_thread_num();

LimitL = id*size;LimitR = (id+1)*size-1; // 确定边界

if (id != THREADS_NUM-1) border = V[LimitR+1];

#pragma omp barrier

...

Page 14: 夏霏 2009.12

反依赖处理 2

... ...

for (i=LimitL; i<LimitR; i++) {

V[i] = V[i] + V[i+1];

}

if (id != THREADS_NUM-1)

V[LimitR] = V[LimitR] + border ;

#pragma omp barrier

barrier ,用于并行区内代码的线程同步,所有线程执行到 barrier 时要停止,直到所有线程都执行到 barrier 时才继续往下执行。

Page 15: 夏霏 2009.12

OpenMP 例子

• 反依赖的消除

• 循环依赖的消除

• OpenMP 实现流水线

Page 16: 夏霏 2009.12

循环分布变换的例子"dis-err.c"

int a[Iter],b[Iter],c[Iter],d[Iter],f[Iter];

int a1[Iter],b1[Iter],c1[Iter],d1[Iter],f1[Iter];

for(i=0;i<Iter;i++) a[i] = b[i] = c[i] = d[i] = f[i] =i;

for(i=0;i<Iter;i++) a1[i] = b1[i] = c1[i] = d1[i] = f1[i] =i;

Page 17: 夏霏 2009.12

循环分布变换的例子 for(i=4;i<Iter-1;i++){

a1[ i ] = b1[ i-2 ] + 1; c1[ i ] = b1[ i-1 ] + f1[ i ]; b1[ i ] = a1[ i-1 ] + 2; d1[ i ] = d1[ i+1] + b1[ i-1]; }

#pragma omp parallel for shared(a,b,c,d,f) private(i) for(i=4;i<Iter-1;i++){

a[ i ] = b[ i-2 ] + 1; c[ i ] = b[ i-1 ] + f [ i ]; b[ i ] = a[ i-1 ] + 2; d[ i ] = d[ i+1 ] + b[ i-1 ]; } //ERROR

Page 18: 夏霏 2009.12

循环分布变换的例子

• "dis-ok1.c"– S1: a[ i ] = b[ i-2] + 1;– S2: c[ i ] = b[ i-1] + f[ i ]; – S3: b[ i ] = a[ i-1] + 2; – S4: d[ i ] = d[ i+1] + b[ i-1];

• int old_d[Iter]; // duplicating array-d to avoid anti-dependency

Page 19: 夏霏 2009.12

循环分布变换的例子#pragma omp parallel shared(a,b,c,d,old_d,f) private(i){ #pragma omp master for(i=4;i<Iter-1;i++){ a[i] = b[i-2] + 1; // S1 b[i] = a[i-1] + 2; // S3 } // 只有主线程执行循环 S1 和 S3

#pragma omp barrier

/* The Parallel Loop below containing both Statement S2 and S4*/ #pragma omp for for(i=4;i<Iter-1;i++) { c[i] = b[i-1] + f[i] ; // S2 d[i] = old_d[i+1] + b[i-1] ; // S4 } // 消除反依赖后, S2 和 S4 由其他线程并行执行

Page 20: 夏霏 2009.12

OpenMP 例子

• 反依赖的消除

• 循环依赖的消除

• OpenMP 实现流水线

Page 21: 夏霏 2009.12

使用 OpenMP 实现流水线for (iter=0; iter<numiter; iter++)

{for (i=0; i<size-1; i++){

V[i] = f( V[i], V[i – 1 ] ); } }

流依赖! 内层循环无法直接采用 OMP 制导命令来并行化

for (j=0; j<M; j++)

#pragma omp parallel for default(none) shared(V) private(i) schedule(static)

for (i=1; i<N; i++) V[i] = ( V[i] + V[i-1] ) / 2 ; ERROR

Page 22: 夏霏 2009.12

使用 OpenMP 实现流水线鉴于程序的特点,可以施加流水线并行技术。Program a threads pipeline !!并行域,流水线核心:

// Parallel Region // 每个线程进行 M + nthreads 次迭代以完成流水线 M+nthreads-1

1). 拷贝邻居线程的边界数据 border = V[limitL - 1]2). 在更新局部数据前,所有线程同步 barrier

3). 以流水线方式计算局部数据更新3a). 每个线程计算自己的第一个元素的值a[limitL] = ( a[limitL] + border ) / 2;3b). 计算剩余元素的值for (i=limitL+1; i<=limitR; i++) a[i] = ( a[i] + a[i-1] ) / 2;

// 拷贝已更新的边界数据前,所有线程再次同步。之后回到 1)//End of Parallel Region

Page 23: 夏霏 2009.12

使用 OpenMP 实现流水线• M = 2 , nthreads = 3• 黑色表示线程 #0 ,红色表示线程 #1 ,黄色表示线程 #2

Page 24: 夏霏 2009.12

使用 OpenMP 实现流水线以下为实际程序的在 1 、 2 、 4 、 8 个线程下实际运行结果。登录结点 43 后,可以在 rsh 到结点 28 上(可能负荷轻点):

[alex@node28 omp-demo]$ export OMP_NUM_THREADS=1[alex@node28 omp-demo]$ ./pipe 1000000 1000 1 Threads of 1000 iterations with 1000000 elements = 9.445195 (sec)[alex@node28 omp-demo]$ export OMP_NUM_THREADS=2[alex@node28 omp-demo]$ ./pipe 1000000 1000 2 Threads of 1000 iterations with 1000000 elements = 4.814943 (sec)[alex@node28 omp-demo]$ export OMP_NUM_THREADS=4[alex@node28 omp-demo]$ ./pipe 1000000 1000 4 Threads of 1000 iterations with 1000000 elements = 2.571246 (sec)[alex@node28 omp-demo]$ export OMP_NUM_THREADS=8[alex@node28 omp-demo]$ ./pipe 1000000 1000 8 Threads of 1000 iterations with 1000000 elements = 1.176101 (sec)[alex@node28 omp-demo]$

Page 25: 夏霏 2009.12

并行程序设计高性能

计算任务划分 依赖

死锁通讯

Page 26: 夏霏 2009.12

延伸阅读

《多核计算与程序设计》作  者: 周伟明 著出 版 社: 华中科技大学出版社

第三章中关于 OpenMP 相关内容

【 1 】

【 2 】 Barbara Chapman , “ How OpenMP is Compiled ”http://cobweb.ecn.purdue.edu/ParaMount/iwomp2008/documents/chapman-underthehood

Page 27: 夏霏 2009.12

夏霏2009.12