.. _program_listing_file_src_utils_MPIUtils.hpp: Program Listing for File MPIUtils.hpp ===================================== |exhale_lsh| :ref:`Return to documentation for file ` (``src/utils/MPIUtils.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #ifndef MPIUTILS_HPP #define MPIUTILS_HPP #include #include // NOLINT(misc-include-cleaner) -- only used inside initMPI()'s own #ifdef SLUG_MPI block (std::cerr, for the MPI_THREAD_FUNNELED warning), so a build without SLUG_MPI never actually uses it, the same reason below needs its own identical NOLINT #include #ifdef SLUG_MPI # include // NOLINT(misc-include-cleaner) #endif #ifdef _OPENMP # include // NOLINT(misc-include-cleaner) -- only used inside initMPI()'s own "provided < MPI_THREAD_FUNNELED" branch, under #ifdef SLUG_MPI as well, so a build with _OPENMP but not SLUG_MPI never actually uses it #endif namespace utils { inline constexpr unsigned long mpiUidStride = 1UL << 40U; namespace detail { inline auto cachedMPIRank() -> int& { static int rank = 0; return rank; } inline auto cachedMPISize() -> int& { static int size = 1; return size; } } // namespace detail inline void initMPI([[maybe_unused]] int* argc, [[maybe_unused]] char*** argv) { #ifdef SLUG_MPI int provided = 0; MPI_Init_thread(argc, argv, MPI_THREAD_FUNNELED, &provided); MPI_Comm_rank(MPI_COMM_WORLD, &detail::cachedMPIRank()); MPI_Comm_size(MPI_COMM_WORLD, &detail::cachedMPISize()); if (provided < MPI_THREAD_FUNNELED) { std::cerr << "slug: warning: MPI implementation provided a lesser " "thread support level than MPI_THREAD_FUNNELED; forcing " "single-threaded execution for this run, since the MPI " "standard does not guarantee correct behavior for a " "multithreaded process otherwise\n"; #ifdef _OPENMP omp_set_num_threads(1); #endif } #endif } inline void finalizeMPI() { #ifdef SLUG_MPI MPI_Finalize(); #endif } class MPIGuard { public: MPIGuard(int* argc, char*** argv) { initMPI(argc, argv); } ~MPIGuard() { finalizeMPI(); } MPIGuard(const MPIGuard&) = delete; MPIGuard(MPIGuard&&) = delete; auto operator=(const MPIGuard&) -> MPIGuard& = delete; auto operator=(MPIGuard&&) -> MPIGuard& = delete; }; [[nodiscard]] inline auto mpiRank() -> int { return detail::cachedMPIRank(); } [[nodiscard]] inline auto mpiSize() -> int { return detail::cachedMPISize(); } [[nodiscard]] inline auto isIORank() -> bool { return mpiRank() == 0; } inline void mpiBarrier() { #ifdef SLUG_MPI MPI_Barrier(MPI_COMM_WORLD); #endif } [[nodiscard]] inline auto mpiAllReceivedSigterm(const bool local) -> bool { #ifdef SLUG_MPI int localFlag = local ? 1 : 0; int anyFlag = 0; MPI_Allreduce(&localFlag, &anyFlag, 1, MPI_INT, MPI_LOR, MPI_COMM_WORLD); return anyFlag != 0; #else return local; #endif } [[nodiscard]] inline auto mpiPartitionRange( const unsigned long rangeStart, const unsigned long rangeEnd) -> std::pair { const auto size = static_cast(mpiSize()); const auto rank = static_cast(mpiRank()); const unsigned long total = rangeEnd - rangeStart; const unsigned long base = total / size; const unsigned long remainder = total % size; const unsigned long myCount = base + ((rank < remainder) ? 1 : 0); const unsigned long precedingCount = rank * base + std::min(rank, remainder); const unsigned long start = rangeStart + precedingCount; return {start, start + myCount}; } } // namespace utils #endif // MPIUTILS_HPP