LSF中的混合MPI/OpenMP

Lin*_*g0k 3 parallel-processing mpi openmp

我正在将一个由OpenMP并行化的程序移动到Cluster.群集使用Lava 1.0作为调度程序,每个节点有8个核心.我在作业脚本中使用MPI包装器来执行多主机并行.

这是工作脚本:

#BSUB -q queue_name
#BSUB -x

#BSUB -R "span[ptile=1]"
#BSUB -n 1

#BSUB -J n1p1o8
##BSUB -o outfile.email
#BSUB -e err

export OMP_NUM_THREADS=8

date
/home/apps/bin/lava.openmpi.wrapper -bynode -x OMP_NUM_THREADS \
    ~/my_program ~/input.dat ~/output.out 
date
Run Code Online (Sandbox Code Playgroud)

我在ONE主机上做了一些实验.但是,我不知道如何解释一些结果.

1.
-nOMP_NUM_THREADStime
1      4      21:12      
2      4      20:12      

这是否意味着MPI在这里不做任何并行?我认为在第二种情况下,每个MPI进程都有4个OMP线程,所以它应该使用800%的CPU使用率,这应该比第一个快.

另一个结果证明了这一点
-nOMP_NUM_THREADStime
2      2      31:42      
4      2      30:47      

他们也有非常接近的运行时间.

2.
在这种情况下,如果我想通过简单的方法以合理的优化速度在这个集群中并行该程序,在每个主机中放置1个MPI进程(告诉LFG我使用一个核心)是合理的,设置OMP_NUM_THREADS = 8,然后专门运行它?因此,MPI仅适用于跨节点作业,而OpenMP适用于内部节点作业.(-n =主机数; ptile = 1; OMP_NUM_THREADS =每个主机中的最大内核数)

更新: 该程序由gfortran -fopenmp编译,没有mpicc.MPI仅用于分发可执行文件.

更新3月3日: 程序内存使用情况监视器

本地环境:Mac 10.8/2.9 Ghz i7/8GB内存

没有OpenMP

  • 实内存大小:8.4 MB
  • 虚拟内存大小:2.37 GB
  • 共享内存大小:212 KB
  • 专用内存大小:7.8 Mb
  • 虚拟专用内存:63.2 MB

使用OpenMP(4个主题)

  • 实内存大小:31.5 MB
  • 虚拟内存大小:2.52 GB
  • 共享内存大小:212 KB
  • 专用内存大小:27.1 Mb
  • 虚拟专用内存:210.2 MB

群集硬件简要信息

每个主机包含双四芯片,每个节点8个内核和8GB内存.此群集中的主机通过infiniband连接.

Hri*_*iev 5

考虑到您在评论中指定的信息,您最好的选择是:

  • 请求独占节点访问-x(您已经这样做);
  • 每个节点请求一个插槽-n 1(你已经这样做了);
  • 设置OMP_NUM_THREADS为每个节点的核心数(你已经这样做了);
  • 启用OpenMP线程的绑定;
  • 直接启动可执行文件.

您的工作脚本应如下所示:

#BSUB -q queue_name
#BSUB -x
#BSUB -n 1

#BSUB -J n1p1o8
##BSUB -o outfile.email
#BSUB -e err

export OMP_NUM_THREADS=8
export OMP_PROC_BIND=true

date
~/my_program ~/input.dat ~/output.out
date
Run Code Online (Sandbox Code Playgroud)

OMP_PROC_BIND是OpenMP 3.1规范的一部分.如果使用符合旧版本标准的编译器,则应使用特定于供应商的设置,例如GOMP_CPU_AFFINITYGCC和KMP_AFFINITY英特尔编译器.将线程绑定到核心可防止操作系统在不同处理器核心之间移动线程,从而加快执行速度,尤其是在NUMA系统上(例如,每个插槽中具有多个CPU插槽和独立内存控制器的机器),其中数据位置非常重要.

如果您想在不同的输入文件上运行程序的许多副本,请提交阵列作业.使用LSF(我猜也是Lava)这是通过更改作业脚本来完成的:

#BSUB -q queue_name
#BSUB -x
#BSUB -n 1

#BSUB -J n1p1o8[1-20]
##BSUB -o outfile.email
#BSUB -e err_%I

export OMP_NUM_THREADS=8
export OMP_PROC_BIND=true

date
~/my_program ~/input_${LSF_JOBINDEX}.dat ~/output_${LSF_JOBINDEX}.out
date
Run Code Online (Sandbox Code Playgroud)

这提交了一个20个subjobs(-J n1p1o8[1-20])的数组作业.%Iin -e由作业编号替换,因此您err将从每个作业中获取单独的文件.该LSF_JOBINDEX环境变量设置为当前的工作指标,也就是说,它会1在第一份工作,2在第二个等等.


我关于你的程序的内存使用情况的问题不是关于它消耗了多少内存.它是关于在单个OpenMP循环中处理的典型数据集有多大.如果数据集不够小,无法容纳CPU的最后一级缓存,则会考虑内存带宽.如果您的代码对每个数据项执行大量本地处理,那么它可能会根据线程数进行扩展.如果在另一侧它执行简单和轻量级处理,那么即使是单个线程,内存总线也可能会饱和,特别是如果代码被正确地矢量化.通常这是通过FLOPS /字节中的所谓操作强度来测量的.它给出了从内存中提取下一个数据元素之前发生的数据处理量.高操作强度意味着在CPU中发生大量数字运算,并且数据很少转移到存储器或从存储器传输.无论内存带宽是多少,这些程序几乎都与线程数成线性关系.另一方面,操作强度非常低的代码受内存限制,导致CPU未得到充分利用.

严重受内存限制的程序不会使用数字线程进行扩展,但会使用可用的内存带宽.例如,在较新的Intel或AMD系统上,每个CPU插槽都有自己的内存控制器和内存数据路径.在这样的系统上,存储器带宽是单个插槽的带宽的倍数,例如,具有两个插槽的系统提供两倍于单插槽系统的存储器带宽.在这种情况下,每当使用两个套接字时,您可能会看到代码运行时的改进,例如,如果设置OMP_NUM_THREADS为等于核心总数或者设置OMP_NUM_THREADS为等于2并且告诉运行时将两个线程放在不同的套接字上(当线程执行矢量化代码并且单个线程能够使本地存储器总线饱和时,这是合理的情况).