本文将主要介绍在Intel® MIC多核架构上运行及优化OpenMP*多线程程序的相关技术,且将围绕offload及native两种运行时执行环境展开详解。OpenMP编程模型包含了众多调优的编程接口及环境变量设置,本文将就此继续介绍如何更好地实现程序的高效运行。
1、使用offload模式时设置MIC_ENV_PREFIX来将Host环境的设置传播至MIC(target)计算节点
2、offload模式的多种关键字
3、使用-openmp-report来了解编译器对程序中OpenMP区域的优化处理
4、在不确定offload区域正在Host还是target上计算运行时,用户可以通过在代码中加入显示当前正执行的线程数目的方法来确定
【1-4详见本系列的第一篇:‘使用OpenMP*库的编程及调优实践(1)’】
5、OepnMP在Offload及Native模式下的不同缺省值:
当运行程序通过Offload启动时,系统会默认指定一个核作为主要的调度核心,当运行上文的查看线程数目的Offload代码时,
#pragma omp parallel { #pragma omp single thread_count = omp_get_num_threads(); } cout << "Thread count: "<< thread_count << endl;
程序会返回以下结果:
Thread count: 124 Threads_max: 124 Proc count: 124 Is dynamic: 0 Is nested: 0 Sched kind: 1 Sched modifier: 0 Thread limit: 2147483647 Max Active levels: 2147483647 Active Level: 1
而当以Native程序的方式运行时,程序会返回以下结果:
Thread count: 128 Threads_max: 128 Proc count: 128 Is dynamic: 0 Is nested: 0 Sched kind: 1 Sched modifier: 0 Thread limit: 2147483647 Max Active levels: 2147483647 Active Level: 1
这两者的区别主要在于运行时可用于计算的核数,这是通过Openmp运行时环境默认设置的内核线程表及线程的亲和度affinity map来实现的。在运行一个Offload程序前可通过设置环境变量KMP_AFFINITY=verbose来打印出所有线程的affinity map:
OMP: Info #156: KMP_AFFINITY: 124 available OS procs OMP: Info #157: KMP_AFFINITY: Uniform topology OMP: Info #179: KMP_AFFINITY: 1 packages x 31 cores/pkg x 4 threads/core (31 total cores) ... OMP: Info #147: KMP_AFFINITY: Internal thread 0 bound to OS proc set {1} OMP: Info #147: KMP_AFFINITY: Internal thread 1 bound to OS proc set {5} OMP: Info #147: KMP_AFFINITY: Internal thread 2 bound to OS proc set {9} OMP: Info #147: KMP_AFFINITY: Internal thread 3 bound to OS proc set {13} OMP: Info #147: KMP_AFFINITY: Internal thread 4 bound to OS proc set {17} OMP: Info #147: KMP_AFFINITY: Internal thread 5 bound to OS proc set {21} ...
缺省的affinity属性为'fine',以确保每个线程与一个特定的逻辑CPU核紧密联系,从而操作系统不会将线程迁移至另一个CPU核。例如在以上例子中,有31核可用时,运行时产生出124个线程,登录至MIC卡上且设置KMP_AFFINITY=verbose时,运行时可看到有一个额外的CPU核是可用的:
OMP: Info #156: KMP_AFFINITY: 128 available OS procs OMP: Info #157: KMP_AFFINITY: Uniform topology OMP: Info #179: KMP_AFFINITY: 1 packages x 32 cores/pkg x 4 threads/core (32 total cores) ... OMP: Info #147: KMP_AFFINITY: Internal thread 0 bound to OS proc set {1} OMP: Info #147: KMP_AFFINITY: Internal thread 1 bound to OS proc set {5} OMP: Info #147: KMP_AFFINITY: Internal thread 2 bound to OS proc set {9} ...
硬件线程的映射结构与每一个单独的MIC设备上的核数无关,在使用Offload时,系统会从affinity map中减少一个可用的核,从而将其用于Intel协处理器负载计算服务(Intel® COI)和其它Offload相关的通信服务等。
在用户对Offload模式没有显式设置环境变量时,Offload模式的环境变量与Native模式几乎相同,在LD_LIBRARY_PATH没有被拷贝时,底层的通信库Intel COI及Intel Symmetric Communications Infrastructure (Intel® SCI)会分别单独添加一个对应的标示符,且在此时,Host的路径被一致地传到MIC端。用户可通过在Host环境设置MIC_ENV_PREFIX环境变量的方式来单独设置Offload模式:
$ export MIC_ENV_PREFIX=MIC $ ./getmyenv mic ENV: "COI_LOG_PORT=65535" ENV: "ENV_PREFIX=MIC" ENV: "PATH=/usr/bin:/bin" ENV: "SCIF_SOURCE_NODE=0" ENV: "__KMP_REGISTERED_LIB_1017=blahblahblahblah-libiomp5.so"
此时在MIC_ENV_PREFIX的限定下,Target/MIC端的环境就与Host端的环境变量保持了良好的隔离,从而避免Host端的环境变量传至MIMC端时,会影响后者的变量设置,从而影响运行时程序的性能。
值得注意的是,当在编译器初始变量设置完后,此时会发现Host端的环境变量定义了LD_LIBRARY_PATH、MIC_LD_LIBRARY_PATH ,前者用于指定Host上各种运行时库的默认查找路径,后者用于指定Offload代码所查找的Target上运行时库的路径。
6、当通过OMP_STACKSIZE设置OpenMP的的栈空间大小时,注意使用不同的控制方式来调节主从端上运行线程的栈空间大小,以及这些控制变量在主从环境中有不同的默认值。
a) 在使用KMP_STACKSIZE变量时,可用B/K/M/G/T来标记多大的Byte、KB或MB空间等,比如‘export KMP_STACKSIZE=4M
’
当单位未指定时,系统默认以字节为单位设置。KMP_STACKSIZE 的设置也会覆盖相关的OMP_STACKSIZE 变量设置,且此时如果两个变量都设置的话,运行时用户将会得到相应的提示信息。OMP_STACKSIZE也使用B/K/M/G/T来标记多大的栈空间,不过在未指定单位时,OMP_STACKSIZE的单位默认为KB。
b) 在将Host上一些计算任务Offload到Targe端且MIC_ENV_PREFIX未指定时,栈空间设置的环境变量也将会被默认拷贝到Target端,有 MIC_ENV_PREFIX指定的话,用户可以更好地在主从端定义对应的环境变量:
export MIC_ENV_PREFIX=MIC export OMP_STACKSIZE=8M export MIC_OMP_STACKSIZE=2M
值得注意的是:通常Xeon Phi协处理器会有60/61个核,每个有4个硬件线程。且运行时默认的OpenMP线程栈空间设置为4MB,所以此时系统在运行时会为所有的240个线程分配总共将近1GB的内存用于做栈空间。
除了以上的环境变量外,运行时库以为受Host端环境变量MIC_STACKSIZE设置的影响。此变量用于控制Target端Offload代码的栈空间大小,默认为12MB;在单独进程中启动的Native程序默认的栈空间为8MB。
To Be Continued...