From f7467c4b343755c29be87109b17bbef03ee902b1 Mon Sep 17 00:00:00 2001 From: Matthias Hochsteger Date: Thu, 2 May 2024 20:23:15 +0200 Subject: [PATCH] MPI wrapper to decide at run-time about MPI version --- libsrc/core/.clang-tidy | 2 +- libsrc/core/CMakeLists.txt | 24 +- libsrc/core/generate_mpi_sources.py | 98 ++++++++ libsrc/core/mpi_wrapper.hpp | 211 +++++++++--------- libsrc/core/ng_mpi.cpp | 62 +++++ libsrc/core/ng_mpi.hpp | 55 +++++ libsrc/core/ng_mpi_generated_declarations.hpp | 31 +++ libsrc/core/ng_mpi_generated_dummy_init.hpp | 31 +++ libsrc/core/ng_mpi_generated_init.hpp | 31 +++ libsrc/core/ng_mpi_wrapper.cpp | 94 ++++++++ libsrc/core/paje_trace.cpp | 19 +- libsrc/core/python_ngcore_export.cpp | 6 + libsrc/core/utils.cpp | 97 +++++++- libsrc/core/utils.hpp | 41 ++++ 14 files changed, 684 insertions(+), 118 deletions(-) create mode 100644 libsrc/core/generate_mpi_sources.py create mode 100644 libsrc/core/ng_mpi.cpp create mode 100644 libsrc/core/ng_mpi.hpp create mode 100644 libsrc/core/ng_mpi_generated_declarations.hpp create mode 100644 libsrc/core/ng_mpi_generated_dummy_init.hpp create mode 100644 libsrc/core/ng_mpi_generated_init.hpp create mode 100644 libsrc/core/ng_mpi_wrapper.cpp diff --git a/libsrc/core/.clang-tidy b/libsrc/core/.clang-tidy index 9ceddce8..086e97b8 100644 --- a/libsrc/core/.clang-tidy +++ b/libsrc/core/.clang-tidy @@ -1,4 +1,4 @@ -Checks: '*,-clang-analyzer-alpha.*,-*braces-around-statements,-fuchsia-*,-google-runtime-references,-readability-implicit-bool-conversion,-google-explicit-constructor,-hicpp-explicit-conversions,-google-runtime-int,-llvm-header-guard,-modernize-pass-by-value,-cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes,-readability-magic-numbers,-cppcoreguidelines-avoid-magic-numbers' +Checks: '*,-cppcoreguidelines-avoid-non-const-global-variables,-llvmlibc-restrict-system-libc-headers,-clang-analyzer-alpha.*,-*braces-around-statements,-fuchsia-*,-google-runtime-references,-readability-implicit-bool-conversion,-google-explicit-constructor,-hicpp-explicit-conversions,-google-runtime-int,-llvm-header-guard,-modernize-pass-by-value,-cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes,-readability-magic-numbers,-cppcoreguidelines-avoid-magic-numbers' CheckOptions: - key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor value: 1 diff --git a/libsrc/core/CMakeLists.txt b/libsrc/core/CMakeLists.txt index d0e37213..a2479bfb 100644 --- a/libsrc/core/CMakeLists.txt +++ b/libsrc/core/CMakeLists.txt @@ -12,6 +12,7 @@ add_library(ngcore ${NGCORE_LIBRARY_TYPE} taskmanager.cpp utils.cpp version.cpp + ng_mpi_wrapper.cpp ) string(REPLACE "|" ";" ng_compile_flags_replace_sep "${NG_COMPILE_FLAGS}") @@ -57,6 +58,8 @@ if(WIN32) get_WIN32_WINNT(ver) target_compile_definitions(ngcore PUBLIC _WIN32_WINNT=${ver} WNT WNT_WINDOW NOMINMAX MSVC_EXPRESS _CRT_SECURE_NO_WARNINGS HAVE_STRUCT_TIMESPEC WIN32) target_link_options(ngcore PUBLIC /ignore:4273 /ignore:4217 /ignore:4049) +else(WIN32) + target_link_libraries(ngcore PUBLIC dl) endif(WIN32) target_compile_definitions(ngcore PRIVATE NGCORE_EXPORTS) @@ -82,7 +85,7 @@ endif(USE_NUMA) install(TARGETS ngcore DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen) -target_link_libraries(ngcore PUBLIC netgen_mpi PRIVATE "$" ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries(ngcore PRIVATE "$" ${CMAKE_THREAD_LIBS_INIT}) install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp logging.hpp memtracer.hpp exception.hpp symboltable.hpp paje_trace.hpp utils.hpp profiler.hpp mpi_wrapper.hpp @@ -90,6 +93,7 @@ install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp xbool.hpp signal.hpp bitarray.hpp table.hpp hashtable.hpp ranges.hpp ngstream.hpp simd.hpp simd_avx.hpp simd_avx512.hpp simd_generic.hpp simd_sse.hpp simd_arm64.hpp register_archive.hpp autodiff.hpp autodiffdiff.hpp + ng_mpi.hpp ng_mpi_generated_declarations.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel) if(ENABLE_CPP_CORE_GUIDELINES_CHECK) @@ -108,3 +112,21 @@ if(USE_PYTHON) install(TARGETS pyngcore DESTINATION ${NG_INSTALL_DIR_PYTHON}/pyngcore COMPONENT netgen) endif(USE_PYTHON) +if(USE_MPI) + target_compile_definitions(ngcore PUBLIC PARALLEL) + + # assume openmpi here + add_library(ng_openmpi SHARED ng_mpi.cpp) + target_link_libraries(ng_openmpi PUBLIC ngcore) + install(TARGETS ng_openmpi DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen) + + # set(MPICH_INCLUDE_DIR /opt/mpich/include) + if(MPICH_INCLUDE_DIR) + add_library(ng_mpich SHARED ng_mpi.cpp) + target_include_directories(ng_mpich PRIVATE ${MPICH_INCLUDE_DIR}) + target_link_libraries(ng_mpich PUBLIC ngcore) + install(TARGETS ng_mpich DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen) + endif(MPICH_INCLUDE_DIR) + +endif(USE_MPI) + diff --git a/libsrc/core/generate_mpi_sources.py b/libsrc/core/generate_mpi_sources.py new file mode 100644 index 00000000..0f266a8c --- /dev/null +++ b/libsrc/core/generate_mpi_sources.py @@ -0,0 +1,98 @@ +functions = [ + ("int", "MPI_Init", "int*", "char***"), + ("int", "MPI_Initialized", "int*"), + ("int", "MPI_Finalize"), + ("int", "MPI_Barrier", "MPI_Comm"), + ("int", "MPI_Comm_free", "MPI_Comm*"), + ("int", "MPI_Comm_rank", "MPI_Comm", "int*"), + ("int", "MPI_Comm_size", "MPI_Comm", "int*"), + ("int", "MPI_Type_commit", "MPI_Datatype*"), + ("int", "MPI_Waitall", "int", "MPI_Request*", "MPI_Status*"), + ("int", "MPI_Waitany", "int", "MPI_Request*", "int*", "MPI_Status*"), + ("int", "MPI_Wait", "MPI_Request*", "MPI_Status*"), + ("int", "MPI_Send", "void*", "int", "MPI_Datatype", "int", "int", "MPI_Comm"), + ("int", "MPI_Probe", "int", "int", "MPI_Comm", "MPI_Status*"), + ("int", "MPI_Recv", "void*", "int", "MPI_Datatype", "int", "int", "MPI_Comm", "MPI_Status*"), + ("int", "MPI_Get_count", "MPI_Status*", "MPI_Datatype", "int*"), + ("int", "MPI_Bcast", "void*", "int", "MPI_Datatype", "int", "MPI_Comm"), + ("int", "MPI_Comm_group", "MPI_Comm", "MPI_Group*"), + ("int", "MPI_Group_incl", "MPI_Group", "int", "int*", "MPI_Group*"), + ("int", "MPI_Comm_create_group", "MPI_Comm", "MPI_Group", "int", "MPI_Comm*"), + ("int", "MPI_Get_processor_name", "char*", "int*"), + ] + +constants = [ + ("MPI_Comm", "MPI_COMM_WORLD"), + ("MPI_Status*", "MPI_STATUS_IGNORE"), + ("MPI_Status*", "MPI_STATUSES_IGNORE"), + ("MPI_Datatype", "MPI_INT"), + ("MPI_Datatype", "MPI_SHORT"), + ("MPI_Datatype", "MPI_CHAR"), + ("MPI_Datatype", "MPI_UINT64_T"), + ("MPI_Datatype", "MPI_DOUBLE"), + ("MPI_Datatype", "MPI_C_BOOL"), + ("void*", "MPI_IN_PLACE"), + ("int", "MPI_MAX_PROCESSOR_NAME"), +] + +def get_args(f): + return ["NG_"+a if a.startswith("MPI_") else a for a in f[2:]] + +def generate_declarations(): + code = "" + for f in functions: + ret = f[0] + name = f[1] + args = ", ".join(get_args(f)) + code += f"NGCORE_API extern {ret} (*NG_{name})({args});\n" + + for typ, name in constants: + if typ.startswith("MPI_"): + typ = "NG_" + typ + code += f"NGCORE_API extern {typ} NG_{name};\n" + + with open("ng_mpi_generated_declarations.hpp", "w") as f: + f.write(code) + +def generate_dummy_init(): + code = "" + for f in functions: + ret = f[0] + name = f[1] + args = ", ".join(get_args(f)) + code += f"decltype(NG_{name}) NG_{name} = []({args})->{ret} {{ throw no_mpi(); }};\n" + + for typ, name in constants: + if typ.startswith("MPI_"): + typ = "NG_" + typ + code += f"{typ} NG_{name} = 0;\n" + + with open("ng_mpi_generated_dummy_init.hpp", "w") as f: + f.write(code) + +def generate_init(): + code = "" + for f in functions: + ret = f[0] + name = f[1] + args = get_args(f) + in_args ='' + call_args = '' + for i, a in enumerate(args): + if i > 0: + in_args += ', ' + call_args += ', ' + in_args += a + f" arg{i}" + call_args += f" ng2mpi(arg{i})" + code += f"NG_{name} = []({in_args})->{ret} {{ return {name}({call_args}); }};\n" + + for _, name in constants: + code += f"NG_{name} = mpi2ng({name});\n" + + with open("ng_mpi_generated_init.hpp", "w") as f: + f.write(code) + +if __name__ == "__main__": + generate_declarations() + generate_dummy_init() + generate_init() diff --git a/libsrc/core/mpi_wrapper.hpp b/libsrc/core/mpi_wrapper.hpp index 8cfe31d2..b68439ab 100644 --- a/libsrc/core/mpi_wrapper.hpp +++ b/libsrc/core/mpi_wrapper.hpp @@ -5,7 +5,7 @@ #ifdef PARALLEL #define OMPI_SKIP_MPICXX -#include +// #include #endif #include "array.hpp" @@ -13,6 +13,7 @@ #include "exception.hpp" #include "profiler.hpp" #include "ngstream.hpp" +#include "ng_mpi.hpp" namespace ngcore { @@ -22,67 +23,67 @@ namespace ngcore template struct MPI_typetrait { }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_INT; } }; + static NG_MPI_Datatype MPIType () { return NG_MPI_INT; } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_SHORT; } }; + static NG_MPI_Datatype MPIType () { return NG_MPI_SHORT; } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_CHAR; } }; + static NG_MPI_Datatype MPIType () { return NG_MPI_CHAR; } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_CHAR; } }; + static NG_MPI_Datatype MPIType () { return NG_MPI_CHAR; } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_CHAR; } }; + static NG_MPI_Datatype MPIType () { return NG_MPI_CHAR; } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_UINT64_T; } }; + static NG_MPI_Datatype MPIType () { return NG_MPI_UINT64_T; } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_DOUBLE; } }; + static NG_MPI_Datatype MPIType () { return NG_MPI_DOUBLE; } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_C_BOOL; } }; + static NG_MPI_Datatype MPIType () { return NG_MPI_C_BOOL; } }; template struct MPI_typetrait> { - static MPI_Datatype MPIType () + static NG_MPI_Datatype MPIType () { - static MPI_Datatype MPI_T = 0; - if (!MPI_T) + static NG_MPI_Datatype NG_MPI_T = 0; + if (!NG_MPI_T) { - MPI_Type_contiguous ( S, MPI_typetrait::MPIType(), &MPI_T); - MPI_Type_commit ( &MPI_T ); + NG_MPI_Type_contiguous ( S, MPI_typetrait::MPIType(), &NG_MPI_T); + NG_MPI_Type_commit ( &NG_MPI_T ); } - return MPI_T; + return NG_MPI_T; } }; template ::MPIType())> - inline MPI_Datatype GetMPIType () { + inline NG_MPI_Datatype GetMPIType () { return MPI_typetrait::MPIType(); } template - inline MPI_Datatype GetMPIType (T &) { + inline NG_MPI_Datatype GetMPIType (T &) { return GetMPIType(); } - inline void MyMPI_WaitAll (FlatArray requests) + inline void MyMPI_WaitAll (FlatArray requests) { static Timer t("MPI - WaitAll"); RegionTimer reg(t); if (!requests.Size()) return; - MPI_Waitall (requests.Size(), requests.Data(), MPI_STATUSES_IGNORE); + NG_MPI_Waitall (requests.Size(), requests.Data(), NG_MPI_STATUSES_IGNORE); } - inline int MyMPI_WaitAny (FlatArray requests) + inline int MyMPI_WaitAny (FlatArray requests) { int nr; - MPI_Waitany (requests.Size(), requests.Data(), &nr, MPI_STATUS_IGNORE); + NG_MPI_Waitany (requests.Size(), requests.Data(), &nr, NG_MPI_STATUS_IGNORE); return nr; } @@ -91,7 +92,7 @@ namespace ngcore class NgMPI_Comm { protected: - MPI_Comm comm; + NG_MPI_Comm comm; bool valid_comm; int * refcount; int rank, size; @@ -100,11 +101,11 @@ namespace ngcore : valid_comm(false), refcount(nullptr), rank(0), size(1) { ; } - NgMPI_Comm (MPI_Comm _comm, bool owns = false) + NgMPI_Comm (NG_MPI_Comm _comm, bool owns = false) : comm(_comm), valid_comm(true) { int flag; - MPI_Initialized (&flag); + NG_MPI_Initialized (&flag); if (!flag) { valid_comm = false; @@ -119,8 +120,8 @@ namespace ngcore else refcount = new int{1}; - MPI_Comm_rank(comm, &rank); - MPI_Comm_size(comm, &size); + NG_MPI_Comm_rank(comm, &rank); + NG_MPI_Comm_size(comm, &size); } NgMPI_Comm (const NgMPI_Comm & c) @@ -141,7 +142,7 @@ namespace ngcore { if (refcount) if (--(*refcount) == 0) - MPI_Comm_free(&comm); + NG_MPI_Comm_free(&comm); } bool ValidCommunicator() const @@ -153,7 +154,7 @@ namespace ngcore { if (refcount) if (--(*refcount) == 0) - MPI_Comm_free(&comm); + NG_MPI_Comm_free(&comm); refcount = c.refcount; if (refcount) (*refcount)++; @@ -169,7 +170,7 @@ namespace ngcore InvalidCommException() : Exception("Do not have a valid communicator") { ; } }; - operator MPI_Comm() const { + operator NG_MPI_Comm() const { if (!valid_comm) throw InvalidCommException(); return comm; } @@ -178,7 +179,7 @@ namespace ngcore int Size() const { return size; } void Barrier() const { static Timer t("MPI - Barrier"); RegionTimer reg(t); - if (size > 1) MPI_Barrier (comm); + if (size > 1) NG_MPI_Barrier (comm); } @@ -186,82 +187,82 @@ namespace ngcore template())> void Send (T & val, int dest, int tag) const { - MPI_Send (&val, 1, GetMPIType(), dest, tag, comm); + NG_MPI_Send (&val, 1, GetMPIType(), dest, tag, comm); } void Send (const std::string & s, int dest, int tag) const { - MPI_Send( const_cast (&s[0]), s.length(), MPI_CHAR, dest, tag, comm); + NG_MPI_Send( const_cast (&s[0]), s.length(), NG_MPI_CHAR, dest, tag, comm); } template())> void Send(FlatArray s, int dest, int tag) const { - MPI_Send (s.Data(), s.Size(), GetMPIType(), dest, tag, comm); + NG_MPI_Send (s.Data(), s.Size(), GetMPIType(), dest, tag, comm); } template())> void Recv (T & val, int src, int tag) const { - MPI_Recv (&val, 1, GetMPIType(), src, tag, comm, MPI_STATUS_IGNORE); + NG_MPI_Recv (&val, 1, GetMPIType(), src, tag, comm, NG_MPI_STATUS_IGNORE); } void Recv (std::string & s, int src, int tag) const { - MPI_Status status; + NG_MPI_Status status; int len; - MPI_Probe (src, tag, comm, &status); - MPI_Get_count (&status, MPI_CHAR, &len); + NG_MPI_Probe (src, tag, comm, &status); + NG_MPI_Get_count (&status, NG_MPI_CHAR, &len); // s.assign (len, ' '); s.resize (len); - MPI_Recv( &s[0], len, MPI_CHAR, src, tag, comm, MPI_STATUS_IGNORE); + NG_MPI_Recv( &s[0], len, NG_MPI_CHAR, src, tag, comm, NG_MPI_STATUS_IGNORE); } template ())> void Recv (FlatArray s, int src, int tag) const { - MPI_Recv (s.Data(), s.Size(), GetMPIType (), src, tag, comm, MPI_STATUS_IGNORE); + NG_MPI_Recv (s.Data(), s.Size(), GetMPIType (), src, tag, comm, NG_MPI_STATUS_IGNORE); } template ())> void Recv (Array & s, int src, int tag) const { - MPI_Status status; + NG_MPI_Status status; int len; - const MPI_Datatype MPI_T = GetMPIType (); - MPI_Probe (src, tag, comm, &status); - MPI_Get_count (&status, MPI_T, &len); + const NG_MPI_Datatype NG_MPI_T = GetMPIType (); + NG_MPI_Probe (src, tag, comm, &status); + NG_MPI_Get_count (&status, NG_MPI_T, &len); s.SetSize (len); - MPI_Recv (s.Data(), len, MPI_T, src, tag, comm, MPI_STATUS_IGNORE); + NG_MPI_Recv (s.Data(), len, NG_MPI_T, src, tag, comm, NG_MPI_STATUS_IGNORE); } /** --- non-blocking P2P --- **/ template())> - MPI_Request ISend (T & val, int dest, int tag) const + NG_MPI_Request ISend (T & val, int dest, int tag) const { - MPI_Request request; - MPI_Isend (&val, 1, GetMPIType(), dest, tag, comm, &request); + NG_MPI_Request request; + NG_MPI_Isend (&val, 1, GetMPIType(), dest, tag, comm, &request); return request; } template())> - MPI_Request ISend (FlatArray s, int dest, int tag) const + NG_MPI_Request ISend (FlatArray s, int dest, int tag) const { - MPI_Request request; - MPI_Isend (s.Data(), s.Size(), GetMPIType(), dest, tag, comm, &request); + NG_MPI_Request request; + NG_MPI_Isend (s.Data(), s.Size(), GetMPIType(), dest, tag, comm, &request); return request; } template())> - MPI_Request IRecv (T & val, int dest, int tag) const + NG_MPI_Request IRecv (T & val, int dest, int tag) const { - MPI_Request request; - MPI_Irecv (&val, 1, GetMPIType(), dest, tag, comm, &request); + NG_MPI_Request request; + NG_MPI_Irecv (&val, 1, GetMPIType(), dest, tag, comm, &request); return request; } template())> - MPI_Request IRecv (FlatArray s, int src, int tag) const + NG_MPI_Request IRecv (FlatArray s, int src, int tag) const { - MPI_Request request; - MPI_Irecv (s.Data(), s.Size(), GetMPIType(), src, tag, comm, &request); + NG_MPI_Request request; + NG_MPI_Irecv (s.Data(), s.Size(), GetMPIType(), src, tag, comm, &request); return request; } @@ -269,41 +270,41 @@ namespace ngcore /** --- collectives --- **/ template ())> - T Reduce (T d, const MPI_Op & op, int root = 0) const + T Reduce (T d, const NG_MPI_Op & op, int root = 0) const { static Timer t("MPI - Reduce"); RegionTimer reg(t); if (size == 1) return d; T global_d; - MPI_Reduce (&d, &global_d, 1, GetMPIType(), op, root, comm); + NG_MPI_Reduce (&d, &global_d, 1, GetMPIType(), op, root, comm); return global_d; } template ())> - T AllReduce (T d, const MPI_Op & op) const + T AllReduce (T d, const NG_MPI_Op & op) const { static Timer t("MPI - AllReduce"); RegionTimer reg(t); if (size == 1) return d; T global_d; - MPI_Allreduce ( &d, &global_d, 1, GetMPIType(), op, comm); + NG_MPI_Allreduce ( &d, &global_d, 1, GetMPIType(), op, comm); return global_d; } template ())> - void AllReduce (FlatArray d, const MPI_Op & op) const + void AllReduce (FlatArray d, const NG_MPI_Op & op) const { static Timer t("MPI - AllReduce Array"); RegionTimer reg(t); if (size == 1) return; - MPI_Allreduce (MPI_IN_PLACE, d.Data(), d.Size(), GetMPIType(), op, comm); + NG_MPI_Allreduce (NG_MPI_IN_PLACE, d.Data(), d.Size(), GetMPIType(), op, comm); } template ())> void Bcast (T & s, int root = 0) const { if (size == 1) return; static Timer t("MPI - Bcast"); RegionTimer reg(t); - MPI_Bcast (&s, 1, GetMPIType(), root, comm); + NG_MPI_Bcast (&s, 1, GetMPIType(), root, comm); } @@ -316,7 +317,7 @@ namespace ngcore Bcast (ds, root); if (Rank() != root) d.SetSize (ds); if (ds != 0) - MPI_Bcast (d.Data(), ds, GetMPIType(), root, comm); + NG_MPI_Bcast (d.Data(), ds, GetMPIType(), root, comm); } @@ -326,13 +327,13 @@ namespace ngcore int len = s.length(); Bcast (len, root); if (rank != 0) s.resize (len); - MPI_Bcast (&s[0], len, MPI_CHAR, root, comm); + NG_MPI_Bcast (&s[0], len, NG_MPI_CHAR, root, comm); } template void AllToAll (FlatArray send, FlatArray recv) const { - MPI_Alltoall (send.Data(), 1, GetMPIType(), + NG_MPI_Alltoall (send.Data(), 1, GetMPIType(), recv.Data(), 1, GetMPIType(), comm); } @@ -341,15 +342,15 @@ namespace ngcore void ScatterRoot (FlatArray send) const { if (size == 1) return; - MPI_Scatter (send.Data(), 1, GetMPIType(), - MPI_IN_PLACE, -1, GetMPIType(), 0, comm); + NG_MPI_Scatter (send.Data(), 1, GetMPIType(), + NG_MPI_IN_PLACE, -1, GetMPIType(), 0, comm); } template void Scatter (T & recv) const { if (size == 1) return; - MPI_Scatter (NULL, 0, GetMPIType(), + NG_MPI_Scatter (NULL, 0, GetMPIType(), &recv, 1, GetMPIType(), 0, comm); } @@ -358,7 +359,7 @@ namespace ngcore { recv[0] = T(0); if (size == 1) return; - MPI_Gather (MPI_IN_PLACE, 1, GetMPIType(), + NG_MPI_Gather (NG_MPI_IN_PLACE, 1, GetMPIType(), recv.Data(), 1, GetMPIType(), 0, comm); } @@ -366,7 +367,7 @@ namespace ngcore void Gather (T send) const { if (size == 1) return; - MPI_Gather (&send, 1, GetMPIType(), + NG_MPI_Gather (&send, 1, GetMPIType(), NULL, 1, GetMPIType(), 0, comm); } @@ -379,7 +380,7 @@ namespace ngcore recv[0] = val; return; } - MPI_Allgather (&val, 1, GetMPIType(), + NG_MPI_Allgather (&val, 1, GetMPIType(), recv.Data(), 1, GetMPIType(), comm); } @@ -400,7 +401,7 @@ namespace ngcore recv_data = DynamicTable (recv_sizes, true); - Array requests; + Array requests; for (int dest = 0; dest < size; dest++) if (dest != rank && send_data[dest].Size()) requests.Append (ISend (FlatArray(send_data[dest]), dest, tag)); @@ -418,11 +419,11 @@ namespace ngcore NgMPI_Comm SubCommunicator (FlatArray procs) const { - MPI_Comm subcomm; - MPI_Group gcomm, gsubcomm; - MPI_Comm_group(comm, &gcomm); - MPI_Group_incl(gcomm, procs.Size(), procs.Data(), &gsubcomm); - MPI_Comm_create_group(comm, gsubcomm, 4242, &subcomm); + NG_MPI_Comm subcomm; + NG_MPI_Group gcomm, gsubcomm; + NG_MPI_Comm_group(comm, &gcomm); + NG_MPI_Group_incl(gcomm, procs.Size(), procs.Data(), &gsubcomm); + NG_MPI_Comm_create_group(comm, gsubcomm, 4242, &subcomm); return NgMPI_Comm(subcomm, true); } @@ -440,16 +441,16 @@ namespace ngcore MyMPI(int argc, char ** argv) { int is_init = -1; - MPI_Initialized(&is_init); + NG_MPI_Initialized(&is_init); if (!is_init) { - MPI_Init (&argc, &argv); + NG_MPI_Init (&argc, &argv); initialized_by_me = true; } else initialized_by_me = false; - NgMPI_Comm comm(MPI_COMM_WORLD); + NgMPI_Comm comm(NG_MPI_COMM_WORLD); NGSOStream::SetGlobalActive (comm.Rank() == 0); if (comm.Size() > 1) @@ -459,7 +460,7 @@ namespace ngcore ~MyMPI() { if (initialized_by_me) - MPI_Finalize (); + NG_MPI_Finalize (); } }; @@ -468,42 +469,42 @@ namespace ngcore #else // PARALLEL - class MPI_Comm { + class NG_MPI_Comm { int nr; public: - MPI_Comm (int _nr = 0) : nr(_nr) { ; } + NG_MPI_Comm (int _nr = 0) : nr(_nr) { ; } operator int() const { return nr; } - bool operator== (MPI_Comm c2) const { return nr == c2.nr; } + bool operator== (NG_MPI_Comm c2) const { return nr == c2.nr; } }; - static MPI_Comm MPI_COMM_WORLD = 12345, MPI_COMM_NULL = 10000; + static NG_MPI_Comm NG_MPI_COMM_WORLD = 12345, NG_MPI_COMM_NULL = 10000; - typedef int MPI_Op; - typedef int MPI_Datatype; - typedef int MPI_Request; + typedef int NG_MPI_Op; + typedef int NG_MPI_Datatype; + typedef int NG_MPI_Request; - enum { MPI_SUM = 0, MPI_MIN = 1, MPI_MAX = 2, MPI_LOR = 4711 }; + enum { NG_MPI_SUM = 0, NG_MPI_MIN = 1, NG_MPI_MAX = 2, NG_MPI_LOR = 4711 }; - inline void MPI_Type_contiguous ( int, MPI_Datatype, MPI_Datatype*) { ; } - inline void MPI_Type_commit ( MPI_Datatype * ) { ; } + inline void NG_MPI_Type_contiguous ( int, NG_MPI_Datatype, NG_MPI_Datatype*) { ; } + inline void NG_MPI_Type_commit ( NG_MPI_Datatype * ) { ; } template struct MPI_typetrait { - static MPI_Datatype MPIType () { return -1; } + static NG_MPI_Datatype MPIType () { return -1; } }; template - inline MPI_Datatype GetMPIType () { return -1; } + inline NG_MPI_Datatype GetMPIType () { return -1; } class NgMPI_Comm { public: NgMPI_Comm () { ; } - NgMPI_Comm (MPI_Comm _comm, bool owns = false) { ; } + NgMPI_Comm (NG_MPI_Comm _comm, bool owns = false) { ; } size_t Rank() const { return 0; } size_t Size() const { return 1; } bool ValidCommunicator() const { return false; } void Barrier() const { ; } - operator MPI_Comm() const { return MPI_Comm(); } + operator NG_MPI_Comm() const { return NG_MPI_Comm(); } template void Send( T & val, int dest, int tag) const { ; } @@ -521,25 +522,25 @@ namespace ngcore void Recv (Array & s, int src, int tag) const { ; } template - MPI_Request ISend (T & val, int dest, int tag) const { return 0; } + NG_MPI_Request ISend (T & val, int dest, int tag) const { return 0; } template - MPI_Request ISend (FlatArray s, int dest, int tag) const { return 0; } + NG_MPI_Request ISend (FlatArray s, int dest, int tag) const { return 0; } template - MPI_Request IRecv (T & val, int dest, int tag) const { return 0; } + NG_MPI_Request IRecv (T & val, int dest, int tag) const { return 0; } template - MPI_Request IRecv (FlatArray s, int src, int tag) const { return 0; } + NG_MPI_Request IRecv (FlatArray s, int src, int tag) const { return 0; } template - T Reduce (T d, const MPI_Op & op, int root = 0) const { return d; } + T Reduce (T d, const NG_MPI_Op & op, int root = 0) const { return d; } template - T AllReduce (T d, const MPI_Op & op) const { return d; } + T AllReduce (T d, const NG_MPI_Op & op) const { return d; } template - void AllReduce (FlatArray d, const MPI_Op & op) const { ; } + void AllReduce (FlatArray d, const NG_MPI_Op & op) const { ; } template void Bcast (T & s, int root = 0) const { ; } @@ -562,8 +563,8 @@ namespace ngcore { return *this; } }; - inline void MyMPI_WaitAll (FlatArray requests) { ; } - inline int MyMPI_WaitAny (FlatArray requests) { return 0; } + inline void MyMPI_WaitAll (FlatArray requests) { ; } + inline int MyMPI_WaitAny (FlatArray requests) { return 0; } class MyMPI { diff --git a/libsrc/core/ng_mpi.cpp b/libsrc/core/ng_mpi.cpp new file mode 100644 index 00000000..62fbf03f --- /dev/null +++ b/libsrc/core/ng_mpi.cpp @@ -0,0 +1,62 @@ +#include "ng_mpi.hpp" + +#include + +#include + +#include "ngcore_api.hpp" + +namespace ngcore { + +template +uintptr_t mpi2ng(T t) { + if constexpr (std::is_pointer_v) + return reinterpret_cast(t); + else + return static_cast(t); +} + +template +T cast_ng2mpi(uintptr_t t) { + if constexpr (std::is_pointer_v) + return reinterpret_cast(t); + else + return static_cast(t); +} + +template +T cast_ng2mpi(uintptr_t* t) { + if constexpr (std::is_pointer_v) + return reinterpret_cast(t); + else + return static_cast(t); +} + +MPI_Comm ng2mpi(NG_MPI_Comm c) { + static_assert(sizeof(MPI_Comm) <= sizeof(c.value), "Size mismatch"); + return cast_ng2mpi(c.value); +} + +MPI_Comm* ng2mpi(NG_MPI_Comm* c) { return cast_ng2mpi(&c->value); } + +MPI_Datatype ng2mpi(NG_MPI_Datatype c) { + static_assert(sizeof(MPI_Datatype) <= sizeof(c.value), "Size mismatch"); + return cast_ng2mpi(c.value); +} + +MPI_Request ng2mpi(NG_MPI_Request c) { + static_assert(sizeof(MPI_Request) <= sizeof(c.value), "Size mismatch"); + return cast_ng2mpi(c.value); +} + +int* ng2mpi(int* c) { return c; } + +} // namespace ngcore + +using namespace ngcore; + +NGCORE_API_EXPORT extern "C" void ng_init_mpi(); + +void ng_init_mpi() { +#include "ng_mpi_generated_init.hpp" +} diff --git a/libsrc/core/ng_mpi.hpp b/libsrc/core/ng_mpi.hpp new file mode 100644 index 00000000..cb9222a7 --- /dev/null +++ b/libsrc/core/ng_mpi.hpp @@ -0,0 +1,55 @@ +#ifndef NG_MPI_HPP_INCLUDED +#define NG_MPI_HPP_INCLUDED + +#include +#include +#include + +#include "ngcore_api.hpp" + +namespace ngcore { + +NGCORE_API void InitMPI(); +NGCORE_API extern std::string mpi_library_version; + +inline void not_implemented() { throw std::runtime_error("Not implemented"); } + +struct NG_MPI_Status { + uint64_t data[4]; +}; + +struct NG_MPI_Comm { + uintptr_t value; + NG_MPI_Comm() { value = 0;} + NG_MPI_Comm(uintptr_t v) : value(v) {} +}; + +struct NG_MPI_Datatype { + uintptr_t value; + NG_MPI_Datatype(uintptr_t v) : value(v) {} + operator bool() const { return value != 0; } +}; + +struct NG_MPI_Request { + uintptr_t value = 0; + NG_MPI_Request(uintptr_t v) : value(v) {} + NG_MPI_Request() = default; +}; + +struct NG_MPI_Op { + uintptr_t value; + NG_MPI_Op(uintptr_t v) : value(v) {} +}; + +struct NG_MPI_Group { + uintptr_t value = 0; + NG_MPI_Group(uintptr_t v) : value(v) {} + NG_MPI_Group() = default; +}; + + +#include "ng_mpi_generated_declarations.hpp" + +} // namespace ngcore + +#endif // NG_MPI_HPP_INCLUDED diff --git a/libsrc/core/ng_mpi_generated_declarations.hpp b/libsrc/core/ng_mpi_generated_declarations.hpp new file mode 100644 index 00000000..f398db00 --- /dev/null +++ b/libsrc/core/ng_mpi_generated_declarations.hpp @@ -0,0 +1,31 @@ +NGCORE_API extern int (*NG_MPI_Init)(int*, char***); +NGCORE_API extern int (*NG_MPI_Initialized)(int*); +NGCORE_API extern int (*NG_MPI_Finalize)(); +NGCORE_API extern int (*NG_MPI_Barrier)(NG_MPI_Comm); +NGCORE_API extern int (*NG_MPI_Comm_free)(NG_MPI_Comm*); +NGCORE_API extern int (*NG_MPI_Comm_rank)(NG_MPI_Comm, int*); +NGCORE_API extern int (*NG_MPI_Comm_size)(NG_MPI_Comm, int*); +NGCORE_API extern int (*NG_MPI_Type_commit)(NG_MPI_Datatype*); +NGCORE_API extern int (*NG_MPI_Waitall)(int, NG_MPI_Request*, NG_MPI_Status*); +NGCORE_API extern int (*NG_MPI_Waitany)(int, NG_MPI_Request*, int*, NG_MPI_Status*); +NGCORE_API extern int (*NG_MPI_Wait)(NG_MPI_Request*, NG_MPI_Status*); +NGCORE_API extern int (*NG_MPI_Send)(void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm); +NGCORE_API extern int (*NG_MPI_Probe)(int, int, NG_MPI_Comm, NG_MPI_Status*); +NGCORE_API extern int (*NG_MPI_Recv)(void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Status*); +NGCORE_API extern int (*NG_MPI_Get_count)(NG_MPI_Status*, NG_MPI_Datatype, int*); +NGCORE_API extern int (*NG_MPI_Bcast)(void*, int, NG_MPI_Datatype, int, NG_MPI_Comm); +NGCORE_API extern int (*NG_MPI_Comm_group)(NG_MPI_Comm, NG_MPI_Group*); +NGCORE_API extern int (*NG_MPI_Group_incl)(NG_MPI_Group, int, int*, NG_MPI_Group*); +NGCORE_API extern int (*NG_MPI_Comm_create_group)(NG_MPI_Comm, NG_MPI_Group, int, NG_MPI_Comm*); +NGCORE_API extern int (*NG_MPI_Get_processor_name)(char*, int*); +NGCORE_API extern NG_MPI_Comm NG_MPI_COMM_WORLD; +NGCORE_API extern NG_MPI_Status* NG_MPI_STATUS_IGNORE; +NGCORE_API extern NG_MPI_Status* NG_MPI_STATUSES_IGNORE; +NGCORE_API extern NG_MPI_Datatype NG_MPI_INT; +NGCORE_API extern NG_MPI_Datatype NG_MPI_SHORT; +NGCORE_API extern NG_MPI_Datatype NG_MPI_CHAR; +NGCORE_API extern NG_MPI_Datatype NG_MPI_UINT64_T; +NGCORE_API extern NG_MPI_Datatype NG_MPI_DOUBLE; +NGCORE_API extern NG_MPI_Datatype NG_MPI_C_BOOL; +NGCORE_API extern void* NG_MPI_IN_PLACE; +NGCORE_API extern int NG_MPI_MAX_PROCESSOR_NAME; diff --git a/libsrc/core/ng_mpi_generated_dummy_init.hpp b/libsrc/core/ng_mpi_generated_dummy_init.hpp new file mode 100644 index 00000000..ffb006d9 --- /dev/null +++ b/libsrc/core/ng_mpi_generated_dummy_init.hpp @@ -0,0 +1,31 @@ +decltype(NG_MPI_Init) NG_MPI_Init = [](int*, char***)->int { throw no_mpi(); }; +decltype(NG_MPI_Initialized) NG_MPI_Initialized = [](int*)->int { throw no_mpi(); }; +decltype(NG_MPI_Finalize) NG_MPI_Finalize = []()->int { throw no_mpi(); }; +decltype(NG_MPI_Barrier) NG_MPI_Barrier = [](NG_MPI_Comm)->int { throw no_mpi(); }; +decltype(NG_MPI_Comm_free) NG_MPI_Comm_free = [](NG_MPI_Comm*)->int { throw no_mpi(); }; +decltype(NG_MPI_Comm_rank) NG_MPI_Comm_rank = [](NG_MPI_Comm, int*)->int { throw no_mpi(); }; +decltype(NG_MPI_Comm_size) NG_MPI_Comm_size = [](NG_MPI_Comm, int*)->int { throw no_mpi(); }; +decltype(NG_MPI_Type_commit) NG_MPI_Type_commit = [](NG_MPI_Datatype*)->int { throw no_mpi(); }; +decltype(NG_MPI_Waitall) NG_MPI_Waitall = [](int, NG_MPI_Request*, NG_MPI_Status*)->int { throw no_mpi(); }; +decltype(NG_MPI_Waitany) NG_MPI_Waitany = [](int, NG_MPI_Request*, int*, NG_MPI_Status*)->int { throw no_mpi(); }; +decltype(NG_MPI_Wait) NG_MPI_Wait = [](NG_MPI_Request*, NG_MPI_Status*)->int { throw no_mpi(); }; +decltype(NG_MPI_Send) NG_MPI_Send = [](void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm)->int { throw no_mpi(); }; +decltype(NG_MPI_Probe) NG_MPI_Probe = [](int, int, NG_MPI_Comm, NG_MPI_Status*)->int { throw no_mpi(); }; +decltype(NG_MPI_Recv) NG_MPI_Recv = [](void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Status*)->int { throw no_mpi(); }; +decltype(NG_MPI_Get_count) NG_MPI_Get_count = [](NG_MPI_Status*, NG_MPI_Datatype, int*)->int { throw no_mpi(); }; +decltype(NG_MPI_Bcast) NG_MPI_Bcast = [](void*, int, NG_MPI_Datatype, int, NG_MPI_Comm)->int { throw no_mpi(); }; +decltype(NG_MPI_Comm_group) NG_MPI_Comm_group = [](NG_MPI_Comm, NG_MPI_Group*)->int { throw no_mpi(); }; +decltype(NG_MPI_Group_incl) NG_MPI_Group_incl = [](NG_MPI_Group, int, int*, NG_MPI_Group*)->int { throw no_mpi(); }; +decltype(NG_MPI_Comm_create_group) NG_MPI_Comm_create_group = [](NG_MPI_Comm, NG_MPI_Group, int, NG_MPI_Comm*)->int { throw no_mpi(); }; +decltype(NG_MPI_Get_processor_name) NG_MPI_Get_processor_name = [](char*, int*)->int { throw no_mpi(); }; +NG_MPI_Comm NG_MPI_COMM_WORLD = 0; +NG_MPI_Status* NG_MPI_STATUS_IGNORE = 0; +NG_MPI_Status* NG_MPI_STATUSES_IGNORE = 0; +NG_MPI_Datatype NG_MPI_INT = 0; +NG_MPI_Datatype NG_MPI_SHORT = 0; +NG_MPI_Datatype NG_MPI_CHAR = 0; +NG_MPI_Datatype NG_MPI_UINT64_T = 0; +NG_MPI_Datatype NG_MPI_DOUBLE = 0; +NG_MPI_Datatype NG_MPI_C_BOOL = 0; +void* NG_MPI_IN_PLACE = 0; +int NG_MPI_MAX_PROCESSOR_NAME = 0; diff --git a/libsrc/core/ng_mpi_generated_init.hpp b/libsrc/core/ng_mpi_generated_init.hpp new file mode 100644 index 00000000..dc89dad8 --- /dev/null +++ b/libsrc/core/ng_mpi_generated_init.hpp @@ -0,0 +1,31 @@ +NG_MPI_Init = [](int* arg0, char*** arg1)->int { return MPI_Init( ng2mpi(arg0), ng2mpi(arg1)); }; +NG_MPI_Initialized = [](int* arg0)->int { return MPI_Initialized( ng2mpi(arg0)); }; +NG_MPI_Finalize = []()->int { return MPI_Finalize(); }; +NG_MPI_Barrier = [](NG_MPI_Comm arg0)->int { return MPI_Barrier( ng2mpi(arg0)); }; +NG_MPI_Comm_free = [](NG_MPI_Comm* arg0)->int { return MPI_Comm_free( ng2mpi(arg0)); }; +NG_MPI_Comm_rank = [](NG_MPI_Comm arg0, int* arg1)->int { return MPI_Comm_rank( ng2mpi(arg0), ng2mpi(arg1)); }; +NG_MPI_Comm_size = [](NG_MPI_Comm arg0, int* arg1)->int { return MPI_Comm_size( ng2mpi(arg0), ng2mpi(arg1)); }; +NG_MPI_Type_commit = [](NG_MPI_Datatype* arg0)->int { return MPI_Type_commit( ng2mpi(arg0)); }; +NG_MPI_Waitall = [](int arg0, NG_MPI_Request* arg1, NG_MPI_Status* arg2)->int { return MPI_Waitall( ng2mpi(arg0), ng2mpi(arg1), ng2mpi(arg2)); }; +NG_MPI_Waitany = [](int arg0, NG_MPI_Request* arg1, int* arg2, NG_MPI_Status* arg3)->int { return MPI_Waitany( ng2mpi(arg0), ng2mpi(arg1), ng2mpi(arg2), ng2mpi(arg3)); }; +NG_MPI_Wait = [](NG_MPI_Request* arg0, NG_MPI_Status* arg1)->int { return MPI_Wait( ng2mpi(arg0), ng2mpi(arg1)); }; +NG_MPI_Send = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, int arg4, NG_MPI_Comm arg5)->int { return MPI_Send( ng2mpi(arg0), ng2mpi(arg1), ng2mpi(arg2), ng2mpi(arg3), ng2mpi(arg4), ng2mpi(arg5)); }; +NG_MPI_Probe = [](int arg0, int arg1, NG_MPI_Comm arg2, NG_MPI_Status* arg3)->int { return MPI_Probe( ng2mpi(arg0), ng2mpi(arg1), ng2mpi(arg2), ng2mpi(arg3)); }; +NG_MPI_Recv = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, int arg4, NG_MPI_Comm arg5, NG_MPI_Status* arg6)->int { return MPI_Recv( ng2mpi(arg0), ng2mpi(arg1), ng2mpi(arg2), ng2mpi(arg3), ng2mpi(arg4), ng2mpi(arg5), ng2mpi(arg6)); }; +NG_MPI_Get_count = [](NG_MPI_Status* arg0, NG_MPI_Datatype arg1, int* arg2)->int { return MPI_Get_count( ng2mpi(arg0), ng2mpi(arg1), ng2mpi(arg2)); }; +NG_MPI_Bcast = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, NG_MPI_Comm arg4)->int { return MPI_Bcast( ng2mpi(arg0), ng2mpi(arg1), ng2mpi(arg2), ng2mpi(arg3), ng2mpi(arg4)); }; +NG_MPI_Comm_group = [](NG_MPI_Comm arg0, NG_MPI_Group* arg1)->int { return MPI_Comm_group( ng2mpi(arg0), ng2mpi(arg1)); }; +NG_MPI_Group_incl = [](NG_MPI_Group arg0, int arg1, int* arg2, NG_MPI_Group* arg3)->int { return MPI_Group_incl( ng2mpi(arg0), ng2mpi(arg1), ng2mpi(arg2), ng2mpi(arg3)); }; +NG_MPI_Comm_create_group = [](NG_MPI_Comm arg0, NG_MPI_Group arg1, int arg2, NG_MPI_Comm* arg3)->int { return MPI_Comm_create_group( ng2mpi(arg0), ng2mpi(arg1), ng2mpi(arg2), ng2mpi(arg3)); }; +NG_MPI_Get_processor_name = [](char* arg0, int* arg1)->int { return MPI_Get_processor_name( ng2mpi(arg0), ng2mpi(arg1)); }; +NG_MPI_COMM_WORLD = mpi2ng(MPI_COMM_WORLD); +NG_MPI_STATUS_IGNORE = mpi2ng(MPI_STATUS_IGNORE); +NG_MPI_STATUSES_IGNORE = mpi2ng(MPI_STATUSES_IGNORE); +NG_MPI_INT = mpi2ng(MPI_INT); +NG_MPI_SHORT = mpi2ng(MPI_SHORT); +NG_MPI_CHAR = mpi2ng(MPI_CHAR); +NG_MPI_UINT64_T = mpi2ng(MPI_UINT64_T); +NG_MPI_DOUBLE = mpi2ng(MPI_DOUBLE); +NG_MPI_C_BOOL = mpi2ng(MPI_C_BOOL); +NG_MPI_IN_PLACE = mpi2ng(MPI_IN_PLACE); +NG_MPI_MAX_PROCESSOR_NAME = mpi2ng(MPI_MAX_PROCESSOR_NAME); diff --git a/libsrc/core/ng_mpi_wrapper.cpp b/libsrc/core/ng_mpi_wrapper.cpp new file mode 100644 index 00000000..43516224 --- /dev/null +++ b/libsrc/core/ng_mpi_wrapper.cpp @@ -0,0 +1,94 @@ +#include + +#include +#include + +#include "ng_mpi.hpp" +#include "utils.hpp" + +using std::cout; +using std::endl; + +namespace ngcore { + +static std::unique_ptr mpi_lib, ng_mpi_lib; + +void InitMPI() { + if (ng_mpi_lib) return; + cout << "InitMPI" << endl; + + typedef void (*get_version_handle)(char *, int *); + typedef int (*init_handle)(int *, char ***); + typedef int (*mpi_initialized_handle)(int *); + typedef void (*ng_init_handle)(); + + init_handle mpi_init; + mpi_initialized_handle mpi_initialized; + get_version_handle get_version; + try { + mpi_init = GetSymbol("MPI_Init"); + cout << "MPI already loaded " << mpi_init << endl; + mpi_initialized = GetSymbol("MPI_Initialized"); + get_version = GetSymbol("MPI_Get_library_version"); + } catch (std::runtime_error &e) { + cout << "MPI not loaded" << endl; + mpi_lib = std::make_unique("libmpi.so", std::nullopt, true); + mpi_init = mpi_lib->GetSymbol("MPI_Init"); + mpi_initialized = + mpi_lib->GetSymbol("MPI_Initialized"); + get_version = + mpi_lib->GetSymbol("MPI_Get_library_version"); + } + + int flag = 0; + mpi_initialized(&flag); + if (!flag) { + cout << "Calling MPI_Init" << endl; + mpi_init(nullptr, nullptr); + } + + char version_string[65536]; + int resultlen = 0; + get_version(version_string, &resultlen); + mpi_library_version = version_string; + cout << "MPI version: " << version_string << endl; + + std::string libname = ""; + if (mpi_library_version.substr(0, 8) == "Open MPI") { + cout << "Have Open MPI" << endl; + libname = "/opt/netgen/lib/libng_openmpi.so"; + } else if (mpi_library_version.substr(0, 5) == "MPICH") { + cout << "Have MPICH" << endl; + libname = "/opt/netgen/lib/libng_mpich.so"; + } else + cout << "Unknown MPI" << endl; + + if (libname.size()) { + cout << "loading " << libname << endl; + cout << "NG_MPI_INT before " << NG_MPI_INT.value << endl; + ng_mpi_lib = std::make_unique(libname); + auto ng_init = ng_mpi_lib->GetSymbol("ng_init_mpi"); + cout << "have ng_init " << ng_init << endl; + ng_init(); + cout << "NG_MPI_INT after " << NG_MPI_INT.value << endl; + } +} + +// NG_MPI_Comm NG_MPI_COMM_WORLD = 0; + +// NG_MPI_Datatype NG_MPI_INT = 0; +// NG_MPI_Datatype NG_MPI_SHORT = 0; +// NG_MPI_Datatype NG_MPI_CHAR = 0; +// NG_MPI_Datatype NG_MPI_UINT64_T = 0; +// NG_MPI_Datatype NG_MPI_DOUBLE = 0; +// NG_MPI_Datatype NG_MPI_C_BOOL = 0; + +static std::runtime_error no_mpi() { + return std::runtime_error("MPI not enabled"); +} + +std::string mpi_library_version = ""; + +#include "ng_mpi_generated_dummy_init.hpp" + +} // namespace ngcore diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 1b81395e..f3f9e944 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -13,6 +13,7 @@ extern const char *header; constexpr int MPI_PAJE_WRITER = 1; +constexpr int ASSUMED_MPI_MAX_PROCESSOR_NAME = 256; namespace ngcore { @@ -24,7 +25,7 @@ namespace ngcore if(id1) @@ -496,9 +497,9 @@ namespace ngcore nthreads = nranks; thread_aliases.reserve(nthreads); - std::array ahostname; + std::array ahostname; int len; - MPI_Get_processor_name(ahostname.data(), &len); + NG_MPI_Get_processor_name(ahostname.data(), &len); std::string hostname = ahostname.data(); std::map host_map; @@ -854,15 +855,15 @@ namespace ngcore { #ifdef PARALLEL // Hostname - NgMPI_Comm comm(MPI_COMM_WORLD); + NgMPI_Comm comm(NG_MPI_COMM_WORLD); // auto rank = comm.Rank(); // auto nranks = comm.Size(); std::string hostname; { - std::array ahostname; + std::array ahostname; int len; - MPI_Get_processor_name(ahostname.data(), &len); + NG_MPI_Get_processor_name(ahostname.data(), &len); hostname = ahostname.data(); } diff --git a/libsrc/core/python_ngcore_export.cpp b/libsrc/core/python_ngcore_export.cpp index 21d25038..4431ea8f 100644 --- a/libsrc/core/python_ngcore_export.cpp +++ b/libsrc/core/python_ngcore_export.cpp @@ -6,6 +6,11 @@ using namespace ngcore; using namespace std; using namespace pybind11::literals; + +namespace ngcore { + NGCORE_API void InitMPI(); +} + PYBIND11_MODULE(pyngcore, m) // NOLINT { try @@ -328,4 +333,5 @@ threads : int }, "Returns list of timers" ); m.def("ResetTimers", &NgProfiler::Reset); + m.def("InitMPI", &InitMPI); } diff --git a/libsrc/core/utils.cpp b/libsrc/core/utils.cpp index eb03eb98..b0a9b683 100644 --- a/libsrc/core/utils.cpp +++ b/libsrc/core/utils.cpp @@ -3,16 +3,24 @@ #include "logging.hpp" #include "simd_generic.hpp" -#ifndef WIN32 +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#else // WIN32 #include -#endif +#include +#endif //WIN32 +// #include #include #include #include +#include #include "ngstream.hpp" + namespace ngcore { namespace detail @@ -134,5 +142,90 @@ namespace ngcore return path; } + + SharedLibrary :: SharedLibrary(const std::filesystem::path & lib_name_, std::optional directory_to_delete_, bool global ) + : lib_name(lib_name_),directory_to_delete(directory_to_delete_) + { + Load(lib_name, global); + } + + SharedLibrary :: ~SharedLibrary() + { + Unload(); + if(directory_to_delete) + for([[maybe_unused]] auto i : Range(5)) + { + // on Windows, a (detached?) child process of the compiler/linker might still block the directory + // wait for it to finish (up to a second) + try + { + std::filesystem::remove_all(*directory_to_delete); + directory_to_delete = std::nullopt; + break; + } + catch(const std::exception &e) + { + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + } + } + if(directory_to_delete) + std::cerr << "Could not delete " << directory_to_delete->string() << std::endl; + } + + void SharedLibrary :: Load( const std::filesystem::path & lib_name_, bool global ) + { + Unload(); + lib_name = lib_name_; +#ifdef WIN32 + lib = LoadLibrary(lib_name.string().c_str()); + if (!lib) throw std::runtime_error(string("Could not load library ") + lib_name.string()); +#else // WIN32 + auto flags = RTLD_NOW; + if (global) flags |= RTLD_GLOBAL; + lib = dlopen(lib_name.c_str(), flags); + if(lib == nullptr) throw std::runtime_error(dlerror()); +#endif // WIN32 + } + + void SharedLibrary :: Unload() { + if(lib) + { +#ifdef WIN32 + FreeLibrary((HMODULE)lib); +#else // WIN32 + int rc = dlclose(lib); + if(rc != 0) std::cerr << "Failed to close library " << lib_name << std::endl; +#endif // WIN32 + } + } + + void* SharedLibrary :: GetRawSymbol( std::string func_name ) + { +#ifdef WIN32 + void* func = GetProcAddress((HMODULE)lib, func_name.c_str()); + if(func == nullptr) + throw std::runtime_error(string("Could not find function ") + func_name + " in library " + lib_name.string()); +#else // WIN32 + void* func = dlsym(lib, func_name.c_str()); + if(func == nullptr) + throw std::runtime_error(dlerror()); +#endif // WIN32 + + return func; + } + + void* GetRawSymbol( std::string func_name ) + { +#ifdef WIN32 + throw std::runtime_error("GetRawSymbol not implemented on WIN32"); +#else // WIN32 + void* func = dlsym(RTLD_DEFAULT, func_name.c_str()); + if(func == nullptr) + throw std::runtime_error(dlerror()); +#endif // WIN32 + return func; + } + + } // namespace ngcore diff --git a/libsrc/core/utils.hpp b/libsrc/core/utils.hpp index 79d919c0..2676a8c1 100644 --- a/libsrc/core/utils.hpp +++ b/libsrc/core/utils.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -347,6 +348,46 @@ namespace ngcore NGCORE_API std::filesystem::path GetTempFilename(); + NGCORE_API void* GetRawSymbol( std::string func_name ); + + template + TFunc GetSymbol( std::string func_name ) + { + return reinterpret_cast(GetRawSymbol(func_name)); + } + + // Class to handle/load shared libraries + class NGCORE_API SharedLibrary + { + std::filesystem::path lib_name; + std::optional directory_to_delete = std::nullopt; + + // #ifdef WIN32 + // HINSTANCE lib = nullptr; + // #else // WIN32 + void *lib = nullptr; + // #endif // WIN32 + + public: + SharedLibrary() = default; + SharedLibrary(const std::filesystem::path & lib_name_, std::optional directory_to_delete_ = std::nullopt, bool global = false ); + + SharedLibrary(const SharedLibrary &) = delete; + SharedLibrary & operator =(const SharedLibrary &) = delete; + + ~SharedLibrary(); + + template + TFunc GetSymbol( std::string func_name ) + { + return reinterpret_cast(GetRawSymbol(func_name)); + } + + void Load( const std::filesystem::path & lib_name_, bool global); + void Unload(); + void* GetRawSymbol( std::string func_name ); + }; + } // namespace ngcore #endif // NETGEN_CORE_UTILS_HPP