Makefile 使用-fopenmp标志编译时,MPI代码要慢得多(对于使用多线程的MPI)

Makefile 使用-fopenmp标志编译时,MPI代码要慢得多(对于使用多线程的MPI),makefile,compilation,mpi,openmp,hybrid,Makefile,Compilation,Mpi,Openmp,Hybrid,我用mpif90编译器用两个不同的Makefile编译Fortran 90代码,第一个看起来像 FC = mpif90 FFLAGS = -Wall -ffree-line-length-none FOPT = -O3 all: ParP2S.o ParP2S ParP2S.o: ParP2S.f90 $(FC) $(FFLAGS) $(FOPT) ParP2S.f90 -c ParP2S: ParP2S.o $(FC) $(FFLAGS) $(FOPT) P

我用mpif90编译器用两个不同的Makefile编译Fortran 90代码,第一个看起来像

FC = mpif90
FFLAGS = -Wall -ffree-line-length-none 
FOPT = -O3

all: ParP2S.o ParP2S
ParP2S.o: ParP2S.f90
        $(FC) $(FFLAGS) $(FOPT) ParP2S.f90 -c
ParP2S: ParP2S.o
        $(FC) $(FFLAGS) $(FOPT) ParP2S.o -o ParP2S
clean: 
        rm -f *.o* rm -f *.o* 
第二个makefile看起来非常相似,我只是添加了-fopenmp标志

FC = mpif90
FFLAGS = -Wall -ffree-line-length-none -fopenmp
FOPT = -O3

all: ParP2S.o ParP2S
ParP2S.o: ParP2S.f90
        $(FC) $(FFLAGS) $(FOPT) ParP2S.f90 -c
ParP2S: ParP2S.o
        $(FC) $(FFLAGS) $(FOPT) ParP2S.o -o ParP2S
clean: 
        rm -f *.o* rm -f *.o* 
第二个生成文件用于混合(MPI和OpenMP)版本的代码。现在,我有完全相同的代码,但使用这些不同的makefile编译。在第二种情况下,代码的速度要慢100倍以上。对我做错了什么有什么评论吗

编辑1:我没有运行多线程任务。事实上,该代码没有任何OpenMP指令,它只是纯MPI代码,但使用不同的makefile编译。尽管如此,我还是试着按照下面的命令运行(见下文),但没有任何帮助

export MV2_ENABLE_AFFINITY=0
export OMP_NUM_THREADS=1
export OMP_PROC_BIND=true
mpirun -np 2 ./ParP2S

编辑2:我使用的是gcc版本4.9.2(我知道在旧版本中fopenmp的矢量化有一个bug)。我认为包含-fopenmp标志可能会抑制编译器优化,但是,在阅读了有趣的讨论()之后,我不确定是否是这种情况。此外,由于我的代码没有任何OpenMP指令,我不明白为什么用-fopenmp编译的代码应该那么慢


edit3:当我在没有-fopenmp(第一个makefile)的情况下运行时,没有优化(-O0)大约需要0.2秒,优化(-O3)大约需要0.08秒,但是包括-fopenmp标志,使用-O3或-O0大约需要11秒。

事实证明,问题实际上是任务相关性,正如Vladimir F和Gilles Gouellardet所建议的那样(非常感谢!)

首先,我意识到我使用OpenMPI版本1.6.4运行MPI,而不是MVAPICH2,因此命令
export MV2\u ENABLE\u AFFINITY=0
在这里没有实际意义。其次,我(可能)通过设置

export OMP_PROC_BIND=true
export OMP_PLACES=cores
但是我没有为MPI进程设置正确的绑定,因为我错误地将应用程序作为

mpirun -np 2 ./Par2S
而且,对于OpenMPI版本1.6.4,更合适的方法似乎是

mpirun -np 2 -bind-to-core -bycore -cpus-per-proc 2  ./hParP2S
命令
-bind to core-bycore-cpu per proc 2
确保我的应用程序有两个内核(请参阅和Gilles Gouailladet的评论)。如果没有它,两个MPI进程都将使用一个内核,这就是在Makefile中使用标记
-fopenmp
时代码效率低下的原因

显然,当运行未使用
-fopenmp
标记编译的纯MPI代码时,不同的MPI进程会自动转到不同的内核,但使用
-fopenmp
时,需要如上所述手动指定绑定

作为一个完整性问题,我应该提到,没有设置正确任务关联的标准,因此我的解决方案将不适用于例如MVAPICH2或(可能)不同版本的OpenMPI。此外,在ncores CPU中运行nproc MPI进程时,每个进程都需要n个线程,例如

export OMP_PROC_BIND=true
export OMP_PLACES=cores
export OMP_NUM_THREADS=nthreads

mpirun -np nproc -bind-to-core -bycore -cpus-per-proc ncores ./hParP2S

其中ncores=nproc*nthreads


ps:我的代码有一个MPI_all_to_all。在一个单核上有多个MPI进程(没有超线程)调用此子例程的情况下,应该是代码速度慢100倍的原因。

请编辑您的问题并添加启动应用程序的方式(您将平面n MPI任务与混合NxM运行进行比较)。如果每个任务运行多个OpenMP线程,则MPI任务不固定在单个核心上是至关重要的。FWIW,
mpirun--oversubscribe…
值得在Open MPI上尝试。检查每个线程运行在哪个核心上。尝试使用
top
检查核心占用情况。我没有使用多线程,没有OpenMP direct在我的代码中添加。除非您可以发布一个,否则我建议您尝试其他编译器和/或配置您的应用程序,以确定在OpenMP“模式”下的时间花费在哪里。如果您可以使用一个MPI任务运行程序,而不使用
mpirun
,则您可能也想尝试一下。如果MPI任务具有重叠的核心集(在本例中为所有内核),OpenMP运行时确实存在将不同MPI任务固定到同一内核的风险(在本例中,所有MPI任务固定在第一个内核上)绑定MPI+OpenMP应用程序实际上是两步探戈:让MPI为MPI任务分配非重叠的核心,然后让OpenMP运行时将其线程绑定到分配的核心集中。