Parallel processing LSF中的混合MPI/OpenMP

Parallel processing LSF中的混合MPI/OpenMP,parallel-processing,mpi,openmp,Parallel Processing,Mpi,Openmp,我正在将OpenMP并行化的程序移动到集群。集群使用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

我正在将OpenMP并行化的程序移动到集群。集群使用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
#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
我只在一台主机上做了一些实验。然而,我不知道如何解释一些结果

一,。
-nOMP_NUM_THREADStime
1421:12
2420:12

这是否意味着MPI在这里没有任何并行功能?我认为在第二种情况下,每个MPI进程将有4个OMP线程,因此它应该使用800%的CPU使用率,这应该比第一种更快

证明这一点的另一个结果是
-nOMP_NUM_THREADStime
2231:42
4230:47

它们的运行时间也非常接近

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

更新: 该程序由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连接。

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

  • 使用
    -x
    请求独占节点访问(您已经这样做了)
  • 使用
    -n1
    为每个节点请求一个插槽(您已经这样做了)
  • OMP\u NUM\u 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
OMP\u PROC\u BIND
是OpenMP 3.1规范的一部分。如果使用的编译器遵循较旧版本的标准,则应使用特定于供应商的设置,例如,对于GCC使用
GOMP\u CPU\u AFFINITY
,对于英特尔编译器使用
KMP\u AFFINITY
。将线程绑定到内核可防止操作系统在不同处理器内核之间的线程之间移动,从而加快执行速度,特别是在NUMA系统上(例如,具有多个CPU插槽的机器,每个插槽中有单独的内存控制器),其中数据位置非常重要

如果要在不同的输入文件上运行程序的多个副本,请提交数组作业。使用LSF(我猜也可以使用Lava),这是通过更改作业脚本来完成的:

#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
#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
这将提交20个子对象的数组作业(
-jn1p1o8[1-20]
)<
-e
中的code>%I被作业编号替换,因此您将从每个作业中获得一个单独的
err
文件。
LSF_JOBINDEX
环境变量被设置为当前作业索引,即第一个作业中为
1
,第二个作业中为
2
,依此类推


我关于你的程序内存使用的问题不是关于它消耗了多少内存。它是关于在单个OpenMP循环中处理的典型数据集有多大。如果数据集不够小,无法放入CPU的最后一级缓存,则需要考虑内存带宽。如果您的代码对每个数据项进行大量的本地处理,那么它可能会随着线程数的增加而增加。另一方面,如果它进行简单而轻松的处理,那么内存总线甚至可能被单个线程饱和,特别是如果代码被正确地矢量化。通常这是通过所谓的运算强度(以浮点/字节为单位)来衡量的。它给出了从内存中提取下一个数据元素之前发生的数据处理量。高操作强度意味着大量的数字运算发生在CPU中,数据很少从内存传输到内存。无论内存带宽是多少,这样的程序几乎与线程数成线性关系。另一方面,操作强度非常低的代码被内存限制,导致CPU未充分利用


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

这里的大多数人都不是通灵者。您可以从描述您的计算算法、其内存需求和计算强度开始(最好以浮点/字节为单位)。然后告诉我们每个群集节点的CPU类型有哪些硬件