diff --git a/src/backends/extrae_partial_tracer/extrae_partial_tracer.cpp b/src/backends/extrae_partial_tracer/extrae_partial_tracer.cpp index d2efb16fbaef79de742c29a37d67ebe7f388bcde..9e1593f2a3a1d1a52e55ec3b51576e17c34a81c3 100644 --- a/src/backends/extrae_partial_tracer/extrae_partial_tracer.cpp +++ b/src/backends/extrae_partial_tracer/extrae_partial_tracer.cpp @@ -79,6 +79,12 @@ void ExtraePartialTracer::Init() noexcept { << job.stop_at << "}" << std::endl; } } + if (mpi_helper_.IsRankNumber(0) && + write_all_regions_.getValue().value_or(false)) { + std::cout << "neSmiK Partial Tracer: Writing all regions even though " + "tracing might be off" + << std::endl; + } } void ExtraePartialTracer::RegionStart( @@ -128,17 +134,30 @@ void ExtraePartialTracer::RegionStart( if (!is_shutdown_) { type_stack_strategy_->RegionStart(region); } + // If were not running but env is set, we still add it to the trace + if (is_shutdown_ && write_all_regions_.getValue().value_or(false)) { + start(); + type_stack_strategy_->RegionStart(region); + shutdown(); + } } void ExtraePartialTracer::RegionStopLast( const ProperlyNestedRegionInformation ®ion) noexcept { const std::string region_name = std::string(region.name); + // We add because were not shutdown if (!is_shutdown_) { - std::cout << "Region stop last " << region.name << std::endl; type_stack_strategy_->RegionStopLast(region); } + // If were shutdown we still add it if the env is set + if (is_shutdown_ && write_all_regions_.getValue().value_or(false)) { + start(); + type_stack_strategy_->RegionStopLast(region); + shutdown(); + } + std::vector matching_jobs; for (const auto &job : jobs_) { if ((job.region_name.compare(region_name) == 0) && diff --git a/src/backends/extrae_partial_tracer/extrae_partial_tracer.hpp b/src/backends/extrae_partial_tracer/extrae_partial_tracer.hpp index f704595e6c9597e3b55236957407699a3687cd47..d613fd75c4b5de5010c5ea79a7419b03e5495f4e 100644 --- a/src/backends/extrae_partial_tracer/extrae_partial_tracer.hpp +++ b/src/backends/extrae_partial_tracer/extrae_partial_tracer.hpp @@ -42,6 +42,12 @@ class ExtraePartialTracer : public ProperlyNestedAnnotationStrategy { "EXTRAE_WRITE_CONFIG_FILE", "Write corresponding Paraver .cfg file if set to True", false); + EnvironmentVariable write_all_regions_ = + EnvironmentVariable("PARTIAL_TRACER_ADD_ALL_REGIONS", + "Write all regions into the trace, even though " + "extrae might not be tracing for all of them", + false); + MPIHelper mpi_helper_; std::unordered_map region_counter_starts_; std::unordered_map region_counter_stops_; @@ -51,7 +57,7 @@ class ExtraePartialTracer : public ProperlyNestedAnnotationStrategy { std::unique_ptr type_stack_strategy_; void shutdown() noexcept; void start() noexcept; - const extrae_type state_type_{82000}; + const actual_extrae_type state_type_{82000}; const std::string type_description_ = "Extrae::PartialTracer State"; public: diff --git a/src/backends/extrae_type_stack/extrae_type_stack.cpp b/src/backends/extrae_type_stack/extrae_type_stack.cpp index 43b816fdd02ee812828dc85743ab93d5f9edbf7a..7b6117779a6b1c0c467be3a8dcc79c1593413bf3 100644 --- a/src/backends/extrae_type_stack/extrae_type_stack.cpp +++ b/src/backends/extrae_type_stack/extrae_type_stack.cpp @@ -14,6 +14,10 @@ extern "C" { #include } +inline std::string getLevelString(const std::size_t level) { + return "Level: " + std::to_string(level); +} + ExtraeTypeStackStrategy::ExtraeTypeStackStrategy() : mpi_helper_{}, extrae_wrapper_{base_type_} { parallelism_descriptor_ = { @@ -24,7 +28,7 @@ ExtraeTypeStackStrategy::ExtraeTypeStackStrategy() void ExtraeTypeStackStrategy::Init() noexcept { // initialize the stack levels up to MAX_STACK_LEVELS for (std::size_t i = 0; i < MAX_STACK_LEVELS; i++) { - std::string description = "Level: " + std::to_string(i); + const std::string description = getLevelString(i); extrae_wrapper_.RegisterTypeWithDescription(description, base_type_ + i); } } @@ -35,7 +39,7 @@ void ExtraeTypeStackStrategy::RegionStart( const auto regionName = std::string(region.name); const auto level = region.stack_.size(); max_stack_size = std::max(level, max_stack_size); - std::string description = "Level: " + std::to_string(level); + const std::string description = getLevelString(level); extrae_wrapper_.StartWithTypeNameAndRegionName(description, regionName); } void ExtraeTypeStackStrategy::RegionStopLast( diff --git a/src/backends/extrae_type_stack/extrae_type_stack.hpp b/src/backends/extrae_type_stack/extrae_type_stack.hpp index 2275991eb64c364dd04049bf67ad20ae2d6576df..c8ccf254ee1e8e339a145ec4bbd05e8de8aa0d6f 100644 --- a/src/backends/extrae_type_stack/extrae_type_stack.hpp +++ b/src/backends/extrae_type_stack/extrae_type_stack.hpp @@ -13,7 +13,7 @@ class ExtraeTypeStackStrategy : public ProperlyNestedAnnotationStrategy { private: const bool write_config_file_default_{true}; - const extrae_type base_type_{81000}; // base event for the MPI wrapper + const actual_extrae_type base_type_{81000}; // base event for the MPI wrapper const std::size_t MAX_STACK_LEVELS = 50; // maximum of supported stack levels EnvironmentVariable write_config_file_ = EnvironmentVariable( diff --git a/src/backends/wrappers/extrae/extrae_types.hpp b/src/backends/wrappers/extrae/extrae_types.hpp index 35c5025d0fecf5e34cf47eec9f9ff59fc2ef9fe2..f960f538ef18f1b403acb2022359c56f72b226b6 100644 --- a/src/backends/wrappers/extrae/extrae_types.hpp +++ b/src/backends/wrappers/extrae/extrae_types.hpp @@ -1,5 +1,9 @@ #ifndef NESMIK_EXTRAE_TYPES_HPP #define NESMIK_EXTRAE_TYPES_HPP -typedef unsigned long extrae_value; -typedef unsigned long extrae_type; +// This defines the actually supported types by extrae and paraver. (Spoiler: +// its not what their APIs promote ;)) See +// https://github.com/bsc-performance-tools/extrae/issues/110 and +// https://github.com/bsc-performance-tools/extrae/issues/111 +typedef int actual_extrae_value; +typedef int actual_extrae_type; #endif // NESMIK_EXTRAE_TYPES_HPP diff --git a/src/backends/wrappers/extrae/extrae_wrapper.cpp b/src/backends/wrappers/extrae/extrae_wrapper.cpp index 735d87f89bb381bda5ffd3acacb21ab259cfa1c4..1eab24e62f4b16c4a2a71c30aa1018818ae3af68 100644 --- a/src/backends/wrappers/extrae/extrae_wrapper.cpp +++ b/src/backends/wrappers/extrae/extrae_wrapper.cpp @@ -10,10 +10,16 @@ #include "extrae_types.hpp" #include "paraver_config.hpp" +#ifdef WITH_MPI +#include +#endif + extern "C" { #include } -ExtraeWrapper::ExtraeWrapper(extrae_type base_type) : base_type_(base_type) { + +ExtraeWrapper::ExtraeWrapper(actual_extrae_type base_type) + : base_type_(base_type) { auto isInitializedVal = Extrae_is_initialized(); if (isInitializedVal == 0) { // Extrae is not initialized yet see @@ -24,25 +30,31 @@ ExtraeWrapper::ExtraeWrapper(extrae_type base_type) : base_type_(base_type) { } } -extrae_value ExtraeWrapper::getValueByName(extrae_type type, - const std::string &name) { +actual_extrae_value ExtraeWrapper::getValueByName(actual_extrae_type type, + const std::string &name) { value_map_t &value_map = string_to_value_; if (value_map.count(name) > 0) { return value_map[name]; - } else - // if not allocate new entry - { - const auto newValue = value_map.size() + 1; - value_map[name] = newValue; - return newValue; + } else { + // allocate a new value by hashing the string name + auto hash = std::hash{}(name); + actual_extrae_value downcasted_hash = + static_cast(hash); + if (downcasted_hash < 0) { + // as we dont support negative values in the .pcf files, we also engineer + // around that ;) + downcasted_hash *= -1; + } + value_map[name] = downcasted_hash; + return downcasted_hash; } } void ExtraeWrapper::RegisterTypeWithDescription( - const std::string &type_description, extrae_type type) { + const std::string &type_description, actual_extrae_type type) { type_map_[type_description] = type; } -void ExtraeWrapper::StartWithTypeAndRegionName(extrae_type type, +void ExtraeWrapper::StartWithTypeAndRegionName(actual_extrae_type type, const std::string &value_str) { const auto value = getValueByName(type, value_str); // write it in type specific map @@ -51,13 +63,13 @@ void ExtraeWrapper::StartWithTypeAndRegionName(extrae_type type, static_cast(value)); } -void ExtraeWrapper::StopWithTypeAndRegionName(extrae_type type, +void ExtraeWrapper::StopWithTypeAndRegionName(actual_extrae_type type, const std::string &value_str) { Extrae_eventandcounters(static_cast(type), 0); } void ExtraeWrapper::StopWithTypeNameAndRegionName( - const std::string type_description, const std::string &value_str) { + const std::string &type_description, const std::string &value_str) { // if this assertion fails, the type with that description has not been // registered before and not started. assert(type_map_.count(type_description) > 0); @@ -65,7 +77,7 @@ void ExtraeWrapper::StopWithTypeNameAndRegionName( } void ExtraeWrapper::StartWithTypeNameAndRegionName( - const std::string type_description, const std::string &value_str) { + const std::string &type_description, const std::string &value_str) { if (type_map_.count(type_description) == 0) { const auto new_type = type_map_.size(); type_map_[type_description] = base_type_ + new_type; @@ -74,7 +86,7 @@ void ExtraeWrapper::StartWithTypeNameAndRegionName( } void ExtraeWrapper::Finalize() { - // now for ever type define the event types: + // for ever type define the event types: for (const auto &[description, type_from_map] : type_map_) { // For every type registered: extrae_type_t type = static_cast(type_from_map); @@ -121,14 +133,18 @@ std::string ExtraeWrapper::getParaverConfig(ExtraeParaverConfig config) { ParaverConfig paraver_config(config.description); // create arrays - std::vector types; + std::vector types; std::vector window_names; - std::vector semantic_maximums; + std::vector semantic_maximums; for (const auto &[name, type] : type_map_) { + if (type_to_value_map_[type].empty()) { + // dont put into the paraver config if no values have been recorded + continue; + } types.push_back(type); window_names.push_back(name); // now the ugly search for the semantic maximum - extrae_value semantic_maximum{0}; + actual_extrae_value semantic_maximum{0}; for (const auto &[value_name, value] : type_to_value_map_[type]) { semantic_maximum = std::max(value, semantic_maximum); } diff --git a/src/backends/wrappers/extrae/extrae_wrapper.hpp b/src/backends/wrappers/extrae/extrae_wrapper.hpp index 6fd0ce59681f4249b65b676c4d1980f821f1dc8e..54b3c59395fa5f87b48a93daea940ec974e3f7cf 100644 --- a/src/backends/wrappers/extrae/extrae_wrapper.hpp +++ b/src/backends/wrappers/extrae/extrae_wrapper.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "extrae_types.hpp" @@ -12,32 +13,34 @@ struct ExtraeParaverConfig { std::string description; }; -using value_map_t = std::unordered_map; +using value_map_t = std::unordered_map; class ExtraeWrapper { - const extrae_type base_type_; + const actual_extrae_type base_type_; private: - std::unordered_map type_map_; - std::unordered_map type_to_value_map_; - std::unordered_map string_to_value_; + std::unordered_map type_map_; + std::unordered_map type_to_value_map_; + std::unordered_map string_to_value_; + MPIHelper mpi_helper_; bool did_init_extrae_{false}; EnvironmentVariable finalize_extrae_ = EnvironmentVariable( "CALL_EXTRAE_FINALZIE", "Enable it to tell neSmiK to call Extrae_fini upon finalization.", false); - extrae_value getValueByName(extrae_type type, const std::string &name); + actual_extrae_value getValueByName(actual_extrae_type type, + const std::string &name); public: - ExtraeWrapper(extrae_type base_type); + ExtraeWrapper(actual_extrae_type base_type); void RegisterTypeWithDescription(const std::string &type_description, - extrae_type type); - void StartWithTypeNameAndRegionName(const std::string type_description, + actual_extrae_type type); + void StartWithTypeNameAndRegionName(const std::string &type_description, const std::string &value_str); - void StartWithTypeAndRegionName(extrae_type type, + void StartWithTypeAndRegionName(actual_extrae_type type, const std::string &value_str); - void StopWithTypeAndRegionName(extrae_type type, + void StopWithTypeAndRegionName(actual_extrae_type type, const std::string &value_str); - void StopWithTypeNameAndRegionName(const std::string type_description, + void StopWithTypeNameAndRegionName(const std::string &type_description, const std::string &value_str); std::string getParaverConfig(ExtraeParaverConfig config); diff --git a/src/backends/wrappers/extrae/paraver_config.cpp b/src/backends/wrappers/extrae/paraver_config.cpp index 0caa3c03bc0eb6171e992a94740c61fc8f478f71..d458c23072033f65b9ef61647eeb5e0395e6a6ba 100644 --- a/src/backends/wrappers/extrae/paraver_config.cpp +++ b/src/backends/wrappers/extrae/paraver_config.cpp @@ -93,7 +93,7 @@ void ParaverConfig::addTimeline(ParaverTimelineWindow window_config) { auto replaced_window_y_pos = std::regex_replace( replaced_event_num, std::regex("NESMIK_REPLACE_WINDOW_Y_POSITION"), std::to_string(150)); - extrae_value max_value_in_array{0}; + actual_extrae_value max_value_in_array{0}; auto max_value_in_array_iterator = std::max_element(window_config.semantic_maximums.begin(), diff --git a/src/backends/wrappers/extrae/paraver_config.hpp b/src/backends/wrappers/extrae/paraver_config.hpp index 91d609f97ec36551e7e7b9c51edacac468353283..e52979d7e86c9daba6f46c475c311ad5622b86c8 100644 --- a/src/backends/wrappers/extrae/paraver_config.hpp +++ b/src/backends/wrappers/extrae/paraver_config.hpp @@ -8,8 +8,8 @@ struct ParaverTimelineWindow { const std::vector &window_names; - const std::vector &types; - const std::vector semantic_maximums; + const std::vector &types; + const std::vector semantic_maximums; std::optional stacked_window_name; }; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9223038c8cfd3f81239e8e7805592ea0f053ff4e..2ac8198c4567274248a759f55dc1b64ffe0cf5ce 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -34,29 +34,28 @@ target_include_directories(TestCppTalpTree add_test(NAME TestCppTalpTree COMMAND TestCppTalpTree) +endif() - if(WITH_MPI AND WITH_MPI_TESTS) - - add_executable(TestCppTalpTreeMPI cpp/TestCppTalpTreeMPI.cpp) - target_link_libraries(TestCppTalpTreeMPI nesmik::nesmik MPI::MPI_CXX) - target_include_directories(TestCppTalpTreeMPI - PRIVATE ${NESMIK_PUBLIC_HEADERS}) +if(WITH_MPI AND WITH_MPI_TESTS) + 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 TestCppTalpTree) + add_test(NAME TestCppTalpTreeMPI + COMMAND TestCppTalpTree) - add_executable(TestCppTalpTreeMPI_MPMD cpp/TestCppTalpTreeMPI_MPMD.cpp) - target_link_libraries(TestCppTalpTreeMPI_MPMD nesmik::nesmik MPI::MPI_CXX) - target_include_directories(TestCppTalpTreeMPI_MPMD - PRIVATE ${NESMIK_PUBLIC_HEADERS}) + add_executable(TestCppTalpTreeMPI_MPMD cpp/TestCppTalpTreeMPI_MPMD.cpp) + target_link_libraries(TestCppTalpTreeMPI_MPMD nesmik::nesmik MPI::MPI_CXX) + target_include_directories(TestCppTalpTreeMPI_MPMD + PRIVATE ${NESMIK_PUBLIC_HEADERS}) - add_test(NAME TestCppTalpTreeMPI_MPMD - COMMAND TestCppTalpTreeMPI_MPMD) + add_test(NAME TestCppTalpTreeMPI_MPMD + COMMAND TestCppTalpTreeMPI_MPMD) - endif() +endif() -endif() if(ENABLE_EXTRAE) add_executable(TestCppExtraeTypeStack cpp/TestCppExtraeTypeStack.cpp) diff --git a/tests/cpp/TestCppTalpTreeMPI_MPMD.cpp b/tests/cpp/TestCppTalpTreeMPI_MPMD.cpp index 600f2d3b49e80b7e762143a0642378a7e6b0fd4d..f5e7c67a94bf6d62f51cf3178eb36b4c82f6cc5b 100644 --- a/tests/cpp/TestCppTalpTreeMPI_MPMD.cpp +++ b/tests/cpp/TestCppTalpTreeMPI_MPMD.cpp @@ -6,10 +6,15 @@ int main() { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); nesmik::nesmik_init(); + + MPI_Barrier(MPI_COMM_WORLD); + // each process has its own regions nesmik::region_start("Top"); - nesmik::region_start(std::to_string(rank)); - nesmik::region_stop(std::to_string(rank)); + nesmik::region_start("rank: " + std::to_string(rank)); + nesmik::region_stop("rank: " + std::to_string(rank)); nesmik::region_stop("Top"); + + MPI_Barrier(MPI_COMM_WORLD); nesmik::nesmik_finalize(); MPI_Finalize(); }