diff --git a/CMakeLists.txt b/CMakeLists.txt index f884a73157979fcf881e6eb61d168baa5ba16515..143435246fdb8fe1737dcd4790ed3597b9b09e4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,12 +9,19 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) list (APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") -option(BACKEND_EXTRAE "Enable Extrae" OFF) -option(BACKEND_DLB "Enable DLB" OFF) +# Available backend options +option(ENABLE_EXTRAE "Enable Extrae" OFF) +option(ENABLE_DLB "Enable DLB" OFF) + +# Install depending options option(BUILD_C_FORTRAN "Enable C and Fortran Interfaces" ON) option(SPLIT_FORTRAN_LIBRARY "Split the fortran symbols into a special library (nesmik_f) - EXPERIMENTAL" OFF) option(GEN_BINDINGS "Use Shroud to Generate C/Fortran interface" OFF) +# Other options +option(WITH_MPI "Compile with MPI" OFF) + + if(BUILD_C_FORTRAN) enable_language(Fortran) set(CMAKE_Fortran_FORMAT FREE) @@ -33,11 +40,20 @@ target_include_directories(${PROJECT_NAME} PUBLIC ) + + if(BUILD_C_FORTRAN AND SPLIT_FORTRAN_LIBRARY) add_library(nesmik_f) add_library(nesmik::nesmik_f ALIAS nesmik_f) endif() +if(WITH_MPI) + find_package(MPI REQUIRED COMPONENTS CXX) + target_link_libraries(${PROJECT_NAME} PUBLIC MPI::MPI_CXX) + target_compile_definitions(nesmik PRIVATE "WITH_MPI") +endif() + + add_subdirectory(src) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1f90296f5e0edd170e3cfbe1bbe9a89fabbd5443..bdc267e42ea931bffc45f509eaa964ad592d4680 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,5 @@ add_subdirectory(backends) -target_sources(nesmik PRIVATE delegator.cpp nesmik.cpp) +target_sources(nesmik PRIVATE delegator.cpp nesmik.cpp parallelism_helper.cpp) if(BUILD_C_FORTRAN) add_subdirectory(bindings) diff --git a/src/backends/default/default.cpp b/src/backends/default/default.cpp index d460168a6e98da4715be4adb45436dbd8ca111ed..7b0c2709574dc0d7ee401674f853a48802c927fe 100644 --- a/src/backends/default/default.cpp +++ b/src/backends/default/default.cpp @@ -3,6 +3,14 @@ #include "default.hpp" +PNDefault::PNDefault(){ + parallelism_descriptor_={ + .mpi_descriptor_ = MPIDescriptor::DontCare, + .thread_descriptor_ = ThreadDescriptor::Supported + }; +} + + void PNDefault::RegionStart( const ProperlyNestedRegionInformation ®ion) noexcept { std::cout << "Region start: " << region.name << std::endl; @@ -22,6 +30,16 @@ void PNDefault::Finalize() noexcept { // NPN + +NPNDefault::NPNDefault(){ + parallelism_descriptor_={ + .mpi_descriptor_ = MPIDescriptor::DontCare, + .thread_descriptor_ = ThreadDescriptor::Supported + }; +} + + + void NPNDefault::RegionStart( const NotProperlyNestedRegionInformation ®ion) noexcept { std::cout << "Region start: " << region.name << std::endl; diff --git a/src/backends/default/default.hpp b/src/backends/default/default.hpp index 9d8b8e48cc66a6e47ae93b4f3ace948d7fa4aaeb..8a1242f560768a343701d382757bc50305bc33b9 100644 --- a/src/backends/default/default.hpp +++ b/src/backends/default/default.hpp @@ -4,6 +4,7 @@ class PNDefault : public ProperlyNestedAnnotationStrategy { public: + PNDefault(); inline static const std::string name = "Default"; void RegionStart(const ProperlyNestedRegionInformation &info_to_start) noexcept override; void RegionStopLast(const ProperlyNestedRegionInformation &info_to_stop) noexcept override; @@ -15,6 +16,7 @@ public: class NPNDefault : public NotProperlyNestedAnnotationStrategy { public: + NPNDefault(); inline static const std::string name = "Default"; virtual void RegionStart(const NotProperlyNestedRegionInformation &info_to_start) noexcept override; virtual void RegionStop(const NotProperlyNestedRegionInformation &info_to_stop) noexcept override; diff --git a/src/backends/dlb/dlb/dlb.cpp b/src/backends/dlb/dlb/dlb.cpp index 3a7b07607586db3695cda10274b34d6ccd5ded01..6ab417112c95d9d83a27e9b273da4da35c8b1012 100644 --- a/src/backends/dlb/dlb/dlb.cpp +++ b/src/backends/dlb/dlb/dlb.cpp @@ -3,6 +3,14 @@ #include "dlb_talp.h" #include + +DLBTalpStrategy::DLBTalpStrategy(){ + parallelism_descriptor_={ + .mpi_descriptor_ = MPIDescriptor::DontCare, + .thread_descriptor_ = ThreadDescriptor::Supported // Even though it makes no semantical sense + }; +} + void DLBTalpStrategy::RegionStart( const NotProperlyNestedRegionInformation ®ion) noexcept { // we have to create a small std::string thing because we cannot assume that diff --git a/src/backends/dlb/dlb/dlb.hpp b/src/backends/dlb/dlb/dlb.hpp index 83201cc72914688be3da9a58e901e9fa182e28b2..b3647b12c04c2fc08beffa713dda898ef58060b2 100644 --- a/src/backends/dlb/dlb/dlb.hpp +++ b/src/backends/dlb/dlb/dlb.hpp @@ -6,6 +6,7 @@ class DLBTalpStrategy : public NotProperlyNestedAnnotationStrategy { public: + DLBTalpStrategy(); inline static const std::string name = "TALP"; virtual void RegionStart(const NotProperlyNestedRegionInformation ®ion) noexcept override; virtual void RegionStop(const NotProperlyNestedRegionInformation ®ion) noexcept override; diff --git a/src/backends/dlb/dlb_talp_tree/dlb_talp_tree.cpp b/src/backends/dlb/dlb_talp_tree/dlb_talp_tree.cpp index cefe614e0ff6e776165b6b2c2a36dc360d7ee5af..f03b5971a97696143c12de611d193178f1b355aa 100644 --- a/src/backends/dlb/dlb_talp_tree/dlb_talp_tree.cpp +++ b/src/backends/dlb/dlb_talp_tree/dlb_talp_tree.cpp @@ -8,6 +8,22 @@ #include #include +#ifdef WITH_MPI + #include +#endif + + +#include + +DLBTalpTreeStrategy::DLBTalpTreeStrategy():mpi_helper_{}{ + parallelism_descriptor_={ + .mpi_descriptor_ = MPIDescriptor::Aware, + .thread_descriptor_ = ThreadDescriptor::Unsupported + }; +} + + + void DLBTalpTreeStrategy::RegionStart( const ProperlyNestedRegionInformation ®ion) noexcept { @@ -65,6 +81,8 @@ void DLBTalpTreeStrategy::RegionStopLast( this->talp_profiling_strategy.RegionStart({name}); } + + void DLBTalpTreeStrategy::Init() noexcept { this->current_region = std::hash{}(this->top_region); @@ -73,8 +91,7 @@ void DLBTalpTreeStrategy::Init() noexcept { /* .tree_lines */ "", /* .parent */ 0, /* .childs */ {}, - }; - + }; this->talp_profiling_strategy.Init(); } @@ -197,11 +214,18 @@ void DLBTalpTreeStrategy::Finalize() noexcept { region_stream_csv << std::endl; } - std::cout << region_stream_stdout.str() << std::endl; + if(mpi_helper_.IsRankNumber(0)){ + std::cout << region_stream_stdout.str() << std::endl; + } + + + if(mpi_helper_.IsRankNumber(0)){ + std::ofstream csv_stream; + csv_stream.open("nesmik_talp_tree.csv", std::ios::trunc); + csv_stream << region_stream_csv.str() << std::endl; + } + - std::ofstream csv_stream; - csv_stream.open("nesmik_talp_tree.csv", std::ios::trunc); - csv_stream << region_stream_csv.str() << std::endl; this->talp_profiling_strategy.Finalize(); } diff --git a/src/backends/dlb/dlb_talp_tree/dlb_talp_tree.hpp b/src/backends/dlb/dlb_talp_tree/dlb_talp_tree.hpp index a1c7823364122d5e916c946842ad07b19be93d44..9e62b3d02ed706b98d87652325e01924a7a725f3 100644 --- a/src/backends/dlb/dlb_talp_tree/dlb_talp_tree.hpp +++ b/src/backends/dlb/dlb_talp_tree/dlb_talp_tree.hpp @@ -8,6 +8,8 @@ #include #include +#include + struct TalpRegionNode { std::string name; std::string tree_lines; @@ -24,8 +26,11 @@ private: std::size_t current_region; std::map regions; + // Mpi aware stuff + MPIHelper mpi_helper_; public: + DLBTalpTreeStrategy(); inline static const std::string_view name = "TALP-Tree"; void RegionStart(const ProperlyNestedRegionInformation ®ion) noexcept override; void RegionStopLast(const ProperlyNestedRegionInformation ®ion) noexcept override; diff --git a/src/backends/extrae/extrae_type_stack.cpp b/src/backends/extrae/extrae_type_stack.cpp index ab690087a4e5dc3384a6d1b823aac0239b571477..23c5b4f917ec74a58fda020b84cff14a7bfdbe0d 100644 --- a/src/backends/extrae/extrae_type_stack.cpp +++ b/src/backends/extrae/extrae_type_stack.cpp @@ -12,6 +12,15 @@ extern "C" { #include } +ExtraeTypeStackStrategy::ExtraeTypeStackStrategy(){ + parallelism_descriptor_={ + .mpi_descriptor_ = MPIDescriptor::Aware, + .thread_descriptor_ = ThreadDescriptor::Supported // i guess no test currently for this + }; +} + + + const std::string ExtraeTypeStackStrategy::paraverConfigHead = R"( diff --git a/src/backends/extrae/extrae_type_stack.hpp b/src/backends/extrae/extrae_type_stack.hpp index 7906dd3f2d1abe1034e60aa118c52d8d96505414..c74ab9fa64bd5583b5c5854cc38f4dbe8baaa067 100644 --- a/src/backends/extrae/extrae_type_stack.hpp +++ b/src/backends/extrae/extrae_type_stack.hpp @@ -31,6 +31,7 @@ private: static extrae_value get_value_by_region_name(const std::string &name); public: + ExtraeTypeStackStrategy(); inline static const std::string_view name = "Extrae::TypeStack"; virtual void RegionStart(const ProperlyNestedRegionInformation ®ion) noexcept override; diff --git a/src/parallelism_helper.cpp b/src/parallelism_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..88f5e137b4c52239bc840a226e492226d77ff5dc --- /dev/null +++ b/src/parallelism_helper.cpp @@ -0,0 +1,55 @@ +#include +#include +#include + +#ifdef WITH_MPI + + +bool MPIHelper::IsUsingMPI()const +{ + return is_using_mpi_; + +} + +bool MPIHelper::CompiledWithMPI() const { + return true; +} + +bool MPIHelper::IsRankNumber(int asked_rank) const { + return asked_rank== mpi_comm_rank; +} + +MPIHelper::MPIHelper(){ + // First check if MPI is initialized + int is_initialized; + MPI_Initialized(&is_initialized); + mpi_is_initialized_ = static_cast(is_initialized); + + if(mpi_is_initialized_){ + MPI_Comm_size(MPI_COMM_WORLD,&mpi_comm_size); + MPI_Comm_rank(MPI_COMM_WORLD,&mpi_comm_rank); + + is_using_mpi_ = mpi_comm_size > 1; + } +} + +#else + + +bool MPIHelper::IsUsingMPI() const +{ + return false; +} + +bool MPIHelper::CompiledWithMPI() const { + return false; +} + +bool MPIHelper::IsRankNumber(int asked_rank) const { + return asked_rank==0; +} + +MPIHelper::MPIHelper(){} + + +#endif \ No newline at end of file diff --git a/src/parallelism_helper.hpp b/src/parallelism_helper.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a0edf1fa96ccd0daa38e9864d0d0b76f0b809816 --- /dev/null +++ b/src/parallelism_helper.hpp @@ -0,0 +1,27 @@ +#ifndef NESMIK_PARALLELISM_HELPER_HPP +#define NESMIK_PARALLELISM_HELPER_HPP +/* + Small helper class that can be used by Backends to Check MPI status in the application beeing run. +*/ +class MPIHelper{ + private: + + // Default values for non-MPI execution + bool is_using_mpi_ = false; + bool mpi_is_initialized_ = false; + int mpi_comm_size = 0; + int mpi_comm_rank = 0; + + public: + + MPIHelper(); + // returns if the library is compiled with MPI support + bool CompiledWithMPI() const ; + // Check is the application is actually using MPI with more than one process + bool IsUsingMPI() const; + // Checks if rank is a certain one, and 0 if MPI is not active + bool IsRankNumber(int asked_rank) const; + +}; + +#endif // NESMIK_PARALLELISM_HELPER_HPP \ No newline at end of file diff --git a/src/strategies.hpp b/src/strategies.hpp index 7880da03221c022037e7d669e01674faf23ce86d..6b5011031c384d95ac9a58b0888db49386d28ef5 100644 --- a/src/strategies.hpp +++ b/src/strategies.hpp @@ -5,6 +5,34 @@ #include #include + +/* + Describes the Strategy behavior with respect to MPI. +*/ +enum class MPIDescriptor{ + DontCare, // Strategy doesnt know and doesnt care + Aware, // Strategy knows about MPI and can use the PMPI Interface to do e.g. reductions. + Required // Strategy requires MPI (should be safeguareded by build options) +}; + +/* + Describes the Strategy behavior with respect to any thread level parallelism + Mainly concerned if starting and stopping regions is supported from multiple threads +*/ +enum class ThreadDescriptor{ + Supported, + Unsupported +}; + +/* + Bundles the above enums into a nice struct +*/ +struct ParallelismDescriptor{ + MPIDescriptor mpi_descriptor_ = MPIDescriptor::DontCare; + ThreadDescriptor thread_descriptor_ = ThreadDescriptor::Unsupported; +}; + + struct ProperlyNestedRegionInformation { std::string_view name; }; @@ -23,6 +51,8 @@ public: virtual void RegionStopLast(const ProperlyNestedRegionInformation ®ion) noexcept = 0; virtual void Finalize() noexcept = 0; + + ParallelismDescriptor parallelism_descriptor_; }; class NotProperlyNestedAnnotationStrategy { @@ -34,6 +64,8 @@ public: virtual void RegionStop(const NotProperlyNestedRegionInformation ®ion) noexcept = 0; virtual void Finalize() noexcept = 0; + + ParallelismDescriptor parallelism_descriptor_; }; #endif // NESMIK_STRATEGY_HPP \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c4c5e24dd49731099c36cc90f681aec59ec7ddc0..32c9d067fcdd9c1b710b3feaccae2ffd7daf75db 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -24,6 +24,20 @@ target_include_directories(TestCppTalpTree add_test(NAME TestCppTalpTree COMMAND TestCppTalpTree) + + if(WITH_MPI) + + add_executable(TestCppTalpTreeMPI cpp/TestCppTalpTreeMPI.cpp) + target_link_libraries(TestCppTalpTreeMPI nesmik::nesmik MPI::MPI_CXX) + target_include_directories(TestCppTalpTreeMPI + PRIVATE ${NESMIK_PUBLIC_HEADERS}) + + add_test(NAME TestCppTalpTreeMPI + COMMAND mpirun -np 2 TestCppTalpTree) + + endif() + + endif() if(ENABLE_EXTRAE) diff --git a/tests/cpp/TestCppTalpTreeMPI.cpp b/tests/cpp/TestCppTalpTreeMPI.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1e0e64822fdae7fb0f58e4d1b6cb2d6c0bcaed22 --- /dev/null +++ b/tests/cpp/TestCppTalpTreeMPI.cpp @@ -0,0 +1,20 @@ +#include "nesmik/nesmik.hpp" +#include +int main() { + MPI_Init(NULL,NULL); + nesmik::init("ProperlyNested","TALP-Tree"); + nesmik::region_start("Top"); + nesmik::region_start("child-1"); + nesmik::region_start("child-1.1"); + nesmik::region_stop("child-1.1"); + nesmik::region_start("child-1.2"); + nesmik::region_stop("child-1.2"); + nesmik::region_stop("child-1"); + nesmik::region_start("child-2"); + nesmik::region_start("child-2.1"); + nesmik::region_stop("child-2.1"); + nesmik::region_stop("child-2"); + nesmik::region_stop("Top"); + nesmik::finalize(); + MPI_Finalize(); +}