OpenMP程序设计 2019/4/25.

Slides:



Advertisements
Similar presentations
1 Programming with Shared Memory 共享存储器程序设计 Part 2.
Advertisements

While 迴圈 - 不知重複執行次數
JAVA 编 程 技 术 主编 贾振华 2010年1月.
第一章 C语言概述 计算机公共教学部.
指導老師:楊淑娥 組別:第一組 成員:劉怡萱4a0i0066 吳珮瑜4a0i0070 林秋如4a0i0075 陳婉婷4a0i0076
第六章 假设检验的基本概念.
周纯葆 中国科学院计算机网络信息中心 超级计算中心
新世代計算機概論 第14章 程式語言.
C++程序设计 王希 图书馆三楼办公室.
C# 程式設計 第一部分 第1-4章 C# 程式設計 - 南華大學資管系.
并行算法实践 上篇 并行程序设计导论.
华南理工大学 陈虎 博士 OpenMP并行程序设计简介 华南理工大学 陈虎 博士
2.1 基本資料型別 2.2 變數 2.3 運算式與運算子 2.4 輸出與輸入資料 2.5 資料型別轉換 2.6 實例
MPI并行程序设计简介 曙光信息产业(北京)有限公司 2018年11月.
多核结构与程序设计 杨全胜 东南大学成贤学院计算机系.
課程名稱:程式設計 授課老師:________
函數 授課:ANT 日期:2009/3/24.
多核结构与程序设计复习 2012年 杨全胜 东南大学成贤学院计算机系.
并行计算实验上机 国家高性能计算中心(合肥).
并行算法实践.
核探测与核电子学国家重点实验室 报告人:董磊 指导老师:宋克柱
程式語言 -Visual Basic 變數、常數與資料型態.
實作輔導 日期: 3/11 09:10~16:00 地點:臺北市立大學 臺北市中正區愛國西路一號 (中正紀念堂站7號出口)
函數 授課:ANT 日期:2011/3/28.
C 程式設計— 語言簡介 台大資訊工程學系 資訊系統訓練班.
第四讲 MPI并行程序设计 课程网站:CourseGrading buaa.edu.cn 主讲教师: 赵长海
C++ 程式設計— 語言簡介 台大資訊工程學系 資訊系統訓練班.
授课老师:龚涛 信息科学与技术学院 2018年3月 教材: 《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
Function.
第三章 C++中的C 面向对象程序设计(C++).
程式撰寫流程.
第3章 變數、常數與資料型態 3-1 C語言的識別字 3-2 變數的宣告與初值 3-3 指定敘述 3-4 C語言的資料型態
新觀念的 VB6 教本 第 6 章 資料型別.
期中考试成绩分布 《程序设计》-2017年秋.
2019/1/17 Java语言程序设计-程序流程 教师:段鹏飞.
Ch02-基礎語法.
計數式重複敘述 for 迴圈 P
切換Dev c++顯示語言 工具->環境選項(V)->介面->language (Chinese TW)
十二、并行程序设计基础.
進階 WWW 程式設計 -- PHP 語言結構 靜宜大學資訊管理學系 蔡奇偉副教授 2003
Introduction to lisp lisp.
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
C++ 程式設計 基礎篇 張啟中 Chang Chi-Chung.
《JAVA程序设计》 语音答疑 辅导老师:高旻.
第二章Java基本程序设计.
C语言概述 第一章.
Chapter 2 & Chapter 3.
陳維魁 博士 儒林圖書公司 第三章 變數與繫結 陳維魁 博士 儒林圖書公司.
Oop8 function函式.
7.1 C程序的结构 7.2 作用域和作用域规则 7.3 存储属性和生存期 7.4 变量的初始化
C语言程序设计 李祥 QQ:
第二章 Java语法基础.
第3章 数据类型、运算符与表达式.
第二章 类型、对象、运算符和表达式.
第二章 基本数据类型 ——数据的表示.
授课老师:龚涛 信息科学与技术学院 2016年3月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
挑戰C++程式語言 ──第9章 函數.
#include <iostream.h>
第二章 Java基本语法 讲师:复凡.
第1章程序设计和C语言.
本章主題 C++的程式結構 資料型態與宣告 算術運算 簡易的輸入輸出指令 程式編譯(Compile)的過程與原理.
《数据结构与算法设计》第一部分 面向对象的C++程序设计基础.
第二章 数据类型、运算符和表达式 §2.1 数据与数据类型 §2.2 常量、变量和标准函数 §2.3 基本运算符及其表达式 目 录 上一章
變數、資料型態、運算子.
C/C++基礎程式設計班 C語言入門、變數、基本處理與輸入輸出 講師:林業峻 CSIE, NTU 3/7, 2015.
基本資料型態 變數與常數 運算子 基本的資料處理 授課:ANT 日期:2014/03/03.
變數與資料型態  綠園.
第三章 流程控制 程序的运行流程 选择结构语句 循环结构语句 主讲:李祥 时间:2015年10月.
Introduction to the C Programming Language
C++语言程序设计 C++语言程序设计 第二章 基本数据类型与表达式 第十一组 C++语言程序设计.
Presentation transcript:

OpenMP程序设计 2019/4/25

OpenMP程序设计 OpenMP概述 OpenMP编程简介 运行库例程与环境变量 OpenMP计算实例

OpenMP概述 OpenMP应用编程接口API是在共享存储体系结构上的一个编程模型 包含编译制导(Compiler Directive)、运行库例程(Runtime Library)和环境变量(Environment Variables) 支持增量并行化(Incremental Parallelization)

什么是OpenMP 什么是OpenMP OpenMP不包含的性质 应用编程接口API(Application Programming Interface ) 由三个基本API部分(编译指令、运行部分和环境变量)构成 是C/C++ 和Fortan等的应用编程接口 已经被大多数计算机硬件和软件厂家所标准化 OpenMP不包含的性质 不是建立在分布式存储系统上的 不是在所有的环境下都是一样的 不是能保证让多数共享存储器均能有效的利用

OpenMP的历史 1994年,第一个ANSI X3H5草案提出,被否决 1997年10月公布了与Fortran语言捆绑的第一个标准规范 FORTRAN version 1.0 1998年11月9日公布了支持C和C++的标准规范C/C++ version 1.0 2000年11月推出FORTRAN version 2.0 2002年3月推出C/C++ version 2.0 2005年5月OpenMP2.5将原来的Fortran和C/C++ 标准规范相结合 相关的规范可在http://www.openmp.org/drupal/node/view/8中下载

OpenMP的目标 标准性 简洁实用 使用方便 可移植性

OpenMP并行编程模型 基于线程的并行编程模型(Programming Model) OpenMP使用Fork-Join并行执行模型

OpenMP程序结构 基于Fortran语言的OpenMP程序的结构 PROGRAM HELLO INTEGER VAR1, VAR2, VAR3 !Serial code … !Beginning of parallel section. Fork a team of threads. !Specify variable scoping !$OMP PARALLEL PRIVATE(VAR1, VAR2) SHARED(VAR3) !Parallel section executed by all threads … !All threads join master thread and disband !$OMP END PARALLEL !Resume serial code … END

OpenMP程序结构 基于c/c++语言的OpenMP程序的结构 #include <omp.h> main (){ int var1, var2, var3; /*Serial code*/ … /*Beginning of parallel section. Fork a team ofthreads*/ /*Specify variable scoping */ #pragma omp parallel private(var1, var2) shared(var3) { /*Parallel section executed by all threads*/ /*All threads join master thread and disband*/ } /*Resume serial code */

一个简单的OpenMP程序实例 基于C/C++语言的OpenMP程序结构的一个具体实现 #include "omp.h“//eg1 int main(int argc, char* argv[]) { int nthreads, tid; int nprocs; char buf[32]; /* Fork a team of threads */ #pragma omp parallel private(nthreads, tid) /* Obtain and print thread id */ tid = omp_get_thread_num(); printf("Hello World from OMP thread %d\n", tid); /* Only master thread does this */ if (tid==0) { nthreads = omp_get_num_threads(); printf("Number of threads %d\n", nthreads); } return 0;

编译制导 OpenMP的#pragma语句的格式为 #pragma omp directive_name … #pragma omp [clause, ...] newline 制导指令前缀。对 所有的OpenMP语 句都需要这样的前 缀。 OpenMP制导指 令。在制导指令前 缀和子句之间必须 有一个正确的 令。 子句。在没有其它 约束条件下,子句 可以无序,也可以 任意的选择。 这一 部分也可以没有。 换行符。表明这条 制导语句的终止。

编译制导 作用域 静态扩展 孤立语句 动态扩展 文本代码在一个编译制导语句之后,被封装到一个结构块中 一个OpenMP的编译制导语句不依赖于其它的语句 动态扩展 包括静态范围和孤立语句

作用域 动态范围 静态范围 for语句出现在一个封闭的并行域中 孤立语句 critical和sections语句出现在封闭的并行域之外 #pragma omp parallel { … #pragma omp for for(…){ sub1(); } sub2(); void sub1() #pragma omp critical void sub2() #pragma omp sections

并行域结构 并行域中的代码被所有的线程执行 具体格式 #pragma omp parallel [clause[[,]clause]…]newline clause= if(scalar-expression) private(list) firstprivate(list) default(shared | none) shared(list) copyin(list) reduction(operator: list) num_threads(integer-expression)

共享任务结构 共享任务结构将它所包含的代码划分给线程组的各成员来执行 并行for循环 并行sections 串行执行

for编译制导语句 for语句指定紧随它的循环语句必须由线程组并行执行; 语句格式 #pragma omp for [clause[[,]clause]…] newline [clause]= Schedule(type [,chunk]) ordered private (list) firstprivate (list) lastprivate (list) shared (list) reduction (operator: list) nowait

for编译制导语句 schedule子句描述如何将循环的迭代划分给线程组中的线程 如果没有指定chunk大小,迭代会尽可能的平均分配给每个线程 type为static,循环被分成大小为 chunk的块,静态分配给线程 type为dynamic,循环被动态划分为大小为chunk的块,动态分配给线程

Sections编译制导语句 sections编译制导语句指定内部的代码被划分给线程组中的各线程 不同的section由不同的线程执行 #pragma omp sections [ clause[[,]clause]…] newline { [#pragma omp section newline] … }

Sections编译制导语句 clause= 在sections语句结束处有一个隐含的路障,使用了nowait子句除外 private (list) firstprivate (list) lastprivate (list) reduction (operator: list) nowait 在sections语句结束处有一个隐含的路障,使用了nowait子句除外

Sections编译制导语句 #include <omp.h>//eg2 #define N 1000 int main (){ int i; float a[N], b[N], c[N]; /* Some initializations */ for (i=0; i < N; i++) a[i] = b[i] = i * 1.0; #pragma omp parallel shared(a,b,c) private(i) { #pragma omp sections nowait #pragma omp section for (i=0; i < N/2; i++) c[i] = a[i] + b[i]; for (i=N/2; i < N; i++) } /* end of sections */ } /* end of parallel section */ }

single编译制导语句 single编译制导语句指定内部代码只有线程组中的一个线程执行。 线程组中没有执行single语句的线程会一直等待代码块的结束,使用nowait子句除外 语句格式: #pragma omp single [clause[[,]clause]…] newline clause= private(list) firstprivate(list) nowait

组合的并行共享任务结构 parallel for编译制导语句 parallel sections编译制导语句

parallel for编译制导语句 Parallel for编译制导语句表明一个并行域包含一个独立的for语句 语句格式 #pragma omp parallel for [clause…] newline clause= if (scalar_logical_expression) default (shared | none) schedule (type [,chunk]) shared (list) private (list) firstprivate (list) lastprivate (list) reduction (operator: list) copyin (list)

parallel for编译制导语句 #include <omp.h> //ex2 #define N 1000 #define CHUNKSIZE 100 int main () { int i, chunk; float a[N], b[N], c[N]; /* Some initializations */ for (i=0; i < N; i++) a[i] = b[i] = i * 1.0; chunk = CHUNKSIZE; #pragma omp parallel for \ shared(a,b,c,chunk) private(i) \ schedule(static,chunk) for (i=0; i < n; i++) c[i] = a[i] + b[i]; }

parallel sections编译制导语句 parallel sections编译制导语句表明一个并行域包含单独的一个sections语句 语句格式 #pragma omp parallel sections [clause…] newline clause= default (shared | none) shared (list) private (list) firstprivate (list) lastprivate (list) reduction (operator: list) copyin (list) ordered

同步结构 master 制导语句 critical制导语句 barrier制导语句 atomic制导语句 flush制导语句 ordered制导语句

master 制导语句 master制导语句指定代码段只有主线程执行 语句格式 #pragma omp master newline

critical制导语句 critical制导语句表明域中的代码一次只能执行一个线程 其他线程被阻塞在临界区 语句格式: #pragma omp critical [name] newline

critical制导语句 #include <omp.h> main() { int x; x = 0; #pragma omp parallel shared(x) #pragma omp critical x = x + 1; } /* end of parallel section */ }

barrier制导语句 barrier制导语句用来同步一个线程组中所有的线程 先到达的线程在此阻塞,等待其他线程 语句格式 #pragma omp barrier newline

barrier制导语句 barrier正确与错误使用比较 错误 正确 if (x == 0) #pragma omp barrier { }

atomic制导语句 atomic制导语句指定特定的存储单元将被原子更新 语句格式 atomic使用的格式 #pragma omp atomic newline atomic使用的格式 x binop = expr x++ ++x x-- --x x是一个标量 expr是一个不含对x引用的标量表达式,且不被重载 binop是+,*,-,/,&,^,|,>>,or<<之一,且不被重载

flush制导语句 flush制导语句用以标识一个同步点,用以确保所有的线程看到一致的存储器视图 语句格式 #pragma omp flush (list) newline flush将在下面几种情形下隐含运行,nowait子句除外 barrier critical:进入与退出部分 ordered:进入与退出部分 parallel:退出部分 for:退出部分 sections:退出部分 single:退出部分

ordered制导语句 ordered制导语句指出其所包含循环的执行 任何时候只能有一个线程执行被ordered所限定部分 只能出现在for或者parallel for语句的动态范围中 语句格式: #pragma omp ordered newline

threadprivate编译制导语句 threadprivate语句使一个全局文件作用域的变量在并行域内变成每个线程私有 每个线程对该变量复制一份私有拷贝 语句格式: #pragma omp threadprivate (list) newline

threadprivate编译制导语句 int alpha[10], beta[10], i;//eg3 #pragma omp threadprivate(alpha) int main () { /* First parallel region */ #pragma omp parallel private(i,beta) for (i=0; i < 10; i++) alpha[i] = beta[i] = i; /* Second parallel region */ #pragma omp parallel printf("alpha[3]= %d and beta[3]=%d\n",alpha[3],beta[3]); }

数据域属性子句 变量作用域范围 数据域属性子句 private子句 shared子句 default子句 firstprivate子句 lastprivate子句 copyin子句 reduction子句

private子句 private子句表示它列出的变量对于每个线程是局部的 。 语句格式 private和threadprivate区别 private(list) private和threadprivate区别 PRIVATE THREADPRIVATE 数据类型 变量 位置 在域的开始或共享任务单元 在块或整个文件区域的例程的定义上 持久性 否 是 扩充性 只是词法的- 除非作为子程序的参数而传递 动态的 初始化 使用 FIRSTPRIVATE 使用 COPYIN

shared子句 shared子句表示它所列出的变量被线程组中所有的线程共享 所有线程都能对它进行读写访问 语句格式 shared (list)

default子句 default子句让用户自行规定在一个并行域的静态范围中所定义的变量的缺省作用范围 语句格式 default (shared | none)

firstprivate子句 firstprivate子句是private子句的超集 对变量做原子初始化 语句格式: firstprivate (list)

lastprivate子句 lastprivate子句是private子句的超集 将变量从最后的循环迭代或段复制给原始的变量 语句格式 lastprivate (list)

copyin子句 copyin子句用来为线程组中所有线程的threadprivate变量赋相同的值 主线程该变量的值作为初始值 语句格式 copyin(list)

reduction子句 reduction子句使用指定的操作对其列表中出现的变量进行规约 初始时,每个线程都保留一份私有拷贝 在结构尾部根据指定的操作对线程中的相应变量进行规约,并更新该变量的全局值 语句格式 reduction (operator: list)

reduction子句 #include <omp.h>//eg4 int main () { int i, n, chunk; float a[100], b[100], result; /* Some initializations */ n = 100; chunk = 10; result = 0.0; for (i=0; i < n; i++) a[i] = i * 1.0; b[i] = i * 2.0; } #pragma omp parallel for default(shared) private(i)\ schedule(static,chunk) reduction(+:result) result = result + (a[i] * b[i]); printf("Final result= %f\n",result);

reduction子句 Reduction子句的格式 x=x op expr x = expr op x (except subtraction) x binop = expr x++ ++x x-- --x x是一个标量 expr是一个不含对x引用的标量表达式,且不被重载 binop是+,*,-,/,&,^,|之一,且不被重载 op是+,*,-,/,&,^,|,&&,or||之一,且不被重载

子句/编译制导语句总结 子句 编译制导 PARALLEL DO/for SECTIONS SINGLE PARALLEL DO/for PARALLEL SECTIONS IF √ PRIVATE SHARED DEFAULT FIRSTPRIVATE LASTPRIVATE REDUCTION COPYIN SCHEDULE ORDERED NOWAIT

语句绑定和嵌套规则 语句绑定 语句DO/for、SECTIONS、SINGLE、MASTER和BARRIER绑定到动态的封装PARALLEL中,如果没有并行域执行,这些语句是无效的; 语句ORDERED指令绑定到动态DO/for封装中; 语句ATOMIC使得ATOMIC语句在所有的线程中独立存取,而并不只是当前的线程; 语句CRITICAL在所有线程有关CRITICAL指令中独立存取,而不是只对当前的线程; 在PARALLEL封装外,一个语句并不绑定到其它的语句中。

语句绑定和嵌套规则 语句嵌套 PARALALL 语句动态地嵌套到其它地语句中,从而逻辑地建立了一个新队列,但这个队列若没有嵌套地并行域执行,则只包含当前的线程; DO/for、SECTION和SINGLE语句绑定到同一个PARALLEL 中,则它们是不允许互相嵌套的; DO/for、SECTION和SINGLE语句不允许在动态的扩展CRITICAL、ORDERED和MASTER域中; CRITICAL语句不允许互相嵌套; BARRIER语句不允许在动态的扩展DO/for、ORDERED、SECTIONS、SINGLE、MASTER和CRITICAL域中; MASTER语句不允许在动态的扩展DO/for、SECTIONS和SINGLE语句中; ORDERED语句不允许在动态的扩展CRITICAL域中; 任何能允许执行到PARALLEL 域中的指令,在并行域外执行也是合法的。当执行到用户指定的并行域外时,语句执行只与主线程有关。

运行库例程与环境变量 运行库例程 OpenMP标准定义了一个应用编程接口来调用库中的多种函数 对于C/C++,在程序开头需要引用文件“omp.h” 环境变量 OMP_SCHEDULE:只能用到for,parallel for中。它的值就是处理器中循环的次数 OMP_NUM_THREADS:定义执行中最大的线程数 OMP_DYNAMIC:通过设定变量值TRUE或FALSE,来确定是否动态设定并行域执行的线程数 OMP_NESTED:确定是否可以并行嵌套

OpenMP计算实例 矩形法则的数值积分方法估算Pi的值 2019/4/25

OpenMP计算实例 C语言写的串行程序 /* Seriel Code */ static long num_steps = 100000; double step; void main () { int i; double x, pi, sum = 0.0; step = 1.0/(double) num_steps; for (i=0;i< num_steps; i++){ x = (i+0.5)*step; sum = sum + 4.0/(1.0+x*x); } pi = step * sum;

OpenMP计算实例 使用并行域并行化的程序//1 #include <omp.h> static long num_steps = 100000; double step; #define NUM_THREADS 2 void main () { int i; double x, pi, sum[NUM_THREADS]; step = 1.0/(double) num_steps; omp_set_num_threads(NUM_THREADS); // #pragma omp parallel { double x; int id; id = omp_get_thread_num(); for (i=id, sum[id]=0.0;i< num_steps; i=i+NUM_THREADS){// x = (i+0.5)*step; sum[id] += 4.0/(1.0+x*x); } for(i=0, pi=0.0;i<NUM_THREADS;i++) pi += sum[i] * step;

OpenMP计算实例 使用共享任务结构并行化的程序 //2 #include <omp.h> static long num_steps = 100000; double step; #define NUM_THREADS 2 void main () { int i; double x, pi, sum[NUM_THREADS]; step = 1.0/(double) num_steps; omp_set_num_threads(NUM_THREADS) ;//****** #pragma omp parallel //****** double x; int id; id = omp_get_thread_num(); sum[id] = 0; //** #pragma omp for//****** for (i=0;i< num_steps; i++){ x = (i+0.5)*step; sum[id] += 4.0/(1.0+x*x); } for(i=0, pi=0.0;i<NUM_THREADS;i++)pi += sum[i] * step;

OpenMP计算实例 使用private子句和critical部分并行化的程序 #include <omp.h> static long num_steps = 100000; double step; #define NUM_THREADS 2 void main () { int i; double x, sum, pi=0.0; step = 1.0/(double) num_steps; omp_set_num_threads(NUM_THREADS) #pragma omp parallel private (x, sum) id = omp_get_thread_num(); for (i=id,sum=0.0;i< num_steps;i=i+NUM_THREADS){ x = (i+0.5)*step; sum += 4.0/(1.0+x*x); } #pragma omp critical pi += sum

OpenMP计算实例 使用并行归约得出的并行程序 #include <omp.h> static long num_steps = 100000; double step; #define NUM_THREADS 2 void main () { int i; double x, pi, sum = 0.0; step = 1.0/(double) num_steps; omp_set_num_threads(NUM_THREADS) #pragma omp parallel for reduction(+:sum) private(x) for (i=0;i<num_steps; i++){ x = (i+0.5)*step; sum = sum + 4.0/(1.0+x*x); } pi = step * sum;