DNDSR 0.1.0.dev1+gcd065ad
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
MPI_bind.cpp
Go to the documentation of this file.
1#include "MPI.hpp"
2
3#include "MPI_bind.hpp"
4
5#include <pybind11/stl.h>
6#include <pybind11/numpy.h>
7
8namespace DNDS
9{
10 void pybind11_MPIInfo(py::module_ &m)
11 {
12 py_class_ssp<MPIInfo>(m, "MPIInfo")
13 .def(py::init<>())
14 .def(py::init([](uintptr_t pComm)
15 { return std::make_unique<MPIInfo>(MPI_Comm(pComm)); }))
16 .def("setWorld", &MPIInfo::setWorld)
17 .def_readonly("rank", &MPIInfo::rank)
18 .def_readonly("size", &MPIInfo::size)
19 .def("comm", [](const MPIInfo &self)
20 { return size_t(self.comm); })
21 .def("equals", &MPIInfo::operator==);
22 }
23}
24
25namespace DNDS::MPI
26{
27 void pybind11_Init_thread(py::module_ &m)
28 {
29 auto m_MPI = m.def_submodule("MPI");
30 m_MPI.def(
31 "Init_thread",
32 [](const std::vector<std::string> &pArgv)
33 {
34 // std::vector<const char *> argStarts;
35 // for (auto &v : pArgv)
36 // argStarts.push_back(v.c_str());
37 // int argn = argStarts.size();
38 // auto argv = argStarts.data();
39 // auto ret = Init_thread(&argn, const_cast<char ***>(&argv));
40 // //! Warning: assuming mpi won't touch anything
41 // return std::make_tuple(ret, pArgv);
42
43 // ! a complete version
44
45 int initial_argc = static_cast<int>(pArgv.size());
46 int initial_argc_mine = initial_argc;
47
48 // Create an array of pointers to C-style strings:
49 char **argv_array = new char *[initial_argc + 1]; // +1 for NULL terminator
50 char **argv_array_mine = argv_array;
51
52 // Allocate memory and copy each string into a modifiable buffer
53 for (int i = 0; i < initial_argc; ++i)
54 {
55 const std::string &s = pArgv[i];
56 size_t len = s.length();
57 char *cstr = new char[len + 1]; // Allocate space for '\0'
58 strcpy(cstr, s.c_str()); // Copy the string
59 argv_array[i] = cstr;
60 }
61 argv_array[initial_argc] = nullptr; // NULL terminator
62
63 int *pargc = &initial_argc;
64 char ***pargv = &argv_array;
65
66 auto ret = Init_thread(pargc, pargv);
67
68 // Capture the modified arguments into output_args:
69 std::vector<std::string> pArgvOut;
70 for (int i = 0; i < *pargc; ++i)
71 pArgvOut.push_back(std::string(argv_array[i]));
72
73 // Cleanup all dynamically allocated memory
74 // Note: Even if MPI changes entries in the array, our pointers still point to
75 // our original allocations (assuming MPI doesn't reallocate the entire array)
76 for (int i = 0; i <= initial_argc_mine; ++i)
77 delete[] argv_array_mine[i]; // Free each string buffer
78 delete[] argv_array_mine; // Free the pointer array
79
80 return std::make_tuple(ret, pArgvOut);
81 });
82 m_MPI.def(
83 "Finalize",
84 []()
85 {
86 return MPI::Finalize();
87 });
88 m_MPI.def("GetMPIThreadLevel", &GetMPIThreadLevel);
89 }
90
91 void pybind11_MPI_Operations(py::module_ &m)
92 {
93 auto m_MPI = m.def_submodule("MPI");
94 m_MPI.def(
95 "Allreduce",
96 [](py::buffer py_sendbuf, py::buffer py_recvbuf, const std::string &op, const MPIInfo &mpi)
97 {
98 auto send_info = py_sendbuf.request(false);
99 auto recv_info = py_recvbuf.request(true);
100
101 DNDS_assert_info(recv_info.format == send_info.format,
102 fmt::format("send and recv buffer format incompatible: [{}], [{}]",
103 send_info.format, recv_info.format));
104
105 MPI_Datatype datatype = py_get_buffer_basic_mpi_datatype(send_info);
106 DNDS_assert(datatype != MPI_DATATYPE_NULL);
107 MPI_Op mpi_op = py_get_simple_mpi_op_by_name(op);
108
109 auto [count_s, send_style] = py_buffer_get_contigious_size(send_info);
110 auto [count_r, recv_style] = py_buffer_get_contigious_size(send_info);
111 DNDS_assert_info(count_r >= count_s, "receive buffer size not enough");
112
113 MPI_int err = Allreduce(send_info.ptr, recv_info.ptr, count_s,
114 datatype, mpi_op, mpi.comm);
115 },
116 py::arg("send"), py::arg("recv"), py::arg("op"), py::arg("mpi"));
117 }
118}
119
120namespace DNDS::Debug
121{
122 // bool IsDebugged();
123 // void MPIDebugHold(const MPIInfo &mpi);
124
125 void pybind11_Debug(py::module_ &m)
126 {
127 auto m_Debug = m.def_submodule("Debug");
128 m_Debug.def("IsDebugged", &IsDebugged);
129 m_Debug.def("MPIDebugHold", &MPIDebugHold);
130 }
131}
132
133namespace DNDS
134{
142}
#define DNDS_assert_info(expr, info)
Debug-only assertion with an extra std::string info message.
Definition Errors.hpp:113
#define DNDS_assert(expr)
Debug-only assertion (compiled out when DNDS_NDEBUG is defined). Prints the expression + file/line + ...
Definition Errors.hpp:108
MPI wrappers: MPIInfo, collective operations, type mapping, CommStrategy.
pybind11 bindings for the DNDS MPI wrappers (MPIInfo, CommStrategy, buffer-protocol datatype helpers)...
bool IsDebugged()
Whether the current process is running under a debugger. Implemented via /proc/self/status TracerPid ...
Definition MPI.cpp:35
void MPIDebugHold(const MPIInfo &mpi)
If isDebugging is set, block every rank in a busy-wait loop so the user can attach a debugger and ins...
Definition MPI.cpp:59
void pybind11_Debug(py::module_ &m)
Definition MPI_bind.cpp:125
void pybind11_Init_thread(py::module_ &m)
Definition MPI_bind.cpp:27
int Finalize()
Release DNDSR-registered MPI resources then call MPI_Finalize.
Definition MPI.hpp:531
void pybind11_MPI_Operations(py::module_ &m)
Definition MPI_bind.cpp:91
MPI_int Allreduce(const void *sendbuf, void *recvbuf, MPI_int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm)
Wrapper over MPI_Allreduce.
Definition MPI.cpp:203
MPI_int Init_thread(int *argc, char ***argv)
Initialise MPI with thread support, honouring the DNDS_DISABLE_ASYNC_MPI environment override.
Definition MPI.hpp:495
int GetMPIThreadLevel()
Return the MPI thread-support level the current process was initialised with.
Definition MPI.hpp:474
the host side operators are provided as implemented
MPI_Op py_get_simple_mpi_op_by_name(const std::string &op)
Definition MPI_bind.hpp:43
py::classh< T > py_class_ssp
std::tuple< ssize_t, char > py_buffer_get_contigious_size(const py::buffer_info &info)
void pybind11_MPIInfo(py::module_ &m)
Definition MPI_bind.cpp:10
MPI_Datatype py_get_buffer_basic_mpi_datatype(const py::buffer_info &info)
Definition MPI_bind.hpp:13
void pybind11_bind_MPI_All(py::module_ &m)
Definition MPI_bind.cpp:135
int MPI_int
MPI counterpart type for MPI_int (= C int). Used for counts and ranks in MPI calls.
Definition MPI.hpp:43
Lightweight bundle of an MPI communicator and the calling rank's coordinates.
Definition MPI.hpp:215
int size
Number of ranks in comm (-1 until initialised).
Definition MPI.hpp:221
int rank
This rank's 0-based index within comm (-1 until initialised).
Definition MPI.hpp:219
MPI_Comm comm
The underlying MPI communicator handle.
Definition MPI.hpp:217
void setWorld()
Initialise the object to MPI_COMM_WORLD. Requires MPI_Init to have run.
Definition MPI.hpp:242
real err