OpenMP 是由计算机硬件和软件厂商共同制定的一组 面向共享内存多线程并行接口,具体并行实现由编译器负责。同一套OpenMP程序代码,可运行在 Windows、MacOS、Linux 等多个操作系统及硬件平台,具有良好的可移植性。
OpenMP程序的性能及行为与环境变量密切相关,本文简要介绍与性能相关的几个环境变量。
OpenMP环境变量
OMP_NUM_THREADS
OMP_NUM_THREADS
应该是最常用的环境变量了,其设置parallel区域的初始线程数,大多数OpenMP实现的默认值是可用逻辑CPU数量(可能有上限,例如32)。现代CPU一般开启了超线程技术,为了最大性能,建议将值设置为不超过物理CPU数。
具体parallel区域的执行线程数,除了该环境变量控制,还与 omp_set_num_threads
设置的值、 制导语句的 num_threads
值、OMP_DYNAMIC
、omp_set_dynamic
等有关系。
使用示例:
# 默认使用4个线程 OMP_NUM_THREADS=4 # 第一层默认4个线程,第二层2个,第三层1个 OMP_NUM_THREADS=4,2,1
OMP_SCHEDULE
OMP_SCHEDULE
用来指定循环的调度方式,默认值一般是 static
或者 dynamic
,其它可用值包括guided
和 auto/runtime
,其中auto/runtime不是真实调度方式。static
、dynamic
和guided
的区别为:
static
: 将循环划分为若干个大致相等的块,并将每个块分配给一个线程,适用于循环迭代次数可以预先确定的情况。需要注意该调度方式也允许指定块大小chunk_size
,推荐用于每个循环计算量基本相同的场景,开销最小;dynamic
:动态地将循环划分为若干块,并将块分配给不同的线程,适用于循环迭代次数不能预先确定,或者每个任务的计算量差异较大的情况,能实现更好的负载均衡;和static
不同,任务执行的线程和顺序都是不确定的;guided
:和dynamic
类似,但开始区间很大,然后逐渐减少执行区间,直到块大小小于或者等于指定的chunk_size
,和dynamic
相比运行时开销更大;
使用示例
OMP_SCHEDULE=static OMP_SCHEDULE=dynamic OMP_SCHEDULE="dynamic,4" OMP_SCHEDULE="guided,3"
OMP_DYNAMIC
OMP_DYNAMIC
设置是否允许动态调整线程数量。当值为 true 时,运行时库会根据系统资源状况动态调整线程数目;当值为 false 时,动态调整被关闭。除了该环境变量,还可以通过 omp_set_dynamic
函数设置是否允许动态调整线程数。
使用示例:
OMP_DYNAMIC=true
OMP_NESTED
OMP_NESTED
设置是否允许嵌套并行。当值为 true 时,嵌套并行性允许;当值为 false 时,嵌套的并行块被当作串行部分执行,大多数实现的缺省值为 false。
使用示例:
OMP_NESTED=true
OMP_PROC_BIND
OMP_PROC_BIND
用于指定线程的绑定策略,在OpenMP 4.0之前值为true或者false,表示是否将CPU与线程绑定。OpenMP 4.0开始,OMP_PROC_BIND
可用的值还有close、master和spread的组合。其中 close 表示线程应该尽可能靠近,master表示线程尽可能靠近主线程,spread则是线程尽可能分开。
使用示例:
OMP_PROC_BIND=spread OMP_PROC_BIND="spread, spread, close"
OMP_PLACES
OMP_PLACES
是OpenMP 4.0新增的环境变量,常和 OMP_PROC_BIND
组合使用指定线程绑定策略。OMP_PLACES
指定线程可用的CPU资源,取值可以比较复杂,但是提供了三个简单的名称:
threads
:每个位置对应主机上的物理线程,开启超线程的情况下,threads表示虚拟线程;cores
:每个位置对应主机上的一个CPU核心;sockets
:每个位置对应主机上的一块CPU,一般个人电脑上只有一块CPU,服务器/工作站有多块CPU;
如果可用的位置不够,具体的线程绑定与实现有关。
使用示例:
OMP_PLACES=threads
OMP_WAIT_POLICY
OMP_WAIT_POLICY
用于指定线程的默认行为,可用的值有 active
和 passive
,大多数实现默认值是 passive
。当值为 active
时,即使线程没有分配任务,也会通过自旋锁等方式消耗CPU。
使用示例:
OMP_WAIT_POLICY=active
OMP_DISPLAY_ENV
OMP_DISPLAY_ENV
是OpenMP 4.0新加进来的环境变量,用来打印OpenMP环境变量的初始值,主要用来调试,默认值是false。如果想查看环境变量是否设置正确,可将值设置为true,会打印类似如下信息:
OPENMP DISPLAY ENVIRONMENT BEGIN _OPENMP = '201511' OMP_DYNAMIC = 'TRUE' OMP_NESTED = 'FALSE' OMP_NUM_THREADS = '4' OMP_SCHEDULE = 'DYNAMIC' OMP_PROC_BIND = 'FALSE' OMP_PLACES = '' OMP_STACKSIZE = '0' OMP_WAIT_POLICY = 'PASSIVE' OMP_THREAD_LIMIT = '4294967295' OMP_MAX_ACTIVE_LEVELS = '2147483647' OMP_CANCELLATION = 'FALSE' OMP_DEFAULT_DEVICE = '0' OMP_MAX_TASK_PRIORITY = '0' OPENMP DISPLAY ENVIRONMENT END
主流编译器对OpenMP标准支持
由于OpenMP的并行实现由编译器完成,因此使用的编译器是否支持相应标准非常重要,对于不支持的特性语句,编译器一般是直接忽略。这里参考官网简要介绍主流编译器对OpenMP标准支持程度,数据更新于2022年11月。
- GCC:GCC 4.9版本开始完全支持OpenMP 4.0标准,GCC 6对C/C++完全支持OpenMP 4.5标准,GCC 9对C/C++开始支持OpenMP 5.0,GCC 11对Fortran完全支持OpenMP 4.5,对C/C++开始支持OpenMP 5.0, GCC 12开始支持OpenMP 5.1, GCC 13开始支持OpenMP 5.2;
- Intel编译器:12.0完全支持OpenMP 3.1,15.0开始支持OpenMP 4.0,17.0开始支持OpenMP 4.5, 2021.1开始支持OpenMP 5.1
- LLVM/CLang:Clang 3.9开始支持OpenMP 4.5,Clang 8.0支持offload到GPU,Clang 11.0开始默认启用OpenMP 5.0标准,同时部分OpenMP 5.1特性;
- MSVC:最拉垮的,完全支持的只有OpenMP 2.0标准,VS 2022 17.2开始完全支持OpenMP 2.5标准以及部分OpenMP 3.1标准;OpenMP中的SIMD特性需要加
-openmp:experimental
才能开启 - NVCC:完全支持OpenMP 3.1,部分支持OpenMP 4.0、4.5、5.0、5.1等标准。
注意事项
1. 当环境变量的值是非法值时,其实际值由实现决定;
2. 环境变量的值不区分大小写,并且和顺序无关;
3. 性能建议:请根据作业的具体情况设置默认调度方式,强烈建议设置 OMP_PLACES
和 OMP_PROC_BIND
进行线程绑定。
参考
1. OpenMP官网
2. 一些常规性能建议
发表回复