4.15. 打包者建议

4.15.1. 请勿使用Open MPI的内部依赖库

Open MPI社区强烈建议二进制Open MPI软件包不应包含Hwloc、Libevent、PMIx或PRRTE。尽管其中多个库是Open MPI所必需的(因此为方便终端用户已捆绑在Open MPI源代码发行版中),但二进制Open MPI软件包应仅限包含Open MPI自身的构件。具体而言:请确保针对这些必需软件包的外部安装来配置和构建Open MPI。

因此,打包人员可能希望使用类似以下配置来设置Open MPI:

# Install Sphinx so that Open MPI can re-build its docs with the
# installed PRRTE's docs

virtualalenv venv
. ./venv/bin/activate
pip install docs/requirements.txt

./configure --with-libevent=external --with-hwloc=external \
    --with-pmix=external --with-prrte=external ...

重要

注意安装Sphinx工具,以便OpenMPI能够与外部PRRTE文档一起重新构建其文档。

如果不这样做,Open MPI的文档将仅适用于其发行版中捆绑的PRRTE版本,但可能不完全适用于您正在构建的PRRTE版本。

external 关键字会强制 Open MPI 的 configure 忽略所有捆绑的库,仅查找这些支持库的外部版本。 这样做的好处是,如果 configure 无法在 Open MPI 源代码树之外 找到所需的支持库,就会失败——这是一个很好的完整性检查, 可以确保您的包正确依赖于独立构建和安装的版本。

参见本节获取更多关于所需支持库--with-FOO命令行选项的信息。

4.15.2. 安装Sphinx

由于您需要(将会)针对外部PRRTE和PMIx安装Open MPI,因此在运行Open MPI的configure脚本之前,您应该已经安装了Sphinx

这将允许Open MPI根据您正在构建的PMIx和PRRTE(重新)生成其文档。

To be clear: the Open MPI distribution tarball comes with pre-built documentation — rendered in HTML and nroff — that is suitable for the versions of PRRTE and PMIx that are bundled in that tarball.

然而,如果您正在针对非捆绑版本的PRRTE/PMIx构建Open MPI(所有打包者都应如此操作),Open MPI需要使用这些外部PRRTE/PMIx安装中的特定信息重新构建其文档。为此,您需要在运行Open MPI的configure脚本之前安装Sphinx。

4.15.3. 组件(“插件”):静态库还是动态共享对象?

Open MPI 包含大量组件(有时称为“插件”),用于实现 MPI 中的不同类型功能。例如,某些组件影响 Open MPI 的网络功能:它们可能链接专门的库以提供高度优化的网络访问。

Open MPI 可以将其组件构建为动态共享对象(DSO),也可以静态包含在核心库中(无论这些库是构建为共享库还是静态库)。

注意

从Open MPI v5.0.x版本开始,configure的全局默认设置是将所有组件构建为静态库(即作为Open MPI核心库的一部分,而非动态共享对象)。在Open MPI v5.0.0之前,全局默认行为是将大多数组件构建为动态共享对象。

4.15.3.1. 为什么将组件构建为动态共享对象(DSOs)?

将组件构建为DSO(动态共享对象)具有以下优势:

  • Open MPI的核心库——以及基于它的MPI应用程序——将具有极少的依赖项。例如,如果您构建Open MPI时支持特定的网络协议栈,该协议栈中的库将成为动态共享对象(DSO)的依赖项,而非Open MPI核心库(或MPI应用程序)的依赖项。

  • 移除不需要的Open MPI功能非常简单,只需从$libdir/open-mpi中删除相应的DSO即可。

4.15.3.2. 为什么将组件构建为Open MPI核心库的一部分?

将组件作为Open MPI核心库的一部分构建的最大优势在于,当Open MPI安装在网络文件系统(而非本地文件系统)上时,能够在(极)大规模运行时体现。

例如,考虑在1000个节点上各启动一个MPI进程。在这种情况下,以下内容会从网络文件系统中访问:

  1. MPI应用程序

  2. Open MPI核心库及其依赖项(例如:libmpi

    • 根据您的配置,这大约需要10-20个库文件。

  3. 所有DSO组件文件及其依赖项

    • 根据您的配置,这可能涉及200多个组件文件。

如果所有组件都物理存在于库中,那么第三步将加载零个DSO组件文件。当在大规模启动时使用网络文件系统时,这可以转化为显著的性能节省。

注意

如果不使用网络文件系统,或者不是大规模启动,加载大量DSO文件在MPI进程启动期间可能不会消耗显著的时间。简而言之:将DSO作为单独文件加载通常只在使用网络文件系统且大规模启动时才有影响。

4.15.3.3. 直接控制将组件构建为DSO或非DSO

Open MPI v5.0.x 在配置时有两个默认设置,可能对软件包维护者感兴趣:

  1. Open MPI的库默认构建为共享库(而非静态库)。例如在Linux系统上,Open MPI默认会构建libmpi.so(而非libmpi.a)。

    注意

    关于如何修改此默认设置,请参阅本节中对--disable-shared--enable-static参数的说明。

    同时请务必查看关于构建静态应用程序的警告说明

  2. Open MPI默认会将组件包含在其库中(而不是编译为动态共享对象,即DSOs)。例如,Linux系统上的libmpi.so将包含UCX PML组件,而不是将UCX PML编译到mca_pml_ucx.so中并通过dlopen(3)在运行时动态加载。

    注意

    有关如何更改此默认设置的更多详细信息,请参阅本节--enable-mca-dso--enable-mca-static的描述。

这两个默认设置的副作用是,Open MPI库中包含的所有组件都会携带它们的依赖项。例如(在Linux系统上),如果MPI层中的XYZ PML组件需要libXYZ.so,那么这些默认设置意味着libmpi.so将依赖于libXYZ.so。这种依赖关系很可能会传递到包含libmpi.so的Open MPI二进制包中。

反之,如果XYZ PML组件被构建为动态共享对象(DSO),那么——假设Open MPI的其他部分都不需要libXYZ.so——libmpi.so不会依赖于libXYZ.so。相反,mca_pml_xyz.so这个DSO将会依赖于libXYZ.so

打包人员可以利用这些特性,通过例如使用--enable-mca-dso选择性地将某些组件构建为动态共享对象(DSO),而将其他组件保留在各自的Open MPI库中,从而可能创建具有不同依赖关系的多个二进制Open MPI软件包。

参见构建加速器支持部分,这是一个实际应用场景的示例。

4.15.3.4. GNU Libtool依赖扁平化

当将Open MPI的组件静态编译为Open MPI核心库的一部分时,GNU Libtool——作为Open MPI构建系统的一部分使用——会尝试"扁平化"依赖关系。

例如,ompi_info(1)命令会链接到Open MPI核心库libopen-pal。该库将依赖于各种高性能计算(HPC)类网络栈库。为简化说明,下文假设Open MPI构建时已支持LibfabricUCX,因此libopen-pal会直接依赖于libfabriclibucx

在此场景中,GNU Libtool将自动尝试通过直接将ompi_info(1)链接到libfabriclibucx(而不是让libopen-pal在运行时引入依赖项)来"扁平化"这些依赖关系。

  • 在某些环境(如Ubuntu 22.04)中,编译器或链接器会自动使用链接器CLI标志-Wl,--as-needed,这将导致这些依赖项不会被扁平化:ompi_info(1)不会直接依赖于libfabriclibucx

  • 在其他环境(如Fedora 38)中,编译器和链接器不会使用-Wl,--as-needed链接器CLI标志。因此,ompi_info(1)将显示对libfabriclibucx的直接依赖。

需要明确的是:这些扁平化的依赖关系并不是问题。无论是否存在扁平化依赖,Open MPI都能正常运行。拥有或不拥有扁平化依赖都不会影响性能。我们在文档中提到这种情况,仅仅是因为一些Open MPI下游包管理器发现ompi_info(1)在Open MPI v5.0.x版本中比之前版本有更多的共享库依赖关系时感到惊讶。

如果打包人员希望ompi_info(1)不包含这些扁平化的依赖项,可以使用以下任一机制:

  1. 使用 --enable-mca-dso 强制将所有组件构建为 DSO(这实际上是 Open MPI v5.0.0 之前的默认行为)。

  2. 在构建Open MPI时,向configure命令行添加LDFLAGS=-Wl,--as-needed

    注意

    Open MPI社区特意选择不自动使用此链接器标志,原因如下:

    1. 扁平化的依赖关系不会导致任何正确性或性能问题。

    2. 用户或打包者可以通过多种机制(如上所述)根据需要更改此行为。

    3. 某些环境选择启用或禁用这种扁平化的依赖行为。Open MPI不会覆盖这些选择。

    4. 一般来说,Open MPI的configure脚本仅在需要时才会使用编译器和链接器标志。所有其他标志应由用户/打包者自行决定。

4.15.3.5. 将加速器支持构建为动态共享对象(DSO)

如果您正在构建一个包含对一种或多种加速器支持的软件包,可能需要将加速器相关组件构建为动态共享对象(DSO)(详情请参阅静态库还是DSO?章节)。

基本原理

加速器硬件价格昂贵,可能仅存在于HPC集群的部分计算节点上。具体而言:HPC集群的"头节点"或编译节点上可能完全没有加速器硬件。因此,在"头节点"上调用已静态集成加速器支持但未配备加速器硬件的Open MPI命令时,可能会因运行时链接器问题而无法启动(因为加速器硬件支持库很可能不存在)。

将Open MPI的加速器相关组件构建为动态共享对象(DSO),使得Open MPI能够尝试加载这些加速器组件,即使由于缺少支持库而导致这些DSO加载失败,程序仍可继续运行。

使用--enable-mca-dso命令行参数配置Open MPI的configure命令,可以让打包程序将所有加速器相关组件构建为DSO。例如:

# Build all the accelerator-related components as DSOs (all other
# components will default to being built in their respective
# libraries)
shell$ ./configure --enable-mca-dso=btl-smcuda,rcache-rgpusm,rcache-gpusm,accelerator

根据上面的示例,这允许将$libdir打包为Open MPI主二进制包的一部分,而将$libdir/openmpi/mca_accelerator_*.so和其他指定组件打包为子包。例如,这些子包可能会继承对CUDA和/或ROCM包的依赖关系。主包可以安装在所有节点上,而特定加速器的子包可以仅安装在具有加速器硬件和支持库的节点上。