From 48c5451b6ca64124db540d68fa68808ca2787892 Mon Sep 17 00:00:00 2001 From: Valentin Seitz <valentin.seitz@bsc.es> Date: Thu, 25 Jul 2024 21:12:10 +0200 Subject: [PATCH 01/12] WIP WUP --- src/backends/extrae/extrae_partial_tracer.cpp | 50 +++++++++++++++++++ src/backends/extrae/extrae_partial_tracer.hpp | 48 ++++++++++++++++++ src/utils/environment_variable.cpp | 38 ++++++++++++++ src/utils/environment_variable.hpp | 8 +++ 4 files changed, 144 insertions(+) create mode 100644 src/backends/extrae/extrae_partial_tracer.cpp create mode 100644 src/backends/extrae/extrae_partial_tracer.hpp diff --git a/src/backends/extrae/extrae_partial_tracer.cpp b/src/backends/extrae/extrae_partial_tracer.cpp new file mode 100644 index 0000000..04e8769 --- /dev/null +++ b/src/backends/extrae/extrae_partial_tracer.cpp @@ -0,0 +1,50 @@ +#include "extrae_partial_tracer.hpp" + +#include <memory> +#include <string> + +extern "C" { +#include <extrae.h> +} +#include <utils/terminator.hpp> + +ExtraePartialTracer::ExtraePartialTracer() : mpi_helper_{} { + parallelism_descriptor_ = { + .mpi_descriptor_ = MPIDescriptor::Aware, + .thread_descriptor_ = ThreadDescriptor::Unsupported}; + type_stack_strategy_ = std::make_unique<ExtraeTypeStackStrategy>(); +} + +void ExtraePartialTracer::shutdown() noexcept { + type_stack_strategy_->RegionStart({"Extrae OFF", {}}); + Extrae_shutdown(); +} + +void ExtraePartialTracer::start() noexcept { + Extrae_restart(); + type_stack_strategy_->RegionStopLast({"Extrae OFF", {}}); +} + +void ExtraePartialTracer::Init() noexcept { + // First init the type stack + type_stack_strategy_->Init(); + shutdown(); + + // then we check the env + const auto number_of_names = region_names_env_.getValue().value().size(); + + if (number_of_names != regions_start_at_env_.getValue().value().size() || + number_of_names != regions_stop_at_env_.getValue().value().size()) { + std::cout << "neSmiK Fatal: Please make sure to specify same amounts of " + "names as well as starts and stops using e.g. " + << regions_stop_at_env_.getEnvName() << "=4,66,89" << std::endl; + Terminator::exit(); + } +} + +void ExtraePartialTracer::RegionStart( + const ProperlyNestedRegionInformation ®ion) noexcept {} +void ExtraePartialTracer::RegionStopLast( + const ProperlyNestedRegionInformation ®ion) noexcept {} + +void ExtraePartialTracer::Finalize() noexcept {} diff --git a/src/backends/extrae/extrae_partial_tracer.hpp b/src/backends/extrae/extrae_partial_tracer.hpp new file mode 100644 index 0000000..9382565 --- /dev/null +++ b/src/backends/extrae/extrae_partial_tracer.hpp @@ -0,0 +1,48 @@ +#include <extrae_type_stack.hpp> +#include <strategies.hpp> +#include <string> +#include <utils/environment_variable.hpp> +#include <utils/parallelism_helper.hpp> +#include <vector> + +class ExtraePartialTracer : public ProperlyNestedAnnotationStrategy { + private: + EnvironmentVariable<std::vector<std::string>> region_names_env_ = + EnvironmentVariable<std::vector<std::string>>( + "PARTIAL_TRACER_REGION_NAMES", + "A comma separated list of names of regions which are disjunct to " + "partially trace.", + true); + EnvironmentVariable<std::vector<unsigned int>> regions_start_at_env_ = + EnvironmentVariable<std::vector<unsigned int>>( + "PARTIAL_TRACER_START_AT_CALL", + "A comma separated list of at which encounter of the region tracing " + "should start", + true); + + EnvironmentVariable<std::vector<unsigned int>> regions_stop_at_env_ = + EnvironmentVariable<std::vector<unsigned int>>( + "PARTIAL_TRACER_STOP_AT_CALL", + "A comma separated list of at which encounter of the region tracing " + "should stop", + true); + + MPIHelper mpi_helper_; + std::unordered_map<std::string, unsigned int> region_counter_; + std::unordered_map<std::string, unsigned int> region_on_off_jobs; + + std::unique_ptr<ExtraeTypeStackStrategy> type_stack_strategy_; + void shutdown(); + void start(); + + public: + ExtraePartialTracer(); + inline static const std::string name = "Extrae::PartialTracer"; + + virtual void RegionStart( + const ProperlyNestedRegionInformation ®ion) noexcept override; + virtual void RegionStopLast( + const ProperlyNestedRegionInformation ®ion) noexcept override; + virtual void Init() noexcept override; + virtual void Finalize() noexcept override; +}; diff --git a/src/utils/environment_variable.cpp b/src/utils/environment_variable.cpp index 979be29..bf1ac27 100644 --- a/src/utils/environment_variable.cpp +++ b/src/utils/environment_variable.cpp @@ -4,8 +4,10 @@ #include <cctype> #include <cstdlib> #include <optional> +#include <sstream> #include <string> #include <utils/string_helpers.hpp> +#include <vector> template <> std::optional<bool> fromEnvString(const std::string &env_string) { @@ -26,3 +28,39 @@ template <> std::optional<std::string> fromEnvString(const std::string &env_string) { return std::optional<std::string>{env_string}; } + +template <> +std::optional<std::vector<std::string>> fromEnvString( + const std::string &env_string) { + const char delimiter = ','; + std::vector<std::string> result; + std::stringstream stream(env_string); + + while (stream.good()) { + std::string entry; + std::getline(stream, entry, delimiter); + if (!entry.empty()) { + result.push_back(entry); + } + } + + if (result.size() > 0) { + return result; + } else { + return std::nullopt; + } +} + +std::optional<std::vector<unsigned int>> fromEnvString( + const std::string &env_string) { + const auto &strings = fromEnvString<std::vector<std::string>>(env_string); + + if (!strings.has_value()) { + return std::nullopt; + } + std::vector<unsigned int> result; + for (const auto &string : strings.value()) { + result.push_back(std::stoul(string)); + } + return result; +} diff --git a/src/utils/environment_variable.hpp b/src/utils/environment_variable.hpp index f071d98..3f6f3f4 100644 --- a/src/utils/environment_variable.hpp +++ b/src/utils/environment_variable.hpp @@ -6,6 +6,7 @@ #include <iostream> #include <optional> #include <string> +#include <vector> // dont allow the compiler to guess, but force user to implement conversion template <typename T> @@ -15,6 +16,13 @@ template <> std::optional<bool> fromEnvString(const std::string &env_string); template <> std::optional<std::string> fromEnvString(const std::string &env_string); +template <> +std::optional<std::vector<std::string>> fromEnvString( + const std::string &env_string); + +template <> +std::optional<std::vector<unsigned int>> fromEnvString( + const std::string &env_string); template <typename T> class EnvironmentVariable { -- GitLab From a7d509a084d442924990a1c6325bd7ab7d42df17 Mon Sep 17 00:00:00 2001 From: Valentin Seitz <valentin.seitz@bsc.es> Date: Fri, 26 Jul 2024 11:47:06 +0200 Subject: [PATCH 02/12] Add partial tracer --- src/backends/extrae/CMakeLists.txt | 2 +- src/backends/extrae/extrae_partial_tracer.cpp | 106 +++++++++++++++++- src/backends/extrae/extrae_partial_tracer.hpp | 20 +++- src/backends/extrae/extrae_type_stack.hpp | 3 + src/delegator.cpp | 10 +- src/utils/environment_variable.cpp | 2 +- 6 files changed, 129 insertions(+), 14 deletions(-) diff --git a/src/backends/extrae/CMakeLists.txt b/src/backends/extrae/CMakeLists.txt index 319ef9c..2512a61 100644 --- a/src/backends/extrae/CMakeLists.txt +++ b/src/backends/extrae/CMakeLists.txt @@ -1 +1 @@ -target_sources(nesmik PRIVATE extrae_type_stack.cpp) +target_sources(nesmik PRIVATE extrae_partial_tracer.cpp extrae_type_stack.cpp) diff --git a/src/backends/extrae/extrae_partial_tracer.cpp b/src/backends/extrae/extrae_partial_tracer.cpp index 04e8769..765de0d 100644 --- a/src/backends/extrae/extrae_partial_tracer.cpp +++ b/src/backends/extrae/extrae_partial_tracer.cpp @@ -1,8 +1,8 @@ #include "extrae_partial_tracer.hpp" +#include <algorithm> #include <memory> #include <string> - extern "C" { #include <extrae.h> } @@ -18,11 +18,13 @@ ExtraePartialTracer::ExtraePartialTracer() : mpi_helper_{} { void ExtraePartialTracer::shutdown() noexcept { type_stack_strategy_->RegionStart({"Extrae OFF", {}}); Extrae_shutdown(); + is_shutdown_ = true; } void ExtraePartialTracer::start() noexcept { Extrae_restart(); type_stack_strategy_->RegionStopLast({"Extrae OFF", {}}); + is_shutdown_ = false; } void ExtraePartialTracer::Init() noexcept { @@ -32,6 +34,12 @@ void ExtraePartialTracer::Init() noexcept { // then we check the env const auto number_of_names = region_names_env_.getValue().value().size(); + if (number_of_names == 0) { + std::cout << "neSmiK Fatal: Please make sure to specify minimum one region " + "to partiallys trace" + << std::endl; + Terminator::exit(); + } if (number_of_names != regions_start_at_env_.getValue().value().size() || number_of_names != regions_stop_at_env_.getValue().value().size()) { @@ -40,11 +48,101 @@ void ExtraePartialTracer::Init() noexcept { << regions_stop_at_env_.getEnvName() << "=4,66,89" << std::endl; Terminator::exit(); } + + jobs_.reserve(number_of_names); + + // now create the start stop jobs + for (std::size_t i = 0; i < number_of_names; i++) { + StartStopJob job{.region_name = region_names_env_.getValue().value()[i], + .start_at = regions_start_at_env_.getValue().value()[i], + .stop_at = regions_stop_at_env_.getValue().value()[i]}; + jobs_.push_back(job); + } } void ExtraePartialTracer::RegionStart( - const ProperlyNestedRegionInformation ®ion) noexcept {} + const ProperlyNestedRegionInformation ®ion) noexcept { + const std::string region_name = std::string(region.name); + // A bit costly maybe if there is a lot of jobs, but much easier than keeping + // a tree or hashmap around + + std::vector<StartStopJob> matching_jobs; + for (const auto &job : jobs_) { + if ((job.region_name.compare(region_name) == 0) && + region_counter_starts_[region_name] == job.start_at) { + // nice we found a matching one + matching_jobs.push_back(job); + } + } + + if (matching_jobs.size() > 1) { + std::cout + << "neSmiK Extrae::PartialTracer: Found multiple matching jobs, please " + "dont duplicate region names with the same start iteration" + << std::endl; + Terminator::exit(); + } + if (!matching_jobs.empty()) { + if (!is_shutdown_) { + std::cout + << "neSmiK Extrae::PartialTracer: The regions you selected are " + "overlapping. The tracer is already running for " + << region_name + << ". Please make sure to select non overlapping regions and restart" + << std::endl; + } + // We need to startup extrae and emit the region_start event + start(); + } + + region_counter_starts_[region_name]++; + + // if were running call extrae backend + if (!is_shutdown_) { + type_stack_strategy_->RegionStart(region); + } +} void ExtraePartialTracer::RegionStopLast( - const ProperlyNestedRegionInformation ®ion) noexcept {} + const ProperlyNestedRegionInformation ®ion) noexcept { + const std::string region_name = std::string(region.name); + + if (!is_shutdown_) { + type_stack_strategy_->RegionStopLast(region); + } + + std::vector<StartStopJob> matching_jobs; + for (const auto &job : jobs_) { + if ((job.region_name.compare(region_name) == 0) && + region_counter_stops_[region_name] == job.stop_at) { + // nice we found a matching one + matching_jobs.push_back(job); + } + } + + if (matching_jobs.size() > 1) { + std::cout + << "neSmiK Extrae::PartialTracer: Found multiple matching jobs, please " + "dont duplicate region names with the same stop iteration" + << std::endl; + Terminator::exit(); + } + + if (!matching_jobs.empty()) { + if (is_shutdown_) { + std::cout + << "neSmiK Extrae::PartialTracer: The regions you selected are " + "overlapping. The tracer is already stopped for " + << region_name + << ". Please make sure to select non overlapping regions and restart" + << std::endl; + } + // We need to stop extrae + shutdown(); + } -void ExtraePartialTracer::Finalize() noexcept {} + region_counter_stops_[region_name]++; +} + +void ExtraePartialTracer::Finalize() noexcept { + type_stack_strategy_->Finalize(); +} diff --git a/src/backends/extrae/extrae_partial_tracer.hpp b/src/backends/extrae/extrae_partial_tracer.hpp index 9382565..6f2093b 100644 --- a/src/backends/extrae/extrae_partial_tracer.hpp +++ b/src/backends/extrae/extrae_partial_tracer.hpp @@ -1,10 +1,17 @@ -#include <extrae_type_stack.hpp> #include <strategies.hpp> #include <string> #include <utils/environment_variable.hpp> #include <utils/parallelism_helper.hpp> #include <vector> +#include "extrae_type_stack.hpp" + +struct StartStopJob { + std::string region_name; + unsigned int start_at; + unsigned int stop_at; +}; + class ExtraePartialTracer : public ProperlyNestedAnnotationStrategy { private: EnvironmentVariable<std::vector<std::string>> region_names_env_ = @@ -28,12 +35,13 @@ class ExtraePartialTracer : public ProperlyNestedAnnotationStrategy { true); MPIHelper mpi_helper_; - std::unordered_map<std::string, unsigned int> region_counter_; - std::unordered_map<std::string, unsigned int> region_on_off_jobs; - + std::unordered_map<std::string, unsigned int> region_counter_starts_; + std::unordered_map<std::string, unsigned int> region_counter_stops_; + std::vector<StartStopJob> jobs_; + bool is_shutdown_{true}; std::unique_ptr<ExtraeTypeStackStrategy> type_stack_strategy_; - void shutdown(); - void start(); + void shutdown() noexcept; + void start() noexcept; public: ExtraePartialTracer(); diff --git a/src/backends/extrae/extrae_type_stack.hpp b/src/backends/extrae/extrae_type_stack.hpp index 02370f8..b66bd55 100644 --- a/src/backends/extrae/extrae_type_stack.hpp +++ b/src/backends/extrae/extrae_type_stack.hpp @@ -1,3 +1,5 @@ +#ifndef NESMIK_EXTRAE_TYPE_STACK_HPP +#define NESMIK_EXTRAE_TYPE_STACK_HPP #include <stack> #include <string> #include <unordered_map> @@ -52,3 +54,4 @@ class ExtraeTypeStackStrategy : public ProperlyNestedAnnotationStrategy { virtual void Init() noexcept override; virtual void Finalize() noexcept override; }; +#endif // NESMIK_EXTRAE_TYPE_STACK_HPP diff --git a/src/delegator.cpp b/src/delegator.cpp index 2439203..bb7a54f 100644 --- a/src/delegator.cpp +++ b/src/delegator.cpp @@ -18,6 +18,7 @@ #endif #ifdef ENABLE_EXTRAE +#include "backends/extrae/extrae_partial_tracer.hpp" #include "backends/extrae/extrae_type_stack.hpp" #endif @@ -41,6 +42,8 @@ void Delegator::TryInitProperlyNestedBackend(const std::string &backend) { #ifdef ENABLE_EXTRAE else if (backend.compare(ExtraeTypeStackStrategy::name) == 0) { pn_annotation_strategy_ = std::make_unique<ExtraeTypeStackStrategy>(); + } else if (backend.compare(ExtraePartialTracer::name) == 0) { + pn_annotation_strategy_ = std::make_unique<ExtraePartialTracer>(); } #endif #ifdef ENABLE_DLB @@ -52,12 +55,15 @@ void Delegator::TryInitProperlyNestedBackend(const std::string &backend) { const std::vector<std::string> Delegator::available_backends = { #ifdef ENABLE_DLB - DLBTalpTreeStrategy::name, DLBTalpStrategy::name, + DLBTalpTreeStrategy::name, + DLBTalpStrategy::name, #endif #ifdef ENABLE_EXTRAE ExtraeTypeStackStrategy::name, + ExtraePartialTracer::name, #endif - "Default", "Detection"}; + "Default", + "Detection"}; bool Delegator::checkIfBackendAvailable(const std::string &backend) { bool found_backend{false}; diff --git a/src/utils/environment_variable.cpp b/src/utils/environment_variable.cpp index bf1ac27..e00cbd5 100644 --- a/src/utils/environment_variable.cpp +++ b/src/utils/environment_variable.cpp @@ -50,7 +50,7 @@ std::optional<std::vector<std::string>> fromEnvString( return std::nullopt; } } - +template <> std::optional<std::vector<unsigned int>> fromEnvString( const std::string &env_string) { const auto &strings = fromEnvString<std::vector<std::string>>(env_string); -- GitLab From 49bbd40776328b83de9e3ef7642414a1313c6d6a Mon Sep 17 00:00:00 2001 From: VALENTIN SEITZ <valentin.seitz@bsc.es> Date: Fri, 26 Jul 2024 19:43:45 +0200 Subject: [PATCH 03/12] Apply 1 suggestion(s) to 1 file(s) Co-authored-by: JOAN VINYALS YLLA CATALA <joan.vinyals@bsc.es> --- src/backends/extrae/extrae_partial_tracer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backends/extrae/extrae_partial_tracer.cpp b/src/backends/extrae/extrae_partial_tracer.cpp index 765de0d..c2c47b6 100644 --- a/src/backends/extrae/extrae_partial_tracer.cpp +++ b/src/backends/extrae/extrae_partial_tracer.cpp @@ -30,6 +30,7 @@ void ExtraePartialTracer::start() noexcept { void ExtraePartialTracer::Init() noexcept { // First init the type stack type_stack_strategy_->Init(); + // And pause extrae shutdown(); // then we check the env -- GitLab From 182ca555759853e53fe56d46b542bc0681d61d70 Mon Sep 17 00:00:00 2001 From: VALENTIN SEITZ <valentin.seitz@bsc.es> Date: Fri, 26 Jul 2024 19:44:05 +0200 Subject: [PATCH 04/12] Apply 1 suggestion(s) to 1 file(s) Co-authored-by: JOAN VINYALS YLLA CATALA <joan.vinyals@bsc.es> --- src/backends/extrae/extrae_partial_tracer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/extrae/extrae_partial_tracer.cpp b/src/backends/extrae/extrae_partial_tracer.cpp index c2c47b6..99eb1ec 100644 --- a/src/backends/extrae/extrae_partial_tracer.cpp +++ b/src/backends/extrae/extrae_partial_tracer.cpp @@ -64,9 +64,9 @@ void ExtraePartialTracer::Init() noexcept { void ExtraePartialTracer::RegionStart( const ProperlyNestedRegionInformation ®ion) noexcept { const std::string region_name = std::string(region.name); + // A bit costly maybe if there is a lot of jobs, but much easier than keeping // a tree or hashmap around - std::vector<StartStopJob> matching_jobs; for (const auto &job : jobs_) { if ((job.region_name.compare(region_name) == 0) && -- GitLab From 8c875125bcb7670038d6a7f254670f2d4536a44c Mon Sep 17 00:00:00 2001 From: VALENTIN SEITZ <valentin.seitz@bsc.es> Date: Fri, 26 Jul 2024 19:53:38 +0200 Subject: [PATCH 05/12] Apply 1 suggestion(s) to 1 file(s) Co-authored-by: JOAN VINYALS YLLA CATALA <joan.vinyals@bsc.es> --- src/backends/extrae/extrae_partial_tracer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backends/extrae/extrae_partial_tracer.cpp b/src/backends/extrae/extrae_partial_tracer.cpp index 99eb1ec..a16c386 100644 --- a/src/backends/extrae/extrae_partial_tracer.cpp +++ b/src/backends/extrae/extrae_partial_tracer.cpp @@ -103,6 +103,7 @@ void ExtraePartialTracer::RegionStart( type_stack_strategy_->RegionStart(region); } } + void ExtraePartialTracer::RegionStopLast( const ProperlyNestedRegionInformation ®ion) noexcept { const std::string region_name = std::string(region.name); -- GitLab From a8e62567df1649bb3df3a3016f40483e82c4f44d Mon Sep 17 00:00:00 2001 From: VALENTIN SEITZ <valentin.seitz@bsc.es> Date: Fri, 26 Jul 2024 19:56:32 +0200 Subject: [PATCH 06/12] Apply 1 suggestion(s) to 1 file(s) Co-authored-by: JOAN VINYALS YLLA CATALA <joan.vinyals@bsc.es> --- src/utils/environment_variable.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/environment_variable.cpp b/src/utils/environment_variable.cpp index e00cbd5..822867a 100644 --- a/src/utils/environment_variable.cpp +++ b/src/utils/environment_variable.cpp @@ -50,6 +50,7 @@ std::optional<std::vector<std::string>> fromEnvString( return std::nullopt; } } + template <> std::optional<std::vector<unsigned int>> fromEnvString( const std::string &env_string) { -- GitLab From d6fbd8bd1af15d84e6c9e7ae07647ba0f7804034 Mon Sep 17 00:00:00 2001 From: Valentin Seitz <valentin.seitz@bsc.es> Date: Mon, 29 Jul 2024 14:14:51 +0200 Subject: [PATCH 07/12] Remove static threadlocal stuff as not needed --- src/backends/extrae/extrae_type_stack.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/backends/extrae/extrae_type_stack.hpp b/src/backends/extrae/extrae_type_stack.hpp index b66bd55..cef9657 100644 --- a/src/backends/extrae/extrae_type_stack.hpp +++ b/src/backends/extrae/extrae_type_stack.hpp @@ -28,19 +28,19 @@ class ExtraeTypeStackStrategy : public ProperlyNestedAnnotationStrategy { static const std::string paraverConfigOverviewWindow; static const std::string paraverConfigLevelWindow; + inline static const int paraverConfigWindowHeight_ = 115; + inline static const int paraverConfigWindowHeightPad_ = 35; + EnvironmentVariable<bool> write_config_file_ = EnvironmentVariable<bool>( "EXTRAE_WRITE_CONFIG_FILE", "Write corresponding Paraver .cfg file if set to True", false); - inline static const int paraverConfigWindowHeight_ = 115; - inline static const int paraverConfigWindowHeightPad_ = 35; - MPIHelper mpi_helper_; - inline static bool didInitialize{false}; + bool didInitialize{false}; - inline static thread_local RegionStackData regionStackData; - inline static thread_local RegionMapData regionMapData; + RegionStackData regionStackData; + RegionMapData regionMapData; extrae_value get_value_by_region_name(const std::string &name); public: -- GitLab From b4bc01da7e0025cca3fb8714cffa0642ffd196c6 Mon Sep 17 00:00:00 2001 From: Valentin Seitz <valentin.seitz@bsc.es> Date: Tue, 30 Jul 2024 17:18:26 +0200 Subject: [PATCH 08/12] add some debug statements --- src/backends/extrae/extrae_partial_tracer.cpp | 30 +++++++++++++++++++ src/backends/extrae/extrae_partial_tracer.hpp | 3 ++ 2 files changed, 33 insertions(+) diff --git a/src/backends/extrae/extrae_partial_tracer.cpp b/src/backends/extrae/extrae_partial_tracer.cpp index a16c386..e71d425 100644 --- a/src/backends/extrae/extrae_partial_tracer.cpp +++ b/src/backends/extrae/extrae_partial_tracer.cpp @@ -16,12 +16,18 @@ ExtraePartialTracer::ExtraePartialTracer() : mpi_helper_{} { } void ExtraePartialTracer::shutdown() noexcept { + if (debug_output_.getValue().value_or(false) && mpi_helper_.IsRankNumber(0)) { + std::cout << "neSmiK Partial Tracer: Shutting down" << std::endl; + } type_stack_strategy_->RegionStart({"Extrae OFF", {}}); Extrae_shutdown(); is_shutdown_ = true; } void ExtraePartialTracer::start() noexcept { + if (debug_output_.getValue().value_or(false) && mpi_helper_.IsRankNumber(0)) { + std::cout << "neSmiK Partial Tracer: Starting up" << std::endl; + } Extrae_restart(); type_stack_strategy_->RegionStopLast({"Extrae OFF", {}}); is_shutdown_ = false; @@ -59,6 +65,18 @@ void ExtraePartialTracer::Init() noexcept { .stop_at = regions_stop_at_env_.getValue().value()[i]}; jobs_.push_back(job); } + + if (debug_output_.getValue().value_or(false) && mpi_helper_.IsRankNumber(0)) { + std::cout << "neSmiK Partial Tracer: Read the following jobs from env:" + << std::endl; + std::cout << "neSmiK Partial Tracer: {name,start_at,stop_at}" << std::endl; + for (std::size_t i = 0; i < jobs_.size(); i++) { + const auto &job = jobs_[i]; + std::cout << "neSmiK Partial Tracer: Jobs: " << i << "{\"" + << job.region_name << "\"," << job.start_at << "," + << job.stop_at << "}" << std::endl; + } + } } void ExtraePartialTracer::RegionStart( @@ -94,6 +112,12 @@ void ExtraePartialTracer::RegionStart( } // We need to startup extrae and emit the region_start event start(); + } else { + if (debug_output_.getValue().value_or(false) && + mpi_helper_.IsRankNumber(0)) { + std::cout << "neSmiK Extrae::PartialTracer: No Start found for " + << region_name << std::endl; + } } region_counter_starts_[region_name]++; @@ -140,6 +164,12 @@ void ExtraePartialTracer::RegionStopLast( } // We need to stop extrae shutdown(); + } else { + if (debug_output_.getValue().value_or(false) && + mpi_helper_.IsRankNumber(0)) { + std::cout << "neSmiK Extrae::PartialTracer: No Stop found for " + << region_name << std::endl; + } } region_counter_stops_[region_name]++; diff --git a/src/backends/extrae/extrae_partial_tracer.hpp b/src/backends/extrae/extrae_partial_tracer.hpp index 6f2093b..64f8dd3 100644 --- a/src/backends/extrae/extrae_partial_tracer.hpp +++ b/src/backends/extrae/extrae_partial_tracer.hpp @@ -34,6 +34,9 @@ class ExtraePartialTracer : public ProperlyNestedAnnotationStrategy { "should stop", true); + EnvironmentVariable<bool> debug_output_ = + EnvironmentVariable<bool>("PARTIAL_TRACER_DEBUG", "DEBUG output", false); + MPIHelper mpi_helper_; std::unordered_map<std::string, unsigned int> region_counter_starts_; std::unordered_map<std::string, unsigned int> region_counter_stops_; -- GitLab From ef28ed0ecf4cd971f8929ff402fd63cd006eac46 Mon Sep 17 00:00:00 2001 From: Valentin Seitz <valentin.seitz@bsc.es> Date: Thu, 1 Aug 2024 15:00:08 +0200 Subject: [PATCH 09/12] Massive refactor of extrae infrastructure --- src/backends/extrae/CMakeLists.txt | 2 +- src/backends/extrae/extrae_partial_tracer.cpp | 25 +- src/backends/extrae/extrae_partial_tracer.hpp | 8 + src/backends/extrae/extrae_type_stack.cpp | 268 ++---------------- src/backends/extrae/extrae_type_stack.hpp | 21 +- src/backends/extrae/extrae_types.hpp | 5 + src/backends/extrae/extrae_wrapper.cpp | 142 ++++++++++ src/backends/extrae/extrae_wrapper.hpp | 39 +++ src/backends/extrae/paraver_config.cpp | 134 +++++++++ src/backends/extrae/paraver_config.hpp | 29 ++ 10 files changed, 413 insertions(+), 260 deletions(-) create mode 100644 src/backends/extrae/extrae_types.hpp create mode 100644 src/backends/extrae/extrae_wrapper.cpp create mode 100644 src/backends/extrae/extrae_wrapper.hpp create mode 100644 src/backends/extrae/paraver_config.cpp create mode 100644 src/backends/extrae/paraver_config.hpp diff --git a/src/backends/extrae/CMakeLists.txt b/src/backends/extrae/CMakeLists.txt index 2512a61..e8ec467 100644 --- a/src/backends/extrae/CMakeLists.txt +++ b/src/backends/extrae/CMakeLists.txt @@ -1 +1 @@ -target_sources(nesmik PRIVATE extrae_partial_tracer.cpp extrae_type_stack.cpp) +target_sources(nesmik PRIVATE extrae_partial_tracer.cpp extrae_type_stack.cpp extrae_wrapper.cpp paraver_config.cpp) diff --git a/src/backends/extrae/extrae_partial_tracer.cpp b/src/backends/extrae/extrae_partial_tracer.cpp index e71d425..3c262e7 100644 --- a/src/backends/extrae/extrae_partial_tracer.cpp +++ b/src/backends/extrae/extrae_partial_tracer.cpp @@ -1,6 +1,7 @@ #include "extrae_partial_tracer.hpp" #include <algorithm> +#include <fstream> #include <memory> #include <string> extern "C" { @@ -12,14 +13,16 @@ ExtraePartialTracer::ExtraePartialTracer() : mpi_helper_{} { parallelism_descriptor_ = { .mpi_descriptor_ = MPIDescriptor::Aware, .thread_descriptor_ = ThreadDescriptor::Unsupported}; + extrae_wrapper_ = std::make_unique<ExtraeWrapper>(state_type_); type_stack_strategy_ = std::make_unique<ExtraeTypeStackStrategy>(); + extrae_wrapper_->RegisterTypeWithDescription(type_description, state_type_); } void ExtraePartialTracer::shutdown() noexcept { if (debug_output_.getValue().value_or(false) && mpi_helper_.IsRankNumber(0)) { std::cout << "neSmiK Partial Tracer: Shutting down" << std::endl; } - type_stack_strategy_->RegionStart({"Extrae OFF", {}}); + extrae_wrapper_->StopWithTypeAndRegionName(state_type_, "ON"); Extrae_shutdown(); is_shutdown_ = true; } @@ -29,13 +32,11 @@ void ExtraePartialTracer::start() noexcept { std::cout << "neSmiK Partial Tracer: Starting up" << std::endl; } Extrae_restart(); - type_stack_strategy_->RegionStopLast({"Extrae OFF", {}}); + extrae_wrapper_->StartWithTypeAndRegionName(state_type_, "ON"); is_shutdown_ = false; } void ExtraePartialTracer::Init() noexcept { - // First init the type stack - type_stack_strategy_->Init(); // And pause extrae shutdown(); @@ -77,6 +78,8 @@ void ExtraePartialTracer::Init() noexcept { << job.stop_at << "}" << std::endl; } } + + is_initialized_ = true; } void ExtraePartialTracer::RegionStart( @@ -133,6 +136,7 @@ void ExtraePartialTracer::RegionStopLast( const std::string region_name = std::string(region.name); if (!is_shutdown_) { + std::cout << "Region stop last " << region.name << std::endl; type_stack_strategy_->RegionStopLast(region); } @@ -176,5 +180,18 @@ void ExtraePartialTracer::RegionStopLast( } void ExtraePartialTracer::Finalize() noexcept { + if (write_config_file_.getValue().value_or(true) && + mpi_helper_.IsRankNumber(0)) { + std::string fileName = "nesmik_running.cfg"; + std::ofstream out_file; + out_file.open(fileName); + ExtraeParaverConfig paraver_config{ + .stacked_window_name = std::nullopt, + .description = "neSmiK Partial Tracer state"}; + // write config + out_file << extrae_wrapper_->getParaverConfig(paraver_config) << std::endl; + } + + extrae_wrapper_->Finalize(); type_stack_strategy_->Finalize(); } diff --git a/src/backends/extrae/extrae_partial_tracer.hpp b/src/backends/extrae/extrae_partial_tracer.hpp index 64f8dd3..22c2037 100644 --- a/src/backends/extrae/extrae_partial_tracer.hpp +++ b/src/backends/extrae/extrae_partial_tracer.hpp @@ -37,14 +37,22 @@ class ExtraePartialTracer : public ProperlyNestedAnnotationStrategy { EnvironmentVariable<bool> debug_output_ = EnvironmentVariable<bool>("PARTIAL_TRACER_DEBUG", "DEBUG output", false); + EnvironmentVariable<bool> write_config_file_ = EnvironmentVariable<bool>( + "EXTRAE_WRITE_CONFIG_FILE", + "Write corresponding Paraver .cfg file if set to True", false); + MPIHelper mpi_helper_; std::unordered_map<std::string, unsigned int> region_counter_starts_; std::unordered_map<std::string, unsigned int> region_counter_stops_; std::vector<StartStopJob> jobs_; bool is_shutdown_{true}; + bool is_initialized_{false}; + std::unique_ptr<ExtraeWrapper> extrae_wrapper_; std::unique_ptr<ExtraeTypeStackStrategy> type_stack_strategy_; void shutdown() noexcept; void start() noexcept; + const extrae_type state_type_{9780}; + const std::string type_description = "Extrae::PartialTracer State"; public: ExtraePartialTracer(); diff --git a/src/backends/extrae/extrae_type_stack.cpp b/src/backends/extrae/extrae_type_stack.cpp index be8be21..57714a4 100644 --- a/src/backends/extrae/extrae_type_stack.cpp +++ b/src/backends/extrae/extrae_type_stack.cpp @@ -5,6 +5,7 @@ #include <fstream> #include <iostream> #include <numeric> +#include <optional> #include <regex> #include <string> #include <vector> @@ -17,121 +18,15 @@ ExtraeTypeStackStrategy::ExtraeTypeStackStrategy() : mpi_helper_{} { parallelism_descriptor_ = { .mpi_descriptor_ = MPIDescriptor::Aware, .thread_descriptor_ = ThreadDescriptor::Unsupported}; -} - -const std::string ExtraeTypeStackStrategy::paraverConfigHead = R"( -#ParaverCFG -ConfigFile.Version: 3.4 -ConfigFile.NumWindows: 2 -ConfigFile.BeginDescription -Configuration to visualize the annotation done by neSmiK in Paraver -ConfigFile.EndDescription -)"; - -const std::string ExtraeTypeStackStrategy::paraverConfigOverviewWindow = R"( -################################################################################ -< NEW DISPLAYING WINDOW neSmiK Annotation Overview > -################################################################################ -window_name neSmiK Annotation Overview -window_type single -window_position_x 400 -window_position_y 150 -window_width 600 -window_height NESMIK_REPLACE_WINDOW_HEIGHT -window_comm_lines_enabled false -window_flags_enabled false -window_noncolor_mode true -window_custom_color_enabled false -window_semantic_scale_min_at_zero false -window_logical_filtered true -window_physical_filtered false -window_intracomms_enabled true -window_intercomms_enabled true -window_comm_fromto true -window_comm_tagsize true -window_comm_typeval true -window_maximum_y NESMIK_REPLACE_SEMANTIC_MAX -window_minimum_y 0 -window_compute_y_max false -window_level thread -window_scale_relative 1.000000000000 -window_end_time_relative 1.000000000000 -window_object appl { 1, { All } } -window_begin_time_relative 0.000000000000 -window_open true -window_drawmode draw_maximum -window_drawmode_rows draw_maximum -window_pixel_size 1 -window_labels_to_draw 1 -window_object_axis_position 0 -window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } } -window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, Stacked Val}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } } -window_filter_module evt_type NESMIK_REPLACE_NUM_LEVELS NESMIK_REPLACE_LEVELS -)"; - -const std::string ExtraeTypeStackStrategy::paraverConfigLevelWindow = R"( -################################################################################ -< NEW DISPLAYING WINDOW NESMIK_REPLACE_WINDOW_NAME > -################################################################################ -window_name NESMIK_REPLACE_WINDOW_NAME -window_type single -window_position_x 400 -window_position_y NESMIK_REPLACE_WINDOW_Y_POSITION -window_width 600 -window_height NESMIK_REPLACE_WINDOW_HEIGHT -window_comm_lines_enabled false -window_flags_enabled false -window_noncolor_mode true -window_custom_color_enabled false -window_semantic_scale_min_at_zero false -window_logical_filtered true -window_physical_filtered false -window_intracomms_enabled true -window_intercomms_enabled true -window_comm_fromto true -window_comm_tagsize true -window_comm_typeval true -window_maximum_y NESMIK_REPLACE_SEMANTIC_MAX -window_minimum_y 0 -window_compute_y_max false -window_level thread -window_scale_relative 1.000000000000 -window_end_time_relative 1.000000000000 -window_object appl { 1, { All } } -window_begin_time_relative 0.000000000000 -window_open true -window_drawmode draw_maximum -window_drawmode_rows draw_maximum -window_pixel_size 1 -window_labels_to_draw 1 -window_object_axis_position 0 -window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } } -window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, As Is}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } } -window_filter_module evt_type 1 NESMIK_REPLACE_EVENT_TYPE -)"; -void ExtraeTypeStackStrategy::Init() noexcept { - auto isInitializedVal = Extrae_is_initialized(); - if (isInitializedVal == 0) { - // Extrae is not initialized yet see - // https://github.com/bsc-performance-tools/extrae/blob/daee11a2f98e301eb146608f51df0c844e1ff381/include/extrae_types.h#L33 - Extrae_init(); - didInitialize = true; - std::cout << "NESMIK forced to Initialize extrae" << std::endl; - } + extrae_wrapper_ = std::make_unique<ExtraeWrapper>(base_type_); } -extrae_value ExtraeTypeStackStrategy::get_value_by_region_name( - const std::string &name) { - // maybe insert - if (regionMapData.regionNameToValue.count(name) > 0) { - return regionMapData.regionNameToValue[name]; - } else - // if not allocate new entry - { - const auto newValue = regionMapData.regionNameToValue.size() + 1; - regionMapData.regionNameToValue[name] = newValue; - return newValue; +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); + extrae_wrapper_->RegisterTypeWithDescription(description, base_type_ + i); } } @@ -139,142 +34,35 @@ void ExtraeTypeStackStrategy::RegionStart( const ProperlyNestedRegionInformation ®ion) noexcept { // First push to stack const auto regionName = std::string(region.name); - auto typeOffset = regionStackData.regionNameStack.size(); - regionStackData.regionNameStack.push(regionName); - - regionStackData.historicMaxStackSize = - std::max(typeOffset, regionStackData.historicMaxStackSize); - - auto value = get_value_by_region_name(regionName); - - auto type = baseType + typeOffset; - - Extrae_eventandcounters(type, value); + const auto level = region.stack_.size(); + max_stack_size = std::max(level, max_stack_size); + std::string description = "Level: " + std::to_string(level); + extrae_wrapper_->StartWithTypeNameAndRegionName(description, regionName); } void ExtraeTypeStackStrategy::RegionStopLast( const ProperlyNestedRegionInformation ®ion) noexcept { - if (regionStackData.regionNameStack.empty()) { - // whoops - std::cout << "imbalanced region stop REASON: Empty stack " << region.name - << std::endl; - return; - } - - const auto &lastRegionName = regionStackData.regionNameStack.top(); - - if (lastRegionName.compare(region.name) == 0) { - // its the same -> we pop it and end that stack level with a 0 - regionStackData.regionNameStack.pop(); - auto typeOffset = regionStackData.regionNameStack.size(); - auto type = baseType + typeOffset; - Extrae_eventandcounters(type, 0); - return; - } else { - std::cout << "imbalanced region stop " << region.name << std::endl; - } + 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); + extrae_wrapper_->StopWithTypeNameAndRegionName(description, regionName); } void ExtraeTypeStackStrategy::Finalize() noexcept { - unsigned int numberOfRegionsRegistered = - regionMapData.regionNameToValue.size(); - std::vector<extrae_value_t> values{}; - std::vector<std::string> routine_names{}; - - for (const auto &item : regionMapData.regionNameToValue) { - const auto &routine_name = item.first; - const auto &value = item.second; - routine_names.push_back(routine_name); - values.push_back(value); - } - // leaking memory a bit, but c vs c++ strings are not worth making it not - // leaky? - char **routine_c_names = new char *[numberOfRegionsRegistered]; - for (unsigned int i = 0; i < numberOfRegionsRegistered; i++) { - routine_c_names[i] = new char[routine_names[i].size() + 1]; - std::strcpy(routine_c_names[i], routine_names[i].c_str()); - } - - for (unsigned int level = 0; level <= regionStackData.historicMaxStackSize; - level++) { - extrae_type_t type = baseType + level; - std::string description = "Level: " + std::to_string(level); - Extrae_define_event_type(&type, const_cast<char *>(description.c_str()), - &numberOfRegionsRegistered, values.data(), - routine_c_names); - } - if (write_config_file_.getValue().value_or(write_config_file_default_) && mpi_helper_.IsRankNumber(0)) { std::string fileName = "nesmik_annotations.cfg"; - std::ofstream outputFile; - outputFile.open(fileName); - - // write header - outputFile << paraverConfigHead; - - // compute overview - auto numberOfEventTypes = - regionStackData.historicMaxStackSize + 1; // 0 based so plus 1 - auto allTypes = std::vector<extrae_type>(numberOfEventTypes); - std::iota(std::begin(allTypes), std::end(allTypes), - baseType); // Fill with baseType baseType+1 .. - - // Build a small list of all types - std::string allTypesString = ""; - for (const auto &type : allTypes) { - allTypesString += std::to_string(type) + " "; - } - - auto overviewReplacedNumLevels = std::regex_replace( - paraverConfigOverviewWindow, std::regex("NESMIK_REPLACE_NUM_LEVELS"), - std::to_string(numberOfEventTypes)); - auto replacedWindowHeightOverview = std::regex_replace( - overviewReplacedNumLevels, std::regex("NESMIK_REPLACE_WINDOW_HEIGHT"), - std::to_string(paraverConfigWindowHeight_)); - auto replacedWindowSemanticMaxOverview = std::regex_replace( - replacedWindowHeightOverview, std::regex("NESMIK_REPLACE_SEMANTIC_MAX"), - std::to_string(numberOfRegionsRegistered)); - auto overviewReplacedAllTypes = - std::regex_replace(replacedWindowSemanticMaxOverview, - std::regex("NESMIK_REPLACE_LEVELS"), allTypesString); - - // write Overview - outputFile << overviewReplacedAllTypes; - outputFile << std::endl; - - // write separate windows - for (unsigned int level = 0; level <= regionStackData.historicMaxStackSize; - level++) { - std::string windowName = - "neSmiK Instrumentation Level: " + std::to_string(level); - - auto replacedEventType = std::regex_replace( - paraverConfigLevelWindow, std::regex("NESMIK_REPLACE_EVENT_TYPE"), - std::to_string(baseType + level)); - auto replacedWindowHeight = std::regex_replace( - replacedEventType, std::regex("NESMIK_REPLACE_WINDOW_HEIGHT"), - std::to_string(paraverConfigWindowHeight_)); - auto replacedWindowYPosition = std::regex_replace( - replacedWindowHeight, std::regex("NESMIK_REPLACE_WINDOW_Y_POSITION"), - std::to_string( - (paraverConfigWindowHeight_ + paraverConfigWindowHeightPad_) * - (level + 2 /* offset with overview window */))); - auto replacedWindowSemanticMax = std::regex_replace( - replacedWindowYPosition, std::regex("NESMIK_REPLACE_SEMANTIC_MAX"), - std::to_string(numberOfRegionsRegistered)); - auto replacedWindowName = std::regex_replace( - replacedWindowSemanticMax, std::regex("NESMIK_REPLACE_WINDOW_NAME"), - windowName); - - // write Overview - outputFile << replacedWindowName; - outputFile << std::endl; - } - } - - if (didInitialize) { - // Assumption is that if we needed to initialize the lib we also need to - // Finalize it - Extrae_fini(); + std::ofstream out_file; + out_file.open(fileName); + ExtraeParaverConfig paraver_config{ + .stacked_window_name = + std::optional<std::string>("neSmiK Annotation Overview"), + .description = + "neSmiK annotation regions using the Extrae::TypeStack Backend" + + }; + // write config + out_file << extrae_wrapper_->getParaverConfig(paraver_config) << std::endl; } + extrae_wrapper_->Finalize(); } diff --git a/src/backends/extrae/extrae_type_stack.hpp b/src/backends/extrae/extrae_type_stack.hpp index cef9657..dc1277b 100644 --- a/src/backends/extrae/extrae_type_stack.hpp +++ b/src/backends/extrae/extrae_type_stack.hpp @@ -6,15 +6,10 @@ #include <utils/environment_variable.hpp> #include <utils/parallelism_helper.hpp> +#include "extrae_types.hpp" +#include "extrae_wrapper.hpp" #include "strategies.hpp" // #include <mutex> -typedef unsigned long extrae_value; -typedef unsigned long extrae_type; - -struct RegionStackData { - std::stack<std::string> regionNameStack; - std::size_t historicMaxStackSize; -}; struct RegionMapData { std::unordered_map<std::string, extrae_value> regionNameToValue; @@ -23,23 +18,19 @@ struct RegionMapData { class ExtraeTypeStackStrategy : public ProperlyNestedAnnotationStrategy { private: const bool write_config_file_default_{true}; - const unsigned long baseType{81000}; - static const std::string paraverConfigHead; - static const std::string paraverConfigOverviewWindow; - static const std::string paraverConfigLevelWindow; - - inline static const int paraverConfigWindowHeight_ = 115; - inline static const int paraverConfigWindowHeightPad_ = 35; + const 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<bool> write_config_file_ = EnvironmentVariable<bool>( "EXTRAE_WRITE_CONFIG_FILE", "Write corresponding Paraver .cfg file if set to True", false); MPIHelper mpi_helper_; + std::unique_ptr<ExtraeWrapper> extrae_wrapper_; bool didInitialize{false}; - RegionStackData regionStackData; + std::size_t max_stack_size{0}; RegionMapData regionMapData; extrae_value get_value_by_region_name(const std::string &name); diff --git a/src/backends/extrae/extrae_types.hpp b/src/backends/extrae/extrae_types.hpp new file mode 100644 index 0000000..35c5025 --- /dev/null +++ b/src/backends/extrae/extrae_types.hpp @@ -0,0 +1,5 @@ +#ifndef NESMIK_EXTRAE_TYPES_HPP +#define NESMIK_EXTRAE_TYPES_HPP +typedef unsigned long extrae_value; +typedef unsigned long extrae_type; +#endif // NESMIK_EXTRAE_TYPES_HPP diff --git a/src/backends/extrae/extrae_wrapper.cpp b/src/backends/extrae/extrae_wrapper.cpp new file mode 100644 index 0000000..25f664e --- /dev/null +++ b/src/backends/extrae/extrae_wrapper.cpp @@ -0,0 +1,142 @@ +#include "extrae_wrapper.hpp" + +#include <cassert> +#include <cstring> +#include <iostream> +#include <string> +#include <unordered_map> +#include <vector> + +#include "extrae_types.hpp" +#include "paraver_config.hpp" + +extern "C" { +#include <extrae.h> +} +ExtraeWrapper::ExtraeWrapper(extrae_type base_type) : base_type_(base_type) { + auto isInitializedVal = Extrae_is_initialized(); + if (isInitializedVal == 0) { + // Extrae is not initialized yet see + // https://github.com/bsc-performance-tools/extrae/blob/daee11a2f98e301eb146608f51df0c844e1ff381/include/extrae_types.h#L33 + Extrae_init(); + did_init_extrae_ = true; + std::cout << "neSmiK forced to Initialize extrae" << std::endl; + } +} + +extrae_value ExtraeWrapper::getValueByName(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; + } +} + +void ExtraeWrapper::RegisterTypeWithDescription( + const std::string &type_description, extrae_type type) { + type_map_[type_description] = type; +} +void ExtraeWrapper::StartWithTypeAndRegionName(extrae_type type, + const std::string &value_str) { + const auto value = getValueByName(type, value_str); + // write it in type specific map + type_to_value_map_[type][value_str] = value; + Extrae_eventandcounters(static_cast<extrae_type_t>(type), + static_cast<extrae_value_t>(value)); +} + +void ExtraeWrapper::StopWithTypeAndRegionName(extrae_type type, + const std::string &value_str) { + Extrae_eventandcounters(static_cast<extrae_type_t>(type), 0); +} + +void ExtraeWrapper::StopWithTypeNameAndRegionName( + 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); + return StopWithTypeAndRegionName(type_map_[type_description], value_str); +} + +void ExtraeWrapper::StartWithTypeNameAndRegionName( + 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; + } + return StartWithTypeAndRegionName(type_map_[type_description], value_str); +} + +void ExtraeWrapper::Finalize() { + // now 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<extrae_type_t>(type_from_map); + const value_map_t &value_map = type_to_value_map_[type]; + unsigned number_of_regions = value_map.size(); + + char **routine_c_names = new char *[number_of_regions]; + std::vector<extrae_value_t> values; + + values.reserve(number_of_regions); + std::size_t i = 0; + for (const auto &[name, value] : value_map) { + values.push_back(static_cast<extrae_value_t>(value)); + routine_c_names[i] = + new char[name.size() + 1]; // +1 for null terminiation + std::strcpy(routine_c_names[i], name.c_str()); + i++; + } + + Extrae_define_event_type(&type, const_cast<char *>(description.c_str()), + &number_of_regions, values.data(), + routine_c_names); + + // free up the memory, long live std::vector + for (std::size_t n; n < number_of_regions; n++) { + delete[] routine_c_names[n]; + } + delete[] routine_c_names; + } + + if (did_init_extrae_) { + // Assumption is that if we needed to initialize the lib we also need to + // Finalize it + Extrae_fini(); + } +} + +std::string ExtraeWrapper::getParaverConfig(ExtraeParaverConfig config) { + ParaverConfig paraver_config(config.description); + + // create arrays + std::vector<extrae_type> types; + std::vector<std::string> window_names; + std::vector<extrae_value> semantic_maximums; + for (const auto &[name, type] : type_map_) { + types.push_back(type); + window_names.push_back(name); + // now the ugly search for the semantic maximum + extrae_value semantic_maximum{0}; + for (const auto &[value_name, value] : type_to_value_map_[type]) { + semantic_maximum = std::max(value, semantic_maximum); + } + semantic_maximums.push_back(semantic_maximum); + } + + ParaverTimelineWindow window{ + .window_names = window_names, + .types = types, + .semantic_maximums = semantic_maximums, + .stacked_window_name = config.stacked_window_name}; + + paraver_config.addTimeline(window); + + return paraver_config.getString(); +} diff --git a/src/backends/extrae/extrae_wrapper.hpp b/src/backends/extrae/extrae_wrapper.hpp new file mode 100644 index 0000000..125668f --- /dev/null +++ b/src/backends/extrae/extrae_wrapper.hpp @@ -0,0 +1,39 @@ +#include <optional> +#include <string> +#include <unordered_map> + +#include "extrae_types.hpp" + +struct ExtraeParaverConfig { + std::optional<std::string> stacked_window_name; + std::string description; +}; + +using value_map_t = std::unordered_map<std::string, extrae_value>; +class ExtraeWrapper { + const extrae_type base_type_; + + private: + std::unordered_map<std::string, extrae_type> type_map_; + std::unordered_map<extrae_type, value_map_t> type_to_value_map_; + std::unordered_map<std::string, extrae_value> string_to_value_; + bool did_init_extrae_{false}; + + extrae_value getValueByName(extrae_type type, const std::string &name); + + public: + ExtraeWrapper(extrae_type base_type); + void RegisterTypeWithDescription(const std::string &type_description, + extrae_type type); + void StartWithTypeNameAndRegionName(const std::string type_description, + const std::string &value_str); + void StartWithTypeAndRegionName(extrae_type type, + const std::string &value_str); + void StopWithTypeAndRegionName(extrae_type type, + const std::string &value_str); + void StopWithTypeNameAndRegionName(const std::string type_description, + const std::string &value_str); + + std::string getParaverConfig(ExtraeParaverConfig config); + void Finalize(); +}; diff --git a/src/backends/extrae/paraver_config.cpp b/src/backends/extrae/paraver_config.cpp new file mode 100644 index 0000000..a04799e --- /dev/null +++ b/src/backends/extrae/paraver_config.cpp @@ -0,0 +1,134 @@ + +#include "paraver_config.hpp" + +#include <cassert> +#include <numeric> +#include <regex> +#include <string> + +const std::string ParaverConfig::config_head_ = R"( +#ParaverCFG +ConfigFile.Version: 3.4 +ConfigFile.NumWindows: 2 +ConfigFile.BeginDescription +NESMIK_REPLACE_DESCRIPTION +ConfigFile.EndDescription +)"; +const std::string ParaverConfig::time_line_window_template_ = R"( +################################################################################ +< NEW DISPLAYING WINDOW NESMIK_REPLACE_WINDOW_NAME > +################################################################################ +window_name NESMIK_REPLACE_WINDOW_NAME +window_type single +window_position_x 400 +window_position_y NESMIK_REPLACE_WINDOW_Y_POSITION +window_width 600 +window_height NESMIK_REPLACE_WINDOW_HEIGHT +window_comm_lines_enabled false +window_flags_enabled false +window_noncolor_mode true +window_custom_color_enabled false +window_semantic_scale_min_at_zero false +window_logical_filtered true +window_physical_filtered false +window_intracomms_enabled true +window_intercomms_enabled true +window_comm_fromto true +window_comm_tagsize true +window_comm_typeval true +window_maximum_y NESMIK_REPLACE_SEMANTIC_MAX +window_minimum_y 0 +window_compute_y_max false +window_level thread +window_scale_relative 1.000000000000 +window_end_time_relative 1.000000000000 +window_object appl { 1, { All } } +window_begin_time_relative 0.000000000000 +window_open true +window_drawmode draw_maximum +window_drawmode_rows draw_maximum +window_pixel_size 1 +window_labels_to_draw 1 +window_object_axis_position 0 +window_selected_functions { 14, { {cpu, Active Thd}, {appl, Adding}, {task, Adding}, {thread, Last Evt Val}, {node, Adding}, {system, Adding}, {workload, Adding}, {from_obj, All}, {to_obj, All}, {tag_msg, All}, {size_msg, All}, {bw_msg, All}, {evt_type, =}, {evt_value, All} } } +window_compose_functions { 9, { {compose_cpu, As Is}, {compose_appl, As Is}, {compose_task, As Is}, {compose_thread, Stacked Val}, {compose_node, As Is}, {compose_system, As Is}, {compose_workload, As Is}, {topcompose1, As Is}, {topcompose2, As Is} } } +window_filter_module evt_type NESMIK_REPLACE_NUM_EVENTTYPES NESMIK_REPLACE_EVENTTYPES +)"; + +ParaverConfig::ParaverConfig(const std::string &description) { + auto head_with_description = std::regex_replace( + config_head_, std::regex("NESMIK_REPLACE_DESCRIPTION"), description); + + config_ << head_with_description << "\n"; +} + +void ParaverConfig::addTimeline(ParaverTimelineWindow window_config) { + assert(window_config.types.size() == window_config.semantic_maximums.size() && + window_config.types.size() == window_config.window_names.size()); + + // replace window height + auto repalaced_window_height = std::regex_replace( + time_line_window_template_, std::regex("NESMIK_REPLACE_WINDOW_HEIGHT"), + std::to_string(window_height_)); + + if (window_config.stacked_window_name.has_value()) { + // Build a small list of all types + std::string allTypesString = ""; + for (const auto &type : window_config.types) { + allTypesString += std::to_string(type) + " "; + } + + auto replace_window_name = std::regex_replace( + repalaced_window_height, std::regex("NESMIK_REPLACE_WINDOW_NAME"), + window_config.stacked_window_name.value()); + + auto replaced_event_type = std::regex_replace( + replace_window_name, std::regex("NESMIK_REPLACE_EVENTTYPES"), + allTypesString); + + auto replaced_event_num = std::regex_replace( + replaced_event_type, std::regex("NESMIK_REPLACE_NUM_EVENTTYPES"), + std::to_string(window_config.types.size())); + + auto replaced_window_y_pos = std::regex_replace( + replaced_event_num, std::regex("NESMIK_REPLACE_WINDOW_Y_POSITION"), + std::to_string(150)); + + const extrae_type max_value_in_array = + *std::max_element(window_config.semantic_maximums.begin(), + window_config.semantic_maximums.end()); + auto replaced_semantic_max = std::regex_replace( + replaced_window_y_pos, std::regex("NESMIK_REPLACE_SEMANTIC_MAX"), + std::to_string(max_value_in_array)); + + config_ << replaced_semantic_max << "\n"; + } + + std::size_t number_of_types = window_config.types.size(); + // now iterate over the types + for (std::size_t i = 0; i < number_of_types; i++) { + auto replace_window_name = std::regex_replace( + repalaced_window_height, std::regex("NESMIK_REPLACE_WINDOW_NAME"), + window_config.window_names[i]); + + auto replaced_event_type = std::regex_replace( + replace_window_name, std::regex("NESMIK_REPLACE_EVENTTYPES"), + std::to_string(window_config.types[i])); + + auto replaced_event_num = std::regex_replace( + replaced_event_type, std::regex("NESMIK_REPLACE_NUM_EVENTTYPES"), + std::to_string(1)); + + auto replaced_window_y_pos = std::regex_replace( + replaced_event_num, std::regex("NESMIK_REPLACE_WINDOW_Y_POSITION"), + std::to_string((window_height_ + window_height_pad_) * (i + 2))); + + auto replaced_semantic_max = std::regex_replace( + replaced_window_y_pos, std::regex("NESMIK_REPLACE_SEMANTIC_MAX"), + std::to_string(window_config.semantic_maximums[i])); + + config_ << replaced_semantic_max << "\n"; + } +} + +std::string ParaverConfig::getString() { return config_.str(); } diff --git a/src/backends/extrae/paraver_config.hpp b/src/backends/extrae/paraver_config.hpp new file mode 100644 index 0000000..91d609f --- /dev/null +++ b/src/backends/extrae/paraver_config.hpp @@ -0,0 +1,29 @@ + +#include <optional> +#include <sstream> +#include <string> +#include <vector> + +#include "extrae_types.hpp" + +struct ParaverTimelineWindow { + const std::vector<std::string> &window_names; + const std::vector<extrae_type> &types; + const std::vector<extrae_value> semantic_maximums; + std::optional<std::string> stacked_window_name; +}; + +class ParaverConfig { + private: + std::stringstream config_; + static const std::string config_head_; + static const std::string time_line_window_template_; + + const unsigned int window_height_ = 115; + const unsigned int window_height_pad_ = 35; + + public: + ParaverConfig(const std::string &description); + void addTimeline(ParaverTimelineWindow window_config); + std::string getString(); +}; -- GitLab From f859300441621424c87e6c7839c4fe68eff6cc95 Mon Sep 17 00:00:00 2001 From: Valentin Seitz <valentin.seitz@bsc.es> Date: Thu, 1 Aug 2024 17:10:33 +0200 Subject: [PATCH 10/12] Fix small unitited value problem --- src/backends/extrae/extrae_wrapper.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backends/extrae/extrae_wrapper.cpp b/src/backends/extrae/extrae_wrapper.cpp index 25f664e..45fe235 100644 --- a/src/backends/extrae/extrae_wrapper.cpp +++ b/src/backends/extrae/extrae_wrapper.cpp @@ -99,7 +99,7 @@ void ExtraeWrapper::Finalize() { routine_c_names); // free up the memory, long live std::vector - for (std::size_t n; n < number_of_regions; n++) { + for (std::size_t n = 0; n < number_of_regions; n++) { delete[] routine_c_names[n]; } delete[] routine_c_names; -- GitLab From 4126645f8ab4bfefb9e53e90a7c4e8feab2b1df8 Mon Sep 17 00:00:00 2001 From: Valentin Seitz <valentin.seitz@bsc.es> Date: Mon, 5 Aug 2024 12:22:05 +0200 Subject: [PATCH 11/12] - removed some dead code - moved to stack allocation --- src/backends/extrae/extrae_partial_tracer.cpp | 17 ++++++++--------- src/backends/extrae/extrae_partial_tracer.hpp | 7 +++---- src/backends/extrae/extrae_type_stack.cpp | 15 +++++++-------- src/backends/extrae/extrae_type_stack.hpp | 9 +-------- 4 files changed, 19 insertions(+), 29 deletions(-) diff --git a/src/backends/extrae/extrae_partial_tracer.cpp b/src/backends/extrae/extrae_partial_tracer.cpp index 3c262e7..b473159 100644 --- a/src/backends/extrae/extrae_partial_tracer.cpp +++ b/src/backends/extrae/extrae_partial_tracer.cpp @@ -9,20 +9,21 @@ extern "C" { } #include <utils/terminator.hpp> -ExtraePartialTracer::ExtraePartialTracer() : mpi_helper_{} { +ExtraePartialTracer::ExtraePartialTracer() + : mpi_helper_{}, extrae_wrapper_{state_type_} { parallelism_descriptor_ = { .mpi_descriptor_ = MPIDescriptor::Aware, .thread_descriptor_ = ThreadDescriptor::Unsupported}; - extrae_wrapper_ = std::make_unique<ExtraeWrapper>(state_type_); + type_stack_strategy_ = std::make_unique<ExtraeTypeStackStrategy>(); - extrae_wrapper_->RegisterTypeWithDescription(type_description, state_type_); + extrae_wrapper_.RegisterTypeWithDescription(type_description_, state_type_); } void ExtraePartialTracer::shutdown() noexcept { if (debug_output_.getValue().value_or(false) && mpi_helper_.IsRankNumber(0)) { std::cout << "neSmiK Partial Tracer: Shutting down" << std::endl; } - extrae_wrapper_->StopWithTypeAndRegionName(state_type_, "ON"); + extrae_wrapper_.StopWithTypeAndRegionName(state_type_, "ON"); Extrae_shutdown(); is_shutdown_ = true; } @@ -32,7 +33,7 @@ void ExtraePartialTracer::start() noexcept { std::cout << "neSmiK Partial Tracer: Starting up" << std::endl; } Extrae_restart(); - extrae_wrapper_->StartWithTypeAndRegionName(state_type_, "ON"); + extrae_wrapper_.StartWithTypeAndRegionName(state_type_, "ON"); is_shutdown_ = false; } @@ -78,8 +79,6 @@ void ExtraePartialTracer::Init() noexcept { << job.stop_at << "}" << std::endl; } } - - is_initialized_ = true; } void ExtraePartialTracer::RegionStart( @@ -189,9 +188,9 @@ void ExtraePartialTracer::Finalize() noexcept { .stacked_window_name = std::nullopt, .description = "neSmiK Partial Tracer state"}; // write config - out_file << extrae_wrapper_->getParaverConfig(paraver_config) << std::endl; + out_file << extrae_wrapper_.getParaverConfig(paraver_config) << std::endl; } - extrae_wrapper_->Finalize(); + extrae_wrapper_.Finalize(); type_stack_strategy_->Finalize(); } diff --git a/src/backends/extrae/extrae_partial_tracer.hpp b/src/backends/extrae/extrae_partial_tracer.hpp index 22c2037..b4b0a3a 100644 --- a/src/backends/extrae/extrae_partial_tracer.hpp +++ b/src/backends/extrae/extrae_partial_tracer.hpp @@ -46,13 +46,12 @@ class ExtraePartialTracer : public ProperlyNestedAnnotationStrategy { std::unordered_map<std::string, unsigned int> region_counter_stops_; std::vector<StartStopJob> jobs_; bool is_shutdown_{true}; - bool is_initialized_{false}; - std::unique_ptr<ExtraeWrapper> extrae_wrapper_; + ExtraeWrapper extrae_wrapper_; std::unique_ptr<ExtraeTypeStackStrategy> type_stack_strategy_; void shutdown() noexcept; void start() noexcept; - const extrae_type state_type_{9780}; - const std::string type_description = "Extrae::PartialTracer State"; + const extrae_type state_type_{82000}; + const std::string type_description_ = "Extrae::PartialTracer State"; public: ExtraePartialTracer(); diff --git a/src/backends/extrae/extrae_type_stack.cpp b/src/backends/extrae/extrae_type_stack.cpp index 57714a4..43b816f 100644 --- a/src/backends/extrae/extrae_type_stack.cpp +++ b/src/backends/extrae/extrae_type_stack.cpp @@ -14,19 +14,18 @@ extern "C" { #include <extrae.h> } -ExtraeTypeStackStrategy::ExtraeTypeStackStrategy() : mpi_helper_{} { +ExtraeTypeStackStrategy::ExtraeTypeStackStrategy() + : mpi_helper_{}, extrae_wrapper_{base_type_} { parallelism_descriptor_ = { .mpi_descriptor_ = MPIDescriptor::Aware, .thread_descriptor_ = ThreadDescriptor::Unsupported}; - - extrae_wrapper_ = std::make_unique<ExtraeWrapper>(base_type_); } 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); - extrae_wrapper_->RegisterTypeWithDescription(description, base_type_ + i); + extrae_wrapper_.RegisterTypeWithDescription(description, base_type_ + i); } } @@ -37,7 +36,7 @@ void ExtraeTypeStackStrategy::RegionStart( const auto level = region.stack_.size(); max_stack_size = std::max(level, max_stack_size); std::string description = "Level: " + std::to_string(level); - extrae_wrapper_->StartWithTypeNameAndRegionName(description, regionName); + extrae_wrapper_.StartWithTypeNameAndRegionName(description, regionName); } void ExtraeTypeStackStrategy::RegionStopLast( const ProperlyNestedRegionInformation ®ion) noexcept { @@ -45,7 +44,7 @@ void ExtraeTypeStackStrategy::RegionStopLast( const auto level = region.stack_.size(); max_stack_size = std::max(level, max_stack_size); std::string description = "Level: " + std::to_string(level); - extrae_wrapper_->StopWithTypeNameAndRegionName(description, regionName); + extrae_wrapper_.StopWithTypeNameAndRegionName(description, regionName); } void ExtraeTypeStackStrategy::Finalize() noexcept { @@ -62,7 +61,7 @@ void ExtraeTypeStackStrategy::Finalize() noexcept { }; // write config - out_file << extrae_wrapper_->getParaverConfig(paraver_config) << std::endl; + out_file << extrae_wrapper_.getParaverConfig(paraver_config) << std::endl; } - extrae_wrapper_->Finalize(); + extrae_wrapper_.Finalize(); } diff --git a/src/backends/extrae/extrae_type_stack.hpp b/src/backends/extrae/extrae_type_stack.hpp index dc1277b..3cd2ee8 100644 --- a/src/backends/extrae/extrae_type_stack.hpp +++ b/src/backends/extrae/extrae_type_stack.hpp @@ -9,11 +9,6 @@ #include "extrae_types.hpp" #include "extrae_wrapper.hpp" #include "strategies.hpp" -// #include <mutex> - -struct RegionMapData { - std::unordered_map<std::string, extrae_value> regionNameToValue; -}; class ExtraeTypeStackStrategy : public ProperlyNestedAnnotationStrategy { private: @@ -26,13 +21,11 @@ class ExtraeTypeStackStrategy : public ProperlyNestedAnnotationStrategy { "Write corresponding Paraver .cfg file if set to True", false); MPIHelper mpi_helper_; - std::unique_ptr<ExtraeWrapper> extrae_wrapper_; + ExtraeWrapper extrae_wrapper_; bool didInitialize{false}; std::size_t max_stack_size{0}; - RegionMapData regionMapData; - extrae_value get_value_by_region_name(const std::string &name); public: ExtraeTypeStackStrategy(); -- GitLab From c103b6608a1b8f4d745c2410cf8f04297f417914 Mon Sep 17 00:00:00 2001 From: Valentin Seitz <valentin.seitz@bsc.es> Date: Mon, 5 Aug 2024 12:24:48 +0200 Subject: [PATCH 12/12] remove verrbosity on other ranks for partial tracer --- src/backends/extrae/extrae_partial_tracer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backends/extrae/extrae_partial_tracer.cpp b/src/backends/extrae/extrae_partial_tracer.cpp index b473159..d2efb16 100644 --- a/src/backends/extrae/extrae_partial_tracer.cpp +++ b/src/backends/extrae/extrae_partial_tracer.cpp @@ -104,7 +104,7 @@ void ExtraePartialTracer::RegionStart( Terminator::exit(); } if (!matching_jobs.empty()) { - if (!is_shutdown_) { + if (!is_shutdown_ && mpi_helper_.IsRankNumber(0)) { std::cout << "neSmiK Extrae::PartialTracer: The regions you selected are " "overlapping. The tracer is already running for " @@ -148,7 +148,7 @@ void ExtraePartialTracer::RegionStopLast( } } - if (matching_jobs.size() > 1) { + if (matching_jobs.size() > 1 && mpi_helper_.IsRankNumber(0)) { std::cout << "neSmiK Extrae::PartialTracer: Found multiple matching jobs, please " "dont duplicate region names with the same stop iteration" @@ -157,7 +157,7 @@ void ExtraePartialTracer::RegionStopLast( } if (!matching_jobs.empty()) { - if (is_shutdown_) { + if (is_shutdown_ && mpi_helper_.IsRankNumber(0)) { std::cout << "neSmiK Extrae::PartialTracer: The regions you selected are " "overlapping. The tracer is already stopped for " -- GitLab