Я пытаюсь обернуть функцию C, используя дескриптор коммуникатора MPI_Comm
в качестве параметра через cython. В результате я хочу иметь возможность вызывать функцию из python, передавая ей объект mpi4py.MPI.Comm
. Мне интересно, как сделать преобразование из mpi4py.MPI.Comm
в MPI_Comm
.
Чтобы продемонстрировать, я использую простую функцию "Hello World!" -type:
helloworld.h
:
#ifndef HELLOWORLD
#define HELLOWORLD
#include <mpi.h>
void sayhello(MPI_Comm comm);
#endif
helloworld.c
:
#include <stdio.h>
#include "helloworld.h"
void sayhello(MPI_Comm comm){
int size, rank;
MPI_Comm_size(comm, &size);
MPI_Comm_rank(comm, &rank);
printf("Hello, World! "
"I am process %d of %d.\n",
rank, size);
}
Теперь я хочу вызвать эту функцию из python следующим образом:
from_python.py
:
import mpi4py
import helloworld_wrap
helloworld_wrap.py_sayhello(mpi4py.MPI.COMM_WORLD)
Это означает, что mpirun -np 4 python2 from_python.py
должен давать что-то вроде:
Привет, мир! Я процесс 0 из 4.
Привет, мир! Я процесс 1 из 4.
Привет, мир! Я - процесс 2 из 4.
Привет, мир! Я процесс 3 из 4.
Но если я попытаюсь добиться этого с помощью cython следующим образом:
helloworld_wrap.pyx
:
cimport mpi4py.MPI as MPI
cimport mpi4py.libmpi as libmpi
cdef extern from "helloworld.h":
void sayhello(libmpi.MPI_Comm comm)
def py_sayhello(MPI.Comm comm):
sayhello(comm)
а также:
setup.py
:
import os
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
mpi_compile_args = os.popen("mpicc --showme:compile").read().strip().split(' ')
mpi_link_args = os.popen("mpicc --showme:link").read().strip().split(' ')
ext_modules=[
Extension("helloworld_wrap",
sources = ["helloworld_wrap.pyx", "helloworld.c"],
language = 'c',
extra_compile_args = mpi_compile_args,
extra_link_args = mpi_link_args,
)
]
setup(
name = "helloworld_wrap",
cmdclass = {"build_ext": build_ext},
ext_modules = ext_modules
)
Появляется следующее сообщение об ошибке:
helloworld_wrap.pyx: 8: 13: Невозможно преобразовать объект Python в 'MPI_Comm'
что mpi4py.MPI.Comm
не может быть преобразовано в MPI_Comm
. Итак, как я могу преобразовать mpi4py.MPI.Comm
в MPI_Comm
, чтобы заставить мою обертку работать?
Преобразование довольно просто, поскольку mpi4py.MPI.Comm
-object внутренне хранит дескриптор MPI_Comm
как член ob_mpi
1. Поэтому, если вы helloworld_wrap.pyx
последнюю строку helloworld_wrap.pyx
для передачи comm.ob_mpi
вместо comm
, модуль компилируется и работает по назначению:
helloworld_wrap.pyx
:
cimport mpi4py.MPI as MPI
cimport mpi4py.libmpi as libmpi
cdef extern from "helloworld.h":
void sayhello(libmpi.MPI_Comm comm)
def py_sayhello(MPI.Comm comm):
sayhello(comm.ob_mpi)
Удивительно, но я не нашел никакой документации для этого, но понял это только при изучении источников mpi4py.MPI.Comm
. Я не уверен, если это намеченный способ справиться с этим, но я не мог заставить его работать иначе.
1 На самом деле, большинство, если не все объекты в mpi4py.MPI
которые моделируют соответствующий дескриптор MPI в C, удерживают соответствующий дескриптор как член ob_mpi
.
mpi4py
в значительной степениmpi4py
и часто приходится искать источник, чтобы выяснить, как все работает.