diff --git a/src/backends/CMakeLists.txt b/src/backends/CMakeLists.txt index c18ed4ecc58c0a198b4fa28382143b9e6ced2b21..43fa57b691a2869b3b8a19bfbdace81536676c7f 100644 --- a/src/backends/CMakeLists.txt +++ b/src/backends/CMakeLists.txt @@ -6,4 +6,4 @@ endif() if(ENABLE_EXTRAE) add_subdirectory(extrae) -endif() \ No newline at end of file +endif() diff --git a/src/backends/dlb/CMakeLists.txt b/src/backends/dlb/CMakeLists.txt index 10aa5684cf0fc76d5417d1e48794fa797f94daa8..3a432c46e8aa7f5fd8c72cbb1af8c0564424d8dd 100644 --- a/src/backends/dlb/CMakeLists.txt +++ b/src/backends/dlb/CMakeLists.txt @@ -1,9 +1,10 @@ find_package(DLB REQUIRED) -target_sources(nesmik PRIVATE dlb.cpp) if(DLB_FOUND) target_include_directories(nesmik PRIVATE ${DLB_INCLUDE_DIRS}) target_link_libraries(nesmik PUBLIC ${DLB_LIBRARIES}) target_compile_definitions(nesmik PRIVATE "ENABLE_DLB") +add_subdirectory(dlb) +add_subdirectory(dlb_talp_tree) endif() diff --git a/src/backends/dlb/dlb/CMakeLists.txt b/src/backends/dlb/dlb/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..9bb7520eaa4a3abb556dfa2bc665b9060e718b51 --- /dev/null +++ b/src/backends/dlb/dlb/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(nesmik PRIVATE dlb.cpp) diff --git a/src/backends/dlb/dlb.cpp b/src/backends/dlb/dlb/dlb.cpp similarity index 99% rename from src/backends/dlb/dlb.cpp rename to src/backends/dlb/dlb/dlb.cpp index ac577e75bb9aa126a07699403cc45fa3b9cf45cd..3c8b5d93da978ec158a6804d2337a917930abf4b 100644 --- a/src/backends/dlb/dlb.cpp +++ b/src/backends/dlb/dlb/dlb.cpp @@ -18,7 +18,6 @@ void DLBTalpStrategy::region_stop( } void DLBTalpStrategy::init() noexcept { - DLB_Init(0, NULL, "--talp"); std::cout << "nesmik::" << name << " init()" << std::endl; } diff --git a/src/backends/dlb/dlb.hpp b/src/backends/dlb/dlb/dlb.hpp similarity index 86% rename from src/backends/dlb/dlb.hpp rename to src/backends/dlb/dlb/dlb.hpp index 5c843e40bf1157beab0a51b3be33c4cf684ba0d0..ebdeb6c14e68cb3d272f673f979ed0cab206bc4d 100644 --- a/src/backends/dlb/dlb.hpp +++ b/src/backends/dlb/dlb/dlb.hpp @@ -1,3 +1,6 @@ +#ifndef SIT_DLB_H +#define SIT_DLB_H + #include class DLBTalpStrategy : public PNProfilingStrategy { @@ -9,3 +12,4 @@ public: virtual void init() noexcept; virtual void finalize() noexcept; }; +#endif // SIT_DLB_H diff --git a/src/backends/dlb/dlb_talp_tree/CMakeLists.txt b/src/backends/dlb/dlb_talp_tree/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..160cc50b7d255384ca8ffc20e3c9efb884ee897b --- /dev/null +++ b/src/backends/dlb/dlb_talp_tree/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(nesmik PRIVATE dlb_talp_tree.cpp) diff --git a/src/backends/dlb/dlb_talp_tree/dlb_talp_tree.cpp b/src/backends/dlb/dlb_talp_tree/dlb_talp_tree.cpp new file mode 100644 index 0000000000000000000000000000000000000000..292cd182753065782539d1541cbc3990fc2b13cf --- /dev/null +++ b/src/backends/dlb/dlb_talp_tree/dlb_talp_tree.cpp @@ -0,0 +1,207 @@ +#include "dlb_talp_tree.hpp" +#include "dlb.h" +#include "dlb_talp.h" +#include +#include +#include +#include +#include +#include + +void DLBTalpTreeStrategy::region_start( + const PNRegionInformation ®ion) noexcept { + + // Construct the opening region hash by joining the name of the region with + // the current region (i.e. the parent) hash. + std::string region_name = std::string(region.name) + std::to_string((unsigned int) this->current_region); + if (region.name.compare(this->top_region) == 0) { + region_name = this->top_region; + } + + std::size_t region_hash = std::hash{}(region_name); + + if (this->regions.count(region_hash) == 0) { + // Add the new region as a child to the current region + this->regions[this->current_region].childs.push_back(region_hash); + + // Add the new region in the map + this->regions[region_hash] = { + /* .name */ std::string(region.name), + /* .tree_lines */ "", + /* .parent */ this->current_region, + /* .childs */ std::vector() + }; + } + + this->current_region = region_hash; + + std::string name = std::to_string((unsigned int) region_hash); + this->talp_profiling_strategy.region_start({name}); +} + +void DLBTalpTreeStrategy::region_stop( + const PNRegionInformation ®ion) noexcept { + + auto current_region = this->regions[this->current_region]; + + if (region.name.compare(current_region.name) != 0) { + std::stringstream error; + + error << "neSmiK:: Closing " << region.name << " would make "; + error << current_region.name << "not nested." << std::endl; + + error << "neSmiK:: Closing " << current_region.name << " instead." << std::endl; + + std::cerr << error.str(); + } + + std::string name = std::to_string((unsigned int)this->current_region); + if (current_region.name.compare(this->top_region) == 0) { + name = this->top_region; + } + + this->current_region = current_region.parent; + + this->talp_profiling_strategy.region_stop({name}); +} + +void DLBTalpTreeStrategy::init() noexcept { + + this->current_region = std::hash{}(this->top_region); + this->regions[this->current_region] = { + /* .name */ this->top_region, + /* .tree_lines */ "", + /* .parent */ 0, + /* .childs */ {}, + }; + + this->talp_profiling_strategy.init(); +} + +void DLBTalpTreeStrategy::finalize() noexcept { + + this->talp_profiling_strategy.region_stop({.name = this->top_region}); + + std::size_t max_width = 0; + + // First pass to format the names with the appropiate tree lines and to determine paddings. + { + std::size_t top_region = std::hash{}(this->top_region); + + std::stack regions_stack; + regions_stack.push(top_region); + + std::stack regions_level; + regions_level.push(0); + + std::stack regions_tree_lines; + regions_tree_lines.push(""); + + while (!regions_stack.empty()) { + auto ¤t_region = this->regions[regions_stack.top()]; + //TalpRegionNode ¤t_region = this->regions[regions_stack.top()]; + int level = regions_level.top(); + std::string tree_lines = regions_tree_lines.top(); + + regions_stack.pop(); + regions_level.pop(); + regions_tree_lines.pop(); + + // I am the last child either if the stack is empty or if the level of the following element + // in the stack is lower than mine. + bool last_child = regions_level.empty() || regions_level.top() < level; + + std::string next_tree_lines = " │ "; // By default I get the continuation line. + if (level == 0) next_tree_lines = ""; // If I am the root region I don't need line. + else if (last_child) next_tree_lines = " "; // If I am the last child I add space. + + for (auto region : current_region.childs) { + regions_stack.push(region); + regions_level.push(level+1); + regions_tree_lines.push(tree_lines + next_tree_lines); + } + + if (level == 0) tree_lines += ""; // If I am the root I don't have lines + else if (last_child) tree_lines += " └─ "; // If I am the last child I close the line + else tree_lines += " ├─ "; // Otherwise i continue the line. + + current_region.tree_lines = tree_lines; + max_width = std::max(max_width, current_region.name.length() + + current_region.tree_lines.length()); + } + } + + std::size_t top_region = std::hash{}(this->top_region); + + std::stack regions_stack; + regions_stack.push(top_region); + + std::stringstream region_stream_stdout; + std::stringstream region_stream_csv; + + while (!regions_stack.empty()) { + std::size_t current_region_hash = regions_stack.top(); + auto current_region = this->regions[current_region_hash]; + regions_stack.pop(); + + for (auto region : current_region.childs) { + regions_stack.push(region); + } + + std::string name = std::to_string((unsigned int)current_region_hash); + if (current_region.name.compare(this->top_region) == 0) { + name = this->top_region; + } + + auto handle = DLB_MonitoringRegionRegister(name.c_str()); + + dlb_pop_metrics_t pop_metrics; + int error = DLB_TALP_CollectPOPMetrics(handle, &pop_metrics); + + if (error != DLB_SUCCESS) { + + } + + std::string name_with_tree_lines = current_region.tree_lines + current_region.name; + + region_stream_stdout << std::setw(max_width+3) << std::left << name_with_tree_lines; + region_stream_stdout << std::fixed << std::setprecision(2); + region_stream_stdout << std::setw(15) << std::right << 100 * pop_metrics.elapsed_time/1000000000 << "s"; + region_stream_stdout << std::setw(8) << std::right << 100 * pop_metrics.parallel_efficiency; + region_stream_stdout << std::setw(8) << std::right << 100 * pop_metrics.mpi_parallel_efficiency; + region_stream_stdout << std::setw(8) << std::right << 100 * pop_metrics.mpi_communication_efficiency; + region_stream_stdout << std::setw(8) << std::right << 100 * pop_metrics.mpi_load_balance; + region_stream_stdout << std::setw(8) << std::right << 100 * pop_metrics.mpi_load_balance_in; + region_stream_stdout << std::setw(8) << std::right << 100 * pop_metrics.mpi_load_balance_out; + + region_stream_stdout << std::setw(8) << std::right << 100 * pop_metrics.omp_parallel_efficiency; + region_stream_stdout << std::setw(8) << std::right << 100 * pop_metrics.omp_load_balance; + region_stream_stdout << std::setw(8) << std::right << 100 * pop_metrics.omp_scheduling_efficiency; + region_stream_stdout << std::setw(8) << std::right << 100 * pop_metrics.omp_serialization_efficiency; + region_stream_stdout << std::endl; + + region_stream_csv << name_with_tree_lines; + region_stream_csv << std::fixed << std::setprecision(4); + region_stream_csv << "," << pop_metrics.elapsed_time/1000000000 << "s"; + region_stream_csv << "," << 100 * pop_metrics.parallel_efficiency; + region_stream_csv << "," << 100 * pop_metrics.mpi_parallel_efficiency; + region_stream_csv << "," << 100 * pop_metrics.mpi_communication_efficiency; + region_stream_csv << "," << 100 * pop_metrics.mpi_load_balance; + region_stream_csv << "," << 100 * pop_metrics.mpi_load_balance_in; + region_stream_csv << "," << 100 * pop_metrics.mpi_load_balance_out; + + region_stream_csv << "," << 100 * pop_metrics.omp_parallel_efficiency; + region_stream_csv << "," << 100 * pop_metrics.omp_load_balance; + region_stream_csv << "," << 100 * pop_metrics.omp_scheduling_efficiency; + region_stream_csv << "," << 100 * pop_metrics.omp_serialization_efficiency; + region_stream_csv << std::endl; + } + + std::cout << region_stream_stdout.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 new file mode 100644 index 0000000000000000000000000000000000000000..d2a58ca5eb6c022b0a627d493f11a8a81a68a0f8 --- /dev/null +++ b/src/backends/dlb/dlb_talp_tree/dlb_talp_tree.hpp @@ -0,0 +1,36 @@ +#ifndef SIT_DLB_TALP_TREE_H +#define SIT_DLB_TALP_TREE_H + +#include "../dlb/dlb.hpp" +#include "strategies.hpp" +#include +#include +#include +#include + +struct TalpRegionNode { + std::string name; + std::string tree_lines; + std::size_t parent; + std::vector childs; +}; + +class DLBTalpTreeStrategy : public PNProfilingStrategy { + +private: + DLBTalpStrategy talp_profiling_strategy; + + inline static const std::string top_region = "Application"; + std::size_t current_region; + std::map regions; + + +public: + inline static const std::string_view name = "TALP-Tree"; + void region_start(const PNRegionInformation ®ion) noexcept override; + void region_stop(const PNRegionInformation ®ion) noexcept override; + virtual void init() noexcept; + virtual void finalize() noexcept; +}; + +#endif // DLB_TALP_TREE_H diff --git a/src/delegator.cpp b/src/delegator.cpp index 1461ed4177c7b7a492cff65085c271b857bdf412..2a651b213c7115a5a5161bef0211660b1344bec4 100644 --- a/src/delegator.cpp +++ b/src/delegator.cpp @@ -9,7 +9,8 @@ #include "backends/default/default.hpp" #ifdef ENABLE_DLB -#include "backends/dlb/dlb.hpp" +#include "backends/dlb/dlb/dlb.hpp" +#include "backends/dlb/dlb_talp_tree/dlb_talp_tree.hpp" #endif #ifdef ENABLE_EXTRAE @@ -31,6 +32,9 @@ void Delegator::init(std::string_view backend) { else if (backend.compare(DLBTalpStrategy::name) == 0) { pn_profiling_strategy = std::make_unique(); } + else if (backend.compare(DLBTalpTreeStrategy::name) == 0) { + pn_profiling_strategy = std::make_unique(); + } #endif else { exit(1); // fail non gracefully for now diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d3d642dd0fca15e4fe4ea69e88af43826b7ea2a5..c4c5e24dd49731099c36cc90f681aec59ec7ddc0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,6 +16,13 @@ target_include_directories(TestCppDLB add_test(NAME TestCppDLB COMMAND TestCppDLB) +add_executable(TestCppTalpTree cpp/TestCppTalpTree.cpp) +target_link_libraries(TestCppTalpTree nesmik::nesmik) +target_include_directories(TestCppTalpTree + PRIVATE ${NESMIK_PUBLIC_HEADERS}) + +add_test(NAME TestCppTalpTree + COMMAND TestCppTalpTree) endif() @@ -57,4 +64,4 @@ if(BUILD_C_FORTRAN) add_test(NAME TestFortranLink COMMAND TestFortranLink) -endif() \ No newline at end of file +endif() diff --git a/tests/cpp/TestCppDLB.cpp b/tests/cpp/TestCppDLB.cpp index ffb3197e1969d13b09883594af79a6ebf03bccda..a91b6d78966d9923884054e7a593ed695b109472 100644 --- a/tests/cpp/TestCppDLB.cpp +++ b/tests/cpp/TestCppDLB.cpp @@ -1,8 +1,8 @@ #include "nesmik/nesmik.hpp" int main() { - nesmik::init("DLB"); + nesmik::init("TALP"); nesmik::region_start("Default"); nesmik::region_stop("Default"); nesmik::finalize(); -} \ No newline at end of file +} diff --git a/tests/cpp/TestCppTalpTree.cpp b/tests/cpp/TestCppTalpTree.cpp new file mode 100644 index 0000000000000000000000000000000000000000..35610bc7f0eccc9d1b596da7e66064ab615e8a05 --- /dev/null +++ b/tests/cpp/TestCppTalpTree.cpp @@ -0,0 +1,18 @@ +#include "nesmik/nesmik.hpp" + +int main() { + nesmik::init("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(); +}