【问题标题】:Running MPI code in embarrassingly parallel (on PBS-Torque cluster)以令人尴尬的并行方式运行 MPI 代码(在 PBS-Torque 集群上)
【发布时间】:2016-02-11 21:53:34
【问题描述】:

我编写了一个基于 MPI 的 C 代码,用于并行执行数值模拟。由于我的一些糟糕的设计,我在代码中内置了一些固有的 MPI 依赖项(数组结构,MPI-IO)。这意味着如果我想串行运行我的代码,我必须调用

mpiexec -n 1 c_exe

主要问题 我在 Python 工作流程中使用我的 C 代码,该工作流程在下面的循环中进行了简化。

import os 
import subprocess

homedir = os.getenv('PBS_O_WORKDIR')

nevents = 100
for ievent in range(nevents):

    perform_workflow_management()
    os.chdir(ievent)
    subprocess.call('mpiexec -n 1 c_exe', Shell=True)
    os.chdir(homedir)

Python 工作流主要用于管理并调用执行数字密集型工作的 C 代码。

Python for 循环中的任务是独立的,因此我想采用一种令人尴尬的并行方案来并行处理事件的循环。基准测试表明,对事件的循环进行并行处理将比使用并行 MPI 调用的串行循环更快。此外,我在 PBS-Torque 集群上运行它。

我不知道如何有效地做到这一点。由于对我的 C 代码的 MPI 调用和多个 MPI 任务的分配,似乎出现了复杂情况。

我以某种形式尝试过的事情

pbsdsh 的包装器 - 导致处理器分配问题。

MPMD 与 mpiexec - 理论上可以做我想做的事,但失败了,因为所有进程似乎都共享 MPI_COMM_WORLD。我的 C 代码为基于域的并行性建立了笛卡尔拓扑;冲突在这里产生。

有人对我如何以令人尴尬的并行方式实现部署有任何建议吗?理想情况下,我想提交一份工作请求

qsub -l nodes=N:ppn=1,walltime=XX:XX:XX go_python_job.bash

其中 N 是处理器的数量。然后,在每个进程上,我希望能够向我的 C 代码提交独立的 mpiexec 调用。

我知道问题的部分原因在于设计缺陷,但如果我能找到解决方案而无需重构大部分代码,那将是有利的。

【问题讨论】:

  • 1) 每个事件有多少“事件”/时间?只为每个事件启动一个作业(通过 python)可能是可行的 - 将最大数量的并行性暴露给批处理系统。这样您可以获得最佳回填 - 但您可能会使批处理系统过载。 2) 除了初始工作流管理之外,您是否尝试过将所有MPI_COMM_WORLD 实例替换为MPI_COMM_SELF
  • 因此事件通常在 100 左右,对于典型的问题大小(串行运行),每个 C 调用可能需要约 10 分钟。我没有尝试过 MPI_COMM_SELF 虽然这似乎是一个解决方案。如果我按如下方式运行 MPMD mpiexec -n 1 a.out : -n 1 b.out,并将 MPI_COMM_WORLD 替换为 MPI_COMM_SELF,每个实例是否只能访问启动它的行列?
  • 集群上每个节点是否可以执行多个作业,或者即使您只请求一个核心,您是否总是阻塞一个完整节点?
  • 我相信每个节点有多个作业是可能的。我使用 mpiexec 测试了带有 MPI_COMM_SELF 和 MPMD 调度的版本。事情似乎按预期进行。 mpiexec 分配不同的节点,MPI_COMM_SELF 用于“序列化”MPI 代码。

标签: python parallel-processing mpi pbs torque


【解决方案1】:

首先,对于任何体面的 MPI 实现,您不必使用 mpiexec 来启动单例 MPI 作业 - 只需运行可执行文件(MPI 标准,§10.5.2 单例 MPI_INIT)。它至少适用于 Open MPI 和 MPICH 系列。

其次,任何体面的 DRM(分布式资源管理器,又名批处理排队系统)都支持阵列作业。这些是 SPMD 的 DRM 等价物 - 具有相同作业文件的多个作业。

要使用 Torque 获取阵列作业,请在命令行或作业脚本中传递 qsub-t from-to 选项:

#PBS -t 1-100
...

然后,在您的 Python 脚本中获取 PBS_ARRAYID 环境变量的值并使用它来区分不同的实例:

import os 
import subprocess

homedir = os.getenv('PBS_O_WORKDIR')
ievent = os.getenv('PBS_ARRAYID')

perform_workflow_management()
os.chdir(ievent)
subprocess.call('./c_exe', Shell=True)
os.chdir(homedir)

正如@Zulan 已经提到的,这允许作业调度程序通过回填更好地利用集群的资源(如果您的 Torque 实例与 Maui 或类似的高级调度程序配对)。

数组作业的优势在于,尽管从您的角度来看,它们看起来和工作(大部分)就像一个单一的作业,但调度程序仍然将它们视为单独的作业并单独安排它们。

这种方法的一个可能的缺点是,如果作业是排他性安排的,即没有两个作业可以共享一个计算节点,那么除非您的集群节点每个只有一个单核 CPU(不太可能),否则利用率将非常低现在)。

【讨论】:

  • 很高兴知道Singleton MPI_INIT 是标准的一部分。我不想建议一个忽略 mpiexec 的解决方案,它完全依赖于实现。
  • 这很有用。我过去曾设法在没有 mpiexec 的情况下运行 ./c_exe,但不知道与 Singleton MPI_INIT 相关的规则。这样 MPI_COMM_WORLD 设置为单个进程,我的代码运行良好。至于作业数组,我避免了这一点,因为它涉及将一系列作业提交到队列。对于我的工作流程,我预先请求我的节点,然后继续从工作流程内将任务分配给节点(在主节点上运行)。如果我使用单例 MPI 调用,调用 pbsdsh 的方案是否合理?
猜你喜欢
  • 1970-01-01
  • 2020-03-29
  • 2017-04-18
  • 2022-01-13
  • 2014-02-26
  • 1970-01-01
  • 2017-02-22
  • 1970-01-01
  • 2011-04-23
相关资源
最近更新 更多