周纯葆 中国科学院计算机网络信息中心 超级计算中心

Slides:



Advertisements
Similar presentations
阻塞操作. 在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t testqueue; init_waitqueue_head(&testqueue);
Advertisements

1 Programming with Shared Memory 共享存储器程序设计 Part 2.
LSF系统介绍 张焕杰 中国科学技术大学网络信息中心
赵永华 中科院计算机网络信息中心 超级计算中心
第一章 C语言概述 计算机公共教学部.
Oracle数据库 Oracle 子程序.
新世代計算機概論 第14章 程式語言.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
Using C++ The Weird Way Something about c++11 & OOP tricks
并行算法实践 上篇 并行程序设计导论.
华南理工大学 陈虎 博士 OpenMP并行程序设计简介 华南理工大学 陈虎 博士
机群应用开发 并行编程原理及 程序设计 Parallel Programming: Fundamentals and Implementation 马少杰 曙光信息产业有限公司
EBNF与操作语义 请用扩展的 BNF 描述 javascript语言里语句的结构;并用操作语义的方法描述对应的语义规则
Kvm异步缺页中断 浙江大学计算机体系结构实验室 徐浩.
MPI并行程序设计简介 曙光信息产业(北京)有限公司 2018年11月.
LSF系统介绍 张焕杰 中国科学技术大学网络信息中心
多核结构与程序设计 杨全胜 东南大学成贤学院计算机系.
多核结构与程序设计复习 2012年 杨全胜 东南大学成贤学院计算机系.
并行计算实验上机 国家高性能计算中心(合肥).
OpenMP简介和开发教程 广州创龙电子科技有限公司
并行算法实践.
核探测与核电子学国家重点实验室 报告人:董磊 指导老师:宋克柱
第四讲 MPI并行程序设计 课程网站:CourseGrading buaa.edu.cn 主讲教师: 赵长海
STRUCTURE 授課:ANT 日期:2010/5/12.
Function.
管理信息结构SMI.
实践演练 广州创龙电子科技有限公司 01 广州创龙电子科技有限公司
走进编程 程序的顺序结构(二).
辅导课程六.
临界区软件互斥软件实现算法.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
第十章 IDL访问数据库 10.1 数据库与数据库访问 1、数据库 数据库中数据的组织由低到高分为四级:字段、记录、表、数据库四种。
Online job scheduling in Distributed Machine Learning Clusters
临界区软件互斥软件实现算法 主讲教师:夏莹杰
中国科学技术大学计算机系 陈香兰(0551- ) Spring 2009
計數式重複敘述 for 迴圈 P
十二、并行程序设计基础.
第七章 函数及变量存贮类型 7.1 函数基础与C程序结构 7.2 函数的定义和声明 7.3 函数的调用 7.4 函数的嵌套与递归
第1章 概述 本章要点: C语言程序结构和特点 C语言程序的基本符号与关键字 C语言程序的编辑及运行 学习方法建议:
第4章 PHP流程控制语句.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
C语言程序设计 主讲教师:陆幼利.
EBNF与操作语义 请用扩展的 BNF 描述 javascript语言里语句的结构;并用操作语义的方法描述对应的语义规则
C语言概述 第一章.
第一章 程序设计和C语言 主讲人:高晓娟 计算机学院.
OpenMP程序设计 2019/4/25.
Oop8 function函式.
<编程达人入门课程> 本节内容 内存的使用 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
Lightweight Data-flow Analysis for Execution-driven Constraint Solving
成绩是怎么算出来的? 16级第一学期半期考试成绩 班级 姓名 语文 数学 英语 政治 历史 地理 物理 化学 生物 总分 1 张三1 115
信号量(Semaphore).
第4章 Excel电子表格制作软件 4.4 函数(一).
本节内容 类成员的访问控制 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第九节 赋值运算符和赋值表达式.
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
授课老师:龚涛 信息科学与技术学院 2016年3月 教材:《Visual C++程序员成长攻略》 《C++ Builder程序员成长攻略》
挑戰C++程式語言 ──第9章 函數.
临界区问题的硬件指令解决方案 (Synchronization Hardware)
本节内容 C语言的汇编表示 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
本节内容 Windows线程切换_时钟中断切换 视频提供:昆山滴水信息技术有限公司 官网地址: 论坛地址: QQ交流 :
实验目的:掌握数据的顺序存储结构及它们在计算机中的操作。 实验内容:
第1章程序设计和C语言.
并行计算实验上机 国家高性能计算中心(合肥).
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
本节内容 动态链接库 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
C/C++基礎程式設計班 C語言入門、變數、基本處理與輸入輸出 講師:林業峻 CSIE, NTU 3/7, 2015.
本节内容 进程 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第三章 流程控制 程序的运行流程 选择结构语句 循环结构语句 主讲:李祥 时间:2015年10月.
函式庫補充資料 1.
Presentation transcript:

周纯葆 中国科学院计算机网络信息中心 超级计算中心 zhoucb@sccas.cn OpenMP编程基础 周纯葆 中国科学院计算机网络信息中心 超级计算中心 zhoucb@sccas.cn

提纲 OpenMP简介 OpenMP编译制导 OpenMP库函数 OpenMP环境变量

并行机体系结构及通信机制 SMP:共享内存并行机 (Shared Memory Processors) 多个处理器通过交叉开关(Crossbar)或总线与共享内存互连 任意处理器可直接访问任意内存地址,且访问延迟、带宽、几率都是等价的 系统是对称的 单地址空间 、共享存储、UMA DSM:分布共享存储并行机 (Distributed Shared Memory) 结点(一般是SMP系统)通过高速消息传递网络互连而成。存储系统在物理上分布、逻辑上共享。各结点有自己独立的寻址空间 单地址空间 、分布共享 NUMA (Nonuniform Memory Access) 与SMP的主要区别:DSM在物理上有分布在各个节点的局部内存从而形成一个共享的存储器

访存模型

OpenMP OpenMP是共享存储体系结构上的一个并行编程模型。适合于SMP共享内存多处理系统和多核处理器体系结构。 起源于ANSI X3H5标准 简单、移植性好和可扩展性等特点 提供了支持Fortran、C/C++的API和规范 由一组编译制导、运行时库函数(Run-Time routines) 和环境变量组成。 工业标准 DEC、Intel、IBM、HP、Sun、SGI等公司支持 包括Linux、UNIX和Windows等多种操作系统平台 http://www.openmp.org/

OpenMP编程模式 OpenMP是基于线程的并行编程模型。 OpenMP采用Fork-Join并行执行方式: OpenMP程序开始于一个单独的主线程(Master Thread),然后主线程一直串行执行,直到遇见第一个并行域(Parallel Region),然后开始并行执行并行区域。其过程如下: Fork:主线程创建一个并行线程队列,然后,并行域中的代码在不同的线程上并行执行; Join:当并行域执行完之后,它们或被同步或被中断,最后只有主线程在执行。

OpenMP执行模型 F O R K J I N F O R K J I N Master thread 并行域 并行域 串行部分 串行部分

OpenMP存储模型

OpenMP存储模型 x = 2; #pragma omp parallel num_threads(2) shared(x) { if (omp_get_thread_num() == 0) { sleep(1); x = 5; } else { printf("1: Thread# %d: x = %d\n", omp_get_thread_num(),x ); } #pragma omp barrier printf("2: Thread# %d: x = %d\n", omp_get_thread_num(),x ); printf("3: Thread# %d: x = %d\n", omp_get_thread_num(),x );

支持条件编译 int main() { #ifdef _OPENMP printf("Compiled by an OpenMP-compliant implementation.\n"); #endif return 0; }

Hello world #include <omp.h> int main(int argc, char *argv[]) { int nthreads, tid; /* Fork a team of threads */ #pragma omp parallel private(nthreads,tid) {     tid = omp_get_thread_num(); /* Obtain and print thread id */            printf("Hello, world from OpenMP thread %d\n", tid); if (tid == 0) /*Only master thread does this */ {      nthreads = omp_get_num_threads();      printf(" Number of threads %d\n",nthreads);   } } return 0; }

OpenMP编译器

OpenMP编译执行 编译 执行 运行结果: icc -openmp –o HelloWorld HelloWorld.c Hello World from OpenMP thread 2 Hello World from OpenMP thread 0 Number of threads 4 Hello World from OpenMP thread 3 Hello World from OpenMP thread 1

OpenMP程序结构 基于Fortran语言的OpenMP程序结构 PROGRAM PROG_NAME INTEGER VAR1, VAR2 ,VAR3 ………. !$OMP PARALLEL PRIVATE(VAR1, VAR2) SHARED(VAR3) !$OMP END PARALLEL …… END

OpenMP程序结构 基于C/C++语言的OpenMP程序结构 #include<omp.h> void main(){ int var1, var2, var3; …….. #pragma omp parallel private(var1, var2) shared(var3) { …………. } ……………

OpenMP制导指令 parallel用在一个代码段之前,表示这段代码将被多个线程并行执行 for 用于for循环之前,将循环分配到多个线程中并行执行,必须保证每次循环之间无相关性。 parallel for是parallel 和 for语句的结合,也是用在一个for循环之前,表示for循环的代码将被多个线程并行执行。 sections 用在可能会被并行执行的代码段之前 parallel sections parallel和sections两个语句的结合 critical 用在一段代码临界区之前 single 用在一段只被单个线程执行的代码段之前,表示后面的代码段将被单线程执行 barrier,用于并行区内代码的线程同步,所有线程执行到barrier时要停止直到所有线程都执行到barrier时才继续往下执行。 Atomic 用于指定一块内存区域被制动更新 Master 用于指定一段代码块由主线程执行 Ordered 用于指定并行区域的循环按顺序执行 threadprivate 用于指定一个变量是线程私有

OpenMP子句 private, 指定每个线程都有它自己的变量私有副本。 firstprivate,指定每个线程都有它自己的变量私有副本,并且变量要被继承主线程中的初值。 lastprivate,主要是用来指定将线程中的私有变量的值在并行处理结束后复制回主线程中的对应变量。 reduction,用来指定一个或多个变量是私有的,并且在并行处理结束后这些变量要执行指定的运算。 nowait,忽略指定中暗含的等待 num_threads,指定线程的个数 schedule,指定如何调度for循环迭代 shared,指定一个或多个变量为多个线程间的共享变量 ordered,用来指定for循环的执行要按顺序执行 copyprivate,用于single指导中的指定变量广播到并行区中其它线程 copyin,用来指定一个threadprivate的变量的值用主线程的值初始化。 default,用来指定并行处理区域内的变量的使用方式,缺省是shared

OpenMP库函数 omp_get_num_procs, 返回运行本线程的多处理机的处理器个数。 omp_get_num_threads, 返回当前并行区域中的活动线程个数。 omp_get_thread_num, 返回线程号       omp_set_num_threads, 设置并行执行代码的线程个数 omp_init_lock, 初始化一个简单锁 omp_set_lock, 上锁操作 omp_unset_lock, 解锁操作,要和omp_set_lock函数配对使用。 omp_destroy_lock, omp_init_lock函数的配对操作函数,关闭一个锁

提纲 OpenMP简介 OpenMP编译制导 OpenMP库函数 OpenMP环境变量

编译制导 OpenMP的并行化是通过使用嵌入到C/C++或Fortran源代码中的编译制导语句来实现。 编译制导是对程序设计语言的扩展。 通过对串行程序添加制导语句实现并行化。 支持并行区域、工作共享、同步等。 支持数据的共享和私有化。

制导语句格式 编译制导语句由下列几部分组成: 格式:制导标识符 制导名称 [子句,] 制导标识符 ( !$OMP 、 #pragma omp ) 制导名称(parallel,DO/for,section等) 子句(private, shared, reduction, copyin等) 格式:制导标识符 制导名称 [子句,]

编译制导标识 制导是特殊的、仅用于特定编译器的源代码。 制导由一个位于行首的标识加以区分。 OpenMP 制导标识: Fortran: !$OMP (or C$OMP or *$OMP) C/C++: #pragma omp

并行域制导 一个并行域就是一个能被多个线程并行执行的程序段 Fortran: !$OMP PARALLEL [clauses] BLOCK !$OMP END PARALLEL C/C++: #pragma omp parallel [clauses] { } 说明: 在并行域结尾有一个隐式同步(barrier)。 子句(clause)用来说明并行域的附加信息。 在Fortran语言中,子句间用逗号或空格分隔; C/C++子句间用空格分开。

并行域结构 Master thread Threads barrier Master thread Threads barrier

shared和private子句 并行域内的变量,可以通过子句说明为公有或私有; 在编写多线程程序时,确定哪些数据的公有或私有非常重要:影响程序的性能和正确性 Fortran: SHARED(list) PRIVATE(list) DEFAULT(SHARED|PRIVATE|NONE) C/C++: shared(list) private(list) default(shared|private|none)

shared和private子句 例:每个线程初始共享数组的一列 说明:如何决定哪些变量是共享哪些是私有? !$OMP PARALLEL DEFAULT(NONE), PRIVATE(I, MYID), !$OMP & SHARED(a, n) myid=omp_get_thread_num()+1 do i=1, n a(i, myid)=1.0 end do !$OMP END PARALLEL 说明:如何决定哪些变量是共享哪些是私有? 通常循环变量、临时变量、写变量一般是私有的; 数组变量、仅用于读的变量通常是共享的。默认时为公有。 i 2 3 1

计算Pi值 /* 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=1;i<= num_steps; i++) { x = (i-0.5)*step; sum = sum + 4.0/(1.0+x*x); } pi = step * sum; printf (“Pi = %f\n”, pi);

并行域并行 #include <omp.h> static long num_steps = 100000; double step; #define NUM_THREADS 4 void main () { int i ; double pi, sum[NUM_THREADS]; step = 1.0/(double) num_steps; omp_set_num_threads(NUM_THREADS) ; #pragma omp parallel private(i) { int id; double x; 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; printf (“Pi = %f\n”, pi);

并行DO/for循环制导 并行DO/for循环制导用来将循环划分成多个块,并分配给各线程并行执行。 说明: Fortran: !$OMP DO[clauses] DO 循环 !$OMP END DO C/C++: #pragma omp for [clauses] for 循环 说明: 并行DO/for循环有时需要PRIVATE和FIRSTPRIVARE子句; 循环变量是私有的。

并行DO/for循环制导 可以将并行域和DO/for制导结合成单一的简单形式 !$OMP PARALLEL [clauses] Fortran: !$OMP PARALLEL [clauses] !$OMP DO[clauses] 循环体 !$OMP END DO !$OMP END PARALLEL 合并后形式: !$OMP PARALLEL DO[clauses] !$OMP END PARALLEL DO 同样地,C/C++:合并后形式 #pragma omp parallel for [clauses] { 循环体 }

循环制导 #include <omp.h> #define NUM_THREADS 4 static long num_steps = 100000; double step; void main () { int i,id; double x, pi, sum[NUM_THREADS]; step = 1.0/(double) num_steps; omp_set_num_threads(NUM_THREADS); #pragma omp parallel private(x, 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; printf (“Pi = %f\n”, pi);

SCHEDULE子句 该子句给出迭代循环划分后的块大小和线程执行的块范围 Fortran: SCHEDULE(kind[, chunksize]) C/C++: schedule (kind[, chunksize]) 其中:kind为STATIC, DYNAMIC或RUNTIME, chunksize是一个整数表达式 例如: !$ OMP DO SCHEDULE (DYNAMIC,4) 循环体 !$ OMP DO

SCHEDULE子句 schedule (STATIC [, chunksize]) : 如果chunksize被指明,迭代空间被划分为chunksize大小,然后被轮转的分配给各个线程 例如:假如线程数为4 schedule(static) T0 T1 T2 T3 1 40 schedule(static, 4) T0 T1 T2 T3 T0 T1 T2 T3 T0 T1 1 40

SCHEDULE子句 schedule (DYNAMIC [, chunksize]) : schedule (GUIDED [, chunksize]) 类似于DYNAMIC调度,但区间开始大,然后迭代区间越来越少,循环区间的划分是基于类似下列公式完成的(不同的编译系统可能不同): 其中N是线程个数,Sk表示第k块的大小,Rk是剩余下未被调度的循环迭代次数。 chunksize说明最小的区间大小。省略chunksize时,其默认值为1。

SCHEDULE子句

reduction子句 归约用来从相关的操作(+,*,max或min等)中产生一个单一值; OpenMP提供了reduction子句。 Fortran:REDUCTION(op:list) C/C++: reduction(op:list) 例子:将一组数值归约求和 sum=0; $OMP PARALLEL REDUCTION(+: sum), PRIVATE(i,myid) myid=omp_get_thread_num()+1 do i= 1, n sum=sum+a(i, myid) end do $OMP END PARALLEL 说明: 在reduction子句中,编译器为每个线程创建变量sum的私有副本。当循环完成后,将这些值加在一起并把结果放到原始的变量sum中; 数组、指针和引用类型不能出现在list; Reduction中的op操作必须满足算术结合律和交换律。

reduction子句 #include <omp.h> #define NUM_THREADS 4 static long num_steps = 100000; double step; void main () { int i,id; double x, pi, sum; step = 1.0/(double) num_steps; omp_set_num_threads(NUM_THREADS) ; start_time=omp_get_wtime(); #pragma omp parallel private(x, id) { #pragma omp for private(x) reduction(+:sum) for (i=0;i< num_steps; i++){ x = (i+0.5)*step; sum += 4.0/(1.0+x*x); } pi = sum*step; printf (“Pi = %f\n”, pi);

数据竞争 下面的循环无法正确执行: 在parallel结构中声明变量,这样的变量是私有的。 正确的方式: (直接声明为私有变量) #pragma omp parallel for for(k=0;k<100;k++) { x=array[k]; array[k]=do_work(x); } 正确的方式: (直接声明为私有变量) #pragma omp parallel for private(x) 在parallel结构中声明变量,这样的变量是私有的。 #pragma omp parallel for for(k=0;k<100;k++) { int x; x=array[k]; array[k]=do_work(x); }

BARRIER制导 BARRIER是OpenMP用于线程同步的一种方法 Fortran: !$ OMP BARRIER C/C++: #pragma omp barrier 说明: 在所有的线程到达之前,没有线程可以提前通过一个barrier; 在DO/FOR、SECTIONS和SINGLE制导后,有一个隐式barrier 存在; 要么所有线程遇到barrier;要么没有线程遇到barrier,否则会出现死锁

BARRIER制导 例子 ! $OMP PARALLEL PRIVATE(i, myid, neighb) myid=omp_get_thread_num() neighb=myid-1 if (myid .eq. 0) neighb=omp_get_num_threads()-1 ……… a(myid)=a(myid)*3.5 ! $ OMP BARRIER b(myid)=a(neighb)+c ………… ! $ OMP END PARALLEL

提纲 OpenMP简介 OpenMP编译制导 OpenMP库函数 OpenMP环境变量

库函数 OpenMP标准定义了一个应用程序编程接口来调用库中的多个函数。 有时需要得到线程数和线程号,这在控制不同线程执行不同的功能代码时特别有用。 得到线程队列中的线程数 Fortran: interger function OMP_GET_NUM_THREADS () C/C++: #include<omp.h> int omp_get_num_threads()

库函数 得到执行线程的线程号: Fortran: Interger function OMP_GET_THREAD_NUM () C/C++: #include<omp.h> int omp_get_thread_num()

库函数 设定执行线程的数量 在制导语句中通过 NUM_THREADS设定。 通过环境变量OMP_NUM_THREADS 设定。 Fortran: routine OMP_SET_NUM_THREADS ( ) C/C++: #include<omp.h> omp_set_num_threads() 在制导语句中通过 NUM_THREADS设定。 通过环境变量OMP_NUM_THREADS 设定。

库函数 得到处理器数量 时间函数 Fortran INTEGER FUNCTION OMP_GET_NUM_PROCS() C/C++ #include <omp.h> int omp_get_num_procs(void) 时间函数 Fortran: DOUBLE PRECISION FUNCTION OMP_GET_WTIME() C/C++: double omp_get_wtime(void);

提纲 OpenMP简介 OpenMP编译制导 OpenMP库函数 OpenMP环境变量

环境变量 OpenMP提供环境变量用来控制并行代码的执行 设定线程数环境变量: 例如: 1. OMP_NUM_THREADS:设定最大线程数。 export OMP_NUM_THREADS=4 2. KMP_AFFINITY:设定线程绑定的环境变量。 export KMP_AFFINITY=scatter

NUM_THREADS子句 OpenMP (Fortran 、C/C++) 提供了NUM_THREADS子句设定线程数。 例子 说明: !$OMP PARALLEL DO NUM_THREADS(4) DO J = 1,N A(I,J) = B(I,J) !$OMP END DO 说明: 在NUM_THREADS中提供的值将取代环境变量OMP_NUM_THREADS 的值 (或由 omp_set_num_threads()设定的值 )

NUM_THREADS子句 num_threads子句用来指定并行域内使用线程的个数,随后的其它并行域不受此影响。 例: #include"omp.h" #include"stdio.h“ void main() { omp_set_num_threads(4); #pragma omp parallel num_threads(2) printf(“my thead number is %d\n",omp_get_thread_num()); } num_threads子句的优先权高于库例程omp_set_num_threads和环境变量NMP_NUM_THREADS。