炼数成金 门户 CUDA 查看内容

OpenMP知识点汇总

2015-9-11 14:46| 发布者: 炼数成金_小数| 查看: 2270| 评论: 0|原作者: fengbingchun|来自: CSDN

摘要: 使用OpenMP前提是机子本身是多处理器或多核的并支持共享内存。内存是共享的,处理器在访问内存的时候使用的是相同的内存编址空间,某一个处理器写入内存的数据会立刻被其它处理器访问到。它可以在大多数的操作系统中 ...

模型 编程 硬件 C++ 程序设计

1、OpenMP(Open Multi-Processing)官网:http://openmp.org/wp/

2、OpenMP版本4.0,2013年7月发布。Visual Studio 2010内置支持OpenMP2.0,选中工程属性->C/C++->Language->Open MP Support:选中Yes(/openmp)即可,然后在文件中加入#include 就可使用OpenMP了。

3、使用OpenMP前提是机子本身是多处理器或多核的并支持共享内存。内存是共享的,处理器在访问内存的时候使用的是相同的内存编址空间,某一个处理器写入内存的数据会立刻被其它处理器访问到。它可以在大多数的操作系统中运行,如Linux、Mac OS、Microsoft Windows。

4、其它开发工具的支持:(1)、GCC4.9:OpenMP4.0;(2)、VisualStudio 2005/2008/2010/2013:OpenMP2.0.

5、The OpenMP Architecture Review Board负责OpenMP新版本的发布,是非盈利公司,其成员包括:AMD、Cray、HP、IBM、Intel、NVIDIA、Oracle、Red Hat等,其标准是由一些具有国际影响力的软件和硬件厂商共同定义和提出,其标准形成于1997年。在2002年发布了C/C++语言的2.0版本。

6、OpenMP本身是一个API规范,它没有License,或者说它与编译器具有相同的License.

7、多核系统并行程序设计中需要重点关注的关键问题有两个:(1)、设计适合多核系统运行的并行程序;(2)、优化多核系统中单个程序并行运行和多个程序同时并行运行的效率。

8、OpenMP本身不是一种独立的并行语言,而是为多处理器上编写并行程序而设计的、指导共享内存、多线程并行的编译制导指令和应用程序编程接口(API),可在C/C++/Fortran中应用,用于编写可移植的多线程应用程序。OpenMP程序设计模型提供了一组与平台无关的编译制导、API函数集和环境变量,可以显示地指导编译器如何以及何时利用应用程序中的并行性。所有OpenMP的并行化都是通过使用嵌入到C/C++/Fortran源代码中的编译制导语句来达到的。

9、OpenMP在串行代码中以编译器可识别的注释形式出现,而这些注释的解析由编译器所完成。OpenMP是独立于平台的,如果编译器不支持OpenMP,将会自动忽略预处理指令#pragma,程序依然可以按照串行程序代码顺利编译执行。

10、OpenMP的执行模型采用fork-join(分叉-合并)的形式,以线程为基础。其中fork创建线程或者唤醒已有线程;join即多线程的会合。fork-join执行模型在刚开始执行的时候,只有一个称为“主线程”的运行线程存在。主线程在运行过程中,当遇到需要进行并行计算的时候,,派生出线程来执行并行任务。在并行执行的时候,主线程和派生线程共同工作。在并行代码执行结束后,派生线程退出或者阻塞,不再工作,控制流回到单独的主线程中。并行部分没有结束是不会执行串行部分的。
fork-join并行执行模型

11、运用OpenMP方法的加速比远小于CPU核心数,这是因为OpenMP调度和同步需要一定的消耗。因此,在实际的编程开发中,要仔细分析代码的性能瓶颈,在合理的位置设置代码的并行化处理。

12、串行程序仅仅利用了多核处理器中的一个处理核心,而其他处理核心则处于空闲状态。采用多线程技术是提高资源利用率的一个有效方法,在单核处理器时代,应用程序已经支持多线程技术。然而,单核内的多线程运行是串行的,在某一时刻,只能有一段代码被CPU执行,单核处理器只能将多个指令流交错执行,轮流使用CPU,并不能真正将它们同时执行。在多核平台,各线程都是在相互独立的执行核上并行运行的,如果线程数目小于等于执行核数目,那么各行程在运行时相互之间不存在对CPU资源的竞争,在某一时刻,可以有多个线程同时运行,达到真正意义上的并行处理。

13、OpenMP缺点:(1)、不适合需要复杂的线程间同步和互斥的场合;(2)、只能在共享内存机上运行;(3)、可维护性不够好;(4)、可扩展性差;(5)、支持OpenMP的编译器一般不会自动检测是否可以正确地执行需要并行化处理的代码;(6)、不容易调试;(7)、需要一个支持OpenMP的编译器;(8)、在GPU上不能使用;(9)、多线程的可执行文件的启动需要更多的时间,可能比单线程的运行的慢,因此,使用多线程一定要有其他有优势的地方;(10)、很多情况下使用多线程不仅没有好处,还会带来一些额外消耗。

14、OpenMP优点:(1)、代码书写简单、开发时间短,不需要显示设置互斥锁、条件变量、数据范围以及初始化,通信是隐式的;(2)、移植性好,完全是与平台无关的;(3)、当带有并行结构的应用程序运行在没有多个处理器或硬件线程的目标平台上时,OpenMP会使用单线程模式,这样并不会带来额外的系统开销;(4)、在一般情况下,使用OpenMP并行时原始的(串行)代码语句不需要进行修改,这减少不经意间引入错误的机会;(5)、数据分布和分解由指令自动完成。

15、多核计算机的各个处理器都配备有自己的局部高速缓存(Cache),处理器访问自身局部缓存的速度要比访问主存或访问其他处理器的缓存快得多。因此并行化设计必须考虑如何合理地使用缓存,以避免在读写数据时产生相关冲突。为了实现快速访问缓存,对于多重嵌套循环体的并行化设计,必须遵循如下规则:第一,尽量并行化最外层循环,使得在并行区域内获得较大的计算工作量,增加其并行粒度;第二,最里层的循环变量应该是变换最快的可变下标变量,而且在最里层应该按照顺序访问数组元素,也就是应按数组列访问。这样可以提高缓存局部性。因此,数组的最左下标变量应当作为最里层的循环变量,可以保证从主存按数组列顺序把数组元素取出并放入缓存之中,从而达到快速访问缓存,提高并行效率的目的。

16、OpenMP要求并行化的代码中没有互相关联的变量。

17、编程人员一定要将并行环境中的代码运行结果与单线程环境下的该程序运行结果继续校验,以确保并行化后的代码的正确性。

18、OpenMP并行区域引用到的变量都是所有线程间共享的,三种特例除外:(1)、并行循环中的循环变量是私有的;(2)、并行区域中声明的变量是私有变量;(3)、通过private、firstprivate、lastprivate以及reduction子句声明的变量是私有变量。

19、OpenMP标准并不保证程序语义的正确性,所以,这种转化并不一定会提高程序的性能,甚至在最坏的情况下,会带来错误的结果。

20、OpenMP并行程序的编译器优化:(1)、OpenMP执行过程中,串行执行和并行执行切换带来的额外执行开销是影响OpenMP程序性能的一个重要因素;(2)、OpenMP实现共享内存编程模式,当两个或多个处理器读写相同的内存单元时,要依靠同步来保证程序的正确性,barrier是一种常用的同步方式,barrier也是影响并行性能的重要因素之一。编译器优化的目标是通过减少并行区和barrier数目,降低并行执行的开销,提高程序的性能。

21、在C/C++程序中,OpenMP的所有编译制导指令是以#pragma omp开始,后面跟具体的功能指令(或命令)。其中指令或命令是可以单独出现的,而子句必须出现在制导指令之后。

22、编译制导指令:(1)、parallel for:for循环语句之前(限制:具有规范的格式,能够推测出循环的次数,在循环过程中不能使用break、goto、return语句,可以使用continue语句,循环计算的过程中没有循环依赖性);(2)、parallel sections:多个结构块语句;(3)、single:只被单个线程执行的代码;(4)、critical:用在一段代码临界区之前,保证每次只有一个OpenMP线程进入;(5)、barrier:线程同步。

23、OpenMP的子句:(1)、firstprivate:继承主线程中同名变量的值作为初值;(2)、lastprivate:将私有变量的值在并行处理结束后复制到主线程中的同名变量;(3)、reduction:归约运算,并将结果返回给主线程同名变量。使用要求:仅在一次归约中列出归约变量,它们无法声明为常量,且它们在并行结构中无法声明为私有;(5)、nowait:忽略barrier同步;(6)、schedule:for中任务分配调度类型,包括static、 dynamic、 guided、 runtime;(7)、private:用来将一个或多个变量声明成线程私有的变量。

24、调试:首先,请务必意识到大多数错误都是竞态条件。大多数竞态条件都是由实际应被声明为私有变量的共享变量引起的。首先应查看并行区域内的变量,确保这些变量在需要时被声明为私有。同时,应检查并行结构内部被调用的函数。在默认情况下,堆栈上声明的变量为私有变量,但C/C++关键词static会改变将放在全局堆上的变量,从而使其被OpenMP循环共享。另一个常见错误是使用未经初始化的变量。请谨记私有变量在进行并行结构时没有初始值。请仅在需要时使用firstprivate和lastprivate子句来对它们进行初始化,否则会增加大量额外的开销。

25、OpenMP线程化应用的性能主要取决于以下几点:(1)、单线程代码的潜在性能;(2)、CPU占用率、闲置线程和负载平衡不足;(3)、并行执行的应用的比例;(4)、线程之间的同步和通信数量;(5)、创建、管理、销毁和同步化线程所需的开销因fork-join转换(从单线程到并行线程或从并行线程到单线程的转换)的次数的增加而增加;(6)、内存、总线带宽和CPU执行单元等共享资源的性能限制;(7)、由共享内存或错误共享内存引起的内存冲突。

26、请记住:一旦采用了OpenMP,线程数量就将由编译器来决定(而不是您),因此无论线程数量如何,重要的是使程序能够正常运行。

27、OpenMP锁在使用前需要进行初始化,不再使用时要解锁。

28、使用reduction子句进行多线程程序设计时,要记住以下三个要点:(1)、在第一个线程到达指定了reduction子句的共享区域或循环末尾时,原来的归约变量的值变为不确定,并保持此不确定状态直至归约计算完成;(2)、如果在一个循环中使用到了reduction子句,同时又使用了nowait子句,那么在确保所有线程完成归约计算的栅栏同步操作之前,原来的归约变量的值将一直保持不确定的状态;(3)、各个线程的私有副本值被归约的顺序是未指定的。因此,对于同一段程序的一次串行执行和一次并行执行,甚至两次并行执行来说,都无法保证得到完全相同的结果(这主要针对浮点计算而言),也无法保证计算过程中诸如浮点计算异常这样的行为会完全相同。

29、如果是类(class)类型的变量使用在lastprivate参数中,那么使用时有些限制,需要一个可访问的,明确的缺省构造函数,除非变量也被使用作为firstprivate子句的参数;还需要一个拷贝赋值操作符,并且这个拷贝赋值操作符对于不同对象的操作顺序是未指定的,依赖于编译器的定义。

鲜花

握手

雷人

路过

鸡蛋

最新评论

热门频道

  • 大数据
  • 商业智能
  • 量化投资
  • 科学探索
  • 创业

即将开课

热门文章

     

    GMT+8, 2020-1-21 18:47 , Processed in 0.148495 second(s), 23 queries .