mpi4py Split_type 使用 openmpi 的 OMPI_COMM_TYPE_SOCKET
mpi4py Split_type using openmpi's OMPI_COMM_TYPE_SOCKET
是否可以在 mpi4py 中使用 openmpi 的 OMPI_COMM_TYPE_SOCKET 拆分通信器?
我已经验证了这个有效:
from mpi4py import MPI
comm = MPI.COMM_WORLD
sharedcomm = comm.Split_type(MPI.COMM_TYPE_SHARED)
但这不是:
socketcomm = comm.Split_type(MPI.OMPI_COMM_TYPE_SOCKET)
这也不行:
socketcomm = comm.Split_type(MPI.COMM_TYPE_SOCKET)
我查看了文档,但找不到任何相关信息。
mpi4py
仅提供标准 MPI 功能的包装器。 OMPI_COMM_TYPE_SOCKET
是 Open MPI 特定的拆分类型。如果您知道它的数值,您仍然可以在 mpi4py
中使用它,因为它只是 C enum
:
的成员
/*
* Communicator split type constants.
* Do not change the order of these without also modifying mpif.h.in
* (see also mpif-common.h.fin).
*/
enum {
MPI_COMM_TYPE_SHARED,
OMPI_COMM_TYPE_HWTHREAD,
OMPI_COMM_TYPE_CORE,
OMPI_COMM_TYPE_L1CACHE,
OMPI_COMM_TYPE_L2CACHE,
OMPI_COMM_TYPE_L3CACHE,
OMPI_COMM_TYPE_SOCKET, // here
OMPI_COMM_TYPE_NUMA,
OMPI_COMM_TYPE_BOARD,
OMPI_COMM_TYPE_HOST,
OMPI_COMM_TYPE_CU,
OMPI_COMM_TYPE_CLUSTER
};
#define OMPI_COMM_TYPE_NODE MPI_COMM_TYPE_SHARED
作为 enum
的成员意味着 OMPI_COMM_TYPE_SOCKET
的实际数值取决于它在 enum
中的位置,因此可能会从一个版本的 Open MPI 到另一个版本.您在这里有多种选择。
硬编码值
这是最简单的选项。打开 mpi.h
(ompi_info --path incdir
给你它的位置),计算 OMPI_COMM_TYPE_SOCKET
在封闭的 enum
中的位置,从 0
开始 MPI_COMM_TYPE_SHARED
和硬编码价值。代码可能会因与您不同的 Open MPI 版本而中断。
解析mpi.h
阅读 mpi.h
,搜索 enum
定义并找到包含 OMPI_COMM_TYPE_SOCKET
的定义。假设 MPI_COMM_TYPE_SHARED
是 0
,OMPI_COMM_TYPE_SOCKET
的值是它在枚举值序列中从 0 开始的索引。这在很大程度上取决于 mpi.h
中具有特定格式的代码,如果发生变化,很容易中断。
解析mpif.h
Fortran 接口更容易解析,因为那里的值定义为:
parameter (OMPI_COMM_TYPE_SOCKET=6)
这很容易用简单的正则表达式解析。问题是 Open MPI 的最新版本将 mpif.h
拆分为几个文件,然后从 mpif.h
中包含这些文件,目前该值在 mpif-constants.h
中。因此,您可能需要解析 include
语句并递归到它们引用的文件中。请注意,这些是 Fortran include
语句而不是预处理器 #include
指令。
代码生成
编写一个小的 C 程序,将 OMPI_COMM_TYPE_SOCKET
的值输出到 Python 文件并 运行 它作为程序设置过程的一部分。类似于:
#include <stdio.h>
#include <mpi.h>
int main (int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: mkompimod /path/to/module.py\n");
return 1;
}
FILE *fh = fopen(argv[1], "w");
if (fh != NULL) {
fprintf(fh, "COMM_TYPE_SOCKET = %d\n", OMPI_COMM_TYPE_SOCKET);
fclose(fh);
}
return 0;
}
将其放入名为 mkompimod.c
的文件中。用mpicc -o mkompimod mkompimod.c
和运行用mkompimod /path/to/ompi.py
编译,创建一个Python文件ompi.py
,值为OMPI_COMM_TYPE_SOCKET
。导入它并在对 comm.Split_type()
:
的调用中使用它
import ompi
socketcomm = comm.Split_type(ompi.COMM_TYPE_SOCKET)
用C写一个Python模块
这有点复杂,但您可以编写一个包含 mpi.h
并将 OMPI_COMM_TYPE_SOCKET
的值导出为 Python 常量的 C 模块。参考 Python documentation 如何用 C 编写扩展。
使用 CFFI 模块
CFFI 可让您构建 Python 模块,这些模块包装 C 库并为您编写所有粘合代码。将以下内容放入名为 ompi_build.py
的文件中:
from cffi import FFI
ffi = FFI()
ffi.set_source("ompi", r"#include <mpi.h>")
ffi.cdef(
r"""
const int OMPI_COMM_TYPE_HWTHREAD;
... more constants here ...
const int OMPI_COMM_TYPE_SOCKET;
... even more constants here ...
"""
)
if __name__ == "__main__":
ffi.compile(verbose=True)
运行 像这样:
$ CC=mpicc python ompi_build.py
这将创建 C 模块 ompi.c
并将其编译成可加载的 DSO。然后您可以导入它并像这样访问常量:
from ompi.lib import OMPI_COMM_TYPE_SOCKET
socketcomm = comm.Split_type(OMPI_COMM_TYPE_SOCKET)
CFFI 提供与 Python 的 distutils
的集成,您可以让它在设置过程中自动构建 C 模块。
使用 Cython
这就是 mpi4py
本身所写的内容。它将 C 和 Python 混合成一个单一的神秘语法。阅读源代码。试着弄清楚发生了什么,以及如何自己写一些东西。帮不了你。
无论您选择哪条路径,请记住,所有这些都与程序 运行 所在的系统有关,而不仅仅是程序将在其上开发的系统。
是否可以在 mpi4py 中使用 openmpi 的 OMPI_COMM_TYPE_SOCKET 拆分通信器?
我已经验证了这个有效:
from mpi4py import MPI
comm = MPI.COMM_WORLD
sharedcomm = comm.Split_type(MPI.COMM_TYPE_SHARED)
但这不是:
socketcomm = comm.Split_type(MPI.OMPI_COMM_TYPE_SOCKET)
这也不行:
socketcomm = comm.Split_type(MPI.COMM_TYPE_SOCKET)
我查看了文档,但找不到任何相关信息。
mpi4py
仅提供标准 MPI 功能的包装器。 OMPI_COMM_TYPE_SOCKET
是 Open MPI 特定的拆分类型。如果您知道它的数值,您仍然可以在 mpi4py
中使用它,因为它只是 C enum
:
/*
* Communicator split type constants.
* Do not change the order of these without also modifying mpif.h.in
* (see also mpif-common.h.fin).
*/
enum {
MPI_COMM_TYPE_SHARED,
OMPI_COMM_TYPE_HWTHREAD,
OMPI_COMM_TYPE_CORE,
OMPI_COMM_TYPE_L1CACHE,
OMPI_COMM_TYPE_L2CACHE,
OMPI_COMM_TYPE_L3CACHE,
OMPI_COMM_TYPE_SOCKET, // here
OMPI_COMM_TYPE_NUMA,
OMPI_COMM_TYPE_BOARD,
OMPI_COMM_TYPE_HOST,
OMPI_COMM_TYPE_CU,
OMPI_COMM_TYPE_CLUSTER
};
#define OMPI_COMM_TYPE_NODE MPI_COMM_TYPE_SHARED
作为 enum
的成员意味着 OMPI_COMM_TYPE_SOCKET
的实际数值取决于它在 enum
中的位置,因此可能会从一个版本的 Open MPI 到另一个版本.您在这里有多种选择。
硬编码值
这是最简单的选项。打开 mpi.h
(ompi_info --path incdir
给你它的位置),计算 OMPI_COMM_TYPE_SOCKET
在封闭的 enum
中的位置,从 0
开始 MPI_COMM_TYPE_SHARED
和硬编码价值。代码可能会因与您不同的 Open MPI 版本而中断。
解析mpi.h
阅读 mpi.h
,搜索 enum
定义并找到包含 OMPI_COMM_TYPE_SOCKET
的定义。假设 MPI_COMM_TYPE_SHARED
是 0
,OMPI_COMM_TYPE_SOCKET
的值是它在枚举值序列中从 0 开始的索引。这在很大程度上取决于 mpi.h
中具有特定格式的代码,如果发生变化,很容易中断。
解析mpif.h
Fortran 接口更容易解析,因为那里的值定义为:
parameter (OMPI_COMM_TYPE_SOCKET=6)
这很容易用简单的正则表达式解析。问题是 Open MPI 的最新版本将 mpif.h
拆分为几个文件,然后从 mpif.h
中包含这些文件,目前该值在 mpif-constants.h
中。因此,您可能需要解析 include
语句并递归到它们引用的文件中。请注意,这些是 Fortran include
语句而不是预处理器 #include
指令。
代码生成
编写一个小的 C 程序,将 OMPI_COMM_TYPE_SOCKET
的值输出到 Python 文件并 运行 它作为程序设置过程的一部分。类似于:
#include <stdio.h>
#include <mpi.h>
int main (int argc, char **argv)
{
if (argc != 2)
{
printf("Usage: mkompimod /path/to/module.py\n");
return 1;
}
FILE *fh = fopen(argv[1], "w");
if (fh != NULL) {
fprintf(fh, "COMM_TYPE_SOCKET = %d\n", OMPI_COMM_TYPE_SOCKET);
fclose(fh);
}
return 0;
}
将其放入名为 mkompimod.c
的文件中。用mpicc -o mkompimod mkompimod.c
和运行用mkompimod /path/to/ompi.py
编译,创建一个Python文件ompi.py
,值为OMPI_COMM_TYPE_SOCKET
。导入它并在对 comm.Split_type()
:
import ompi
socketcomm = comm.Split_type(ompi.COMM_TYPE_SOCKET)
用C写一个Python模块
这有点复杂,但您可以编写一个包含 mpi.h
并将 OMPI_COMM_TYPE_SOCKET
的值导出为 Python 常量的 C 模块。参考 Python documentation 如何用 C 编写扩展。
使用 CFFI 模块
CFFI 可让您构建 Python 模块,这些模块包装 C 库并为您编写所有粘合代码。将以下内容放入名为 ompi_build.py
的文件中:
from cffi import FFI
ffi = FFI()
ffi.set_source("ompi", r"#include <mpi.h>")
ffi.cdef(
r"""
const int OMPI_COMM_TYPE_HWTHREAD;
... more constants here ...
const int OMPI_COMM_TYPE_SOCKET;
... even more constants here ...
"""
)
if __name__ == "__main__":
ffi.compile(verbose=True)
运行 像这样:
$ CC=mpicc python ompi_build.py
这将创建 C 模块 ompi.c
并将其编译成可加载的 DSO。然后您可以导入它并像这样访问常量:
from ompi.lib import OMPI_COMM_TYPE_SOCKET
socketcomm = comm.Split_type(OMPI_COMM_TYPE_SOCKET)
CFFI 提供与 Python 的 distutils
的集成,您可以让它在设置过程中自动构建 C 模块。
使用 Cython
这就是 mpi4py
本身所写的内容。它将 C 和 Python 混合成一个单一的神秘语法。阅读源代码。试着弄清楚发生了什么,以及如何自己写一些东西。帮不了你。
无论您选择哪条路径,请记住,所有这些都与程序 运行 所在的系统有关,而不仅仅是程序将在其上开发的系统。