1 / 27

夏霏 2009.12

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<VSIZE+1; i++) { V[i]= i ; U[i] = i ; }

osman
Download Presentation

夏霏 2009.12

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. OpenMP 范例 OpenMP 范例 夏霏 2009.12

  2. 1 3 2 OpenMP Why OpenMP CPU核数扩展性 方便性 可移植性

  3. OpenMP例子 • 反依赖的消除 • 循环依赖的消除 • OpenMP实现流水线

  4. 反依赖的例子 • 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]; • }

  5. parallel for • OpenMP指令使用的格式为 • #pragma omp 指令 [子句[子句]…] • parallel for就是一条指令,“指令” = “编译指导语句” private 子句

  6. parallel for • parallel指令的用法 • parallel 是用来构造一个并行块的,也可以使用其他指令如for、sections等和它配合使用。 • #pragma omp parallel [for | sections] [子句[子句]…] • { • //代码 • }

  7. parallel for • for指令的使用方法 • for指令则是用来将一个for循环分配到多个线程中执行。for指令一般可以和parallel指令合起来形成parallel for指令使用,也可以单独用在parallel语句的并行块中。 • #pragma omp [parallel] for [子句] • for循环语句

  8. parallel for • parallel,用在一个代码段之前,表示这段代码将被多个线程并行执行 • for,用于for循环之前,将循环分配到多个线程中并行执行,必须保证每次循环之间无相关性。 • parallel for,parallel 和 for语句的结合,也是用在一个for循环之前,表示for循环的代码将被多个线程并行执行。 • SIMD

  9. 反依赖的例子 "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]; //先读后写的反依赖关系 }

  10. 反依赖处理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数组,从而解决先读后写的反依赖关系。

  11. 反依赖处理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]; }

  12. 反依赖处理2 • 采用的边界范围limitL和limitR,以及边界值border;首先,各线程读取各自的border(编号最大的一个线程出外),然后同步。 • 接着,各线程独立更新limitL~limitR – 1 范围内的值,再更新limitR的值;再次同步!

  13. 反依赖处理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 ...

  14. 反依赖处理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时才继续往下执行。

  15. OpenMP例子 • 反依赖的消除 • 循环依赖的消除 • OpenMP实现流水线

  16. 循环分布变换的例子 "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;

  17. 循环分布变换的例子 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

  18. 循环分布变换的例子 • "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

  19. 循环分布变换的例子 #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由其他线程并行执行

  20. OpenMP例子 • 反依赖的消除 • 循环依赖的消除 • OpenMP实现流水线

  21. 使用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

  22. 使用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

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

  24. 使用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]$

  25. 并行程序设计 高性能 依赖 计算任务划分 死锁 通讯

  26. 延伸阅读 【1】 《多核计算与程序设计》 作  者: 周伟明 著 出 版 社: 华中科技大学出版社 第三章中关于OpenMP相关内容 【2】 Barbara Chapman, “How OpenMP is Compiled ” http://cobweb.ecn.purdue.edu/ParaMount/iwomp2008/documents/chapman-underthehood

  27. 谢谢大家 谢谢大家 夏霏 2009.12

More Related