5

OpenMP与性能相关的几个环境变量

 9 months ago
source link: https://itlanyan.com/openmp-performance-environments/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

OpenMP 是由计算机硬件和软件厂商共同制定的一组 面向共享内存多线程并行接口具体并行实现由编译器负责。同一套OpenMP程序代码,可运行在 WindowsMacOSLinux 等多个操作系统及硬件平台,具有良好的可移植性。

OpenMP程序的性能及行为与环境变量密切相关,本文简要介绍与性能相关的几个环境变量。

OpenMP环境变量

OMP_NUM_THREADS

OMP_NUM_THREADS 应该是最常用的环境变量了,其设置parallel区域的初始线程数,大多数OpenMP实现的默认值是可用逻辑CPU数量(可能有上限,例如32)。现代CPU一般开启了超线程技术,为了最大性能,建议将值设置为不超过物理CPU数。

具体parallel区域的执行线程数,除了该环境变量控制,还与 omp_set_num_threads 设置的值、 制导语句的 num_threads 值、OMP_DYNAMIComp_set_dynamic 等有关系。

使用示例:

# 默认使用4个线程
OMP_NUM_THREADS=4

# 第一层默认4个线程,第二层2个,第三层1个
OMP_NUM_THREADS=4,2,1

OMP_SCHEDULE

OMP_SCHEDULE 用来指定循环的调度方式,默认值一般是 static 或者 dynamic,其它可用值包括guidedauto/runtime,其中auto/runtime不是真实调度方式。staticdynamicguided的区别为:

  • 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 用于指定线程的默认行为,可用的值有 activepassive,大多数实现默认值是 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_PLACESOMP_PROC_BIND进行线程绑定。

1. OpenMP官网

2. 一些常规性能建议


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK