From 91c34f8ca30c43968bb48f4fad94996917b1e0c0 Mon Sep 17 00:00:00 2001 From: Gaurav Harsha Date: Wed, 5 Nov 2025 03:37:53 -0500 Subject: [PATCH 1/8] add support for non-accumulate mode in timing.h --- src/green/utils/timing.h | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/green/utils/timing.h b/src/green/utils/timing.h index e7cc730..c2c8584 100644 --- a/src/green/utils/timing.h +++ b/src/green/utils/timing.h @@ -37,11 +37,12 @@ namespace green::utils { struct event_t { - event_t() : start(0), duration(0), active(false) {} + event_t() : start(0), duration(0), active(false), accumulate(true) {} event_t(double start_, double duration_) : start(start_), duration(duration_), active(false){}; double start; double duration; bool active; + bool accumulate; event_t* parent = nullptr; std::unordered_map> children; }; @@ -141,8 +142,9 @@ namespace green::utils { * `_current_event` will be set to a newly started event. * * @param name - event name to start time measurement + * @param accumulate - whether to accumulate time for this event */ - void start(const std::string& name) { + void start(const std::string& name, bool accumulate=false) { #ifndef NDEBUG if (_root_events.find(name) != _root_events.end() && _root_events[name]->active) { throw wrong_event_state("Event is already active"); @@ -153,10 +155,12 @@ namespace green::utils { if (_current_event->children[name] == nullptr) _current_event->children[name] = std::make_unique(0, 0); _current_event->children[name]->parent = _current_event; _current_event = _current_event->children[name].get(); + _current_event->accumulate = accumulate; } else { // start root event if (_root_events[name] == nullptr) _root_events[name] = std::make_unique(0, 0); _current_event = _root_events[name].get(); + _current_event->accumulate = accumulate; } _current_event->active = true; _current_event->start = time(); @@ -173,12 +177,25 @@ namespace green::utils { return; } double time1 = time(); - _current_event->duration += time1 - _current_event->start; + if (_current_event->accumulate) { + _current_event->duration += time1 - _current_event->start; + } else { + _current_event->duration = time1 - _current_event->start; + } _current_event->active = false; _current_event = _current_event->parent; } + + void reset() { + if (!_current_event) return; + for (auto& kv : _current_event->children) { + kv.second->duration = 0.0; + kv.second->active = false; + } + } + /** * Print statistics for all observed events */ From 8a79d9954671d59f8ccf97bd46b14ea66be1bfba Mon Sep 17 00:00:00 2001 From: Gaurav Harsha Date: Wed, 5 Nov 2025 19:56:08 -0500 Subject: [PATCH 2/8] add documentation --- src/green/utils/timing.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/green/utils/timing.h b/src/green/utils/timing.h index c2c8584..b6954d3 100644 --- a/src/green/utils/timing.h +++ b/src/green/utils/timing.h @@ -42,7 +42,7 @@ namespace green::utils { double start; double duration; bool active; - bool accumulate; + bool accumulate; // accumulate time for subsequent measurements event_t* parent = nullptr; std::unordered_map> children; }; @@ -130,6 +130,20 @@ namespace green::utils { timing(timing const&) = delete; void operator=(timing const&) = delete; + /** + * @brief Register a root-level timing event by name without starting it. + * + * Creates the event entry in the internal root events map if it does not exist yet. + * This call is idempotent and has no effect if the event is already present. + * + * Notes: + * - This does not start timing. Use start(name) to begin measuring and end() to stop. + * - Added events appear in print()/print(MPI_Comm) output even if never started (duration = 0). + * - The event is registered at the root level; child events are created implicitly when + * start(name) is invoked while another event is active. + * + * @param name Unique identifier of the event to pre-register at the root level. + */ void add(const std::string& name) { if (_root_events.find(name) == _root_events.end()) { _root_events[name] = std::make_unique(0.0, 0.0); @@ -188,6 +202,10 @@ namespace green::utils { } + /** + * @brief reset the `duration` attribute of all child events of the current event + * + */ void reset() { if (!_current_event) return; for (auto& kv : _current_event->children) { From f5ebdcc1470537236aae9be4060cf5b2049a4bc0 Mon Sep 17 00:00:00 2001 From: Gaurav Harsha Date: Wed, 5 Nov 2025 23:29:02 -0500 Subject: [PATCH 3/8] add tests for new functionalities --- test/utils_test.cpp | 52 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/test/utils_test.cpp b/test/utils_test.cpp index c0f24c6..c75079b 100644 --- a/test/utils_test.cpp +++ b/test/utils_test.cpp @@ -93,4 +93,56 @@ TEST_CASE("Timing") { REQUIRE(statistic.event("UNKNOWN2").parent == &statistic.event("TEST")); statistic.end(); } + + SECTION("Test Accumulate") { + // Test case when Accumulate is ON + green::utils::timing statistic; + double s1 = MPI_Wtime(); + statistic.start("ACCUMULATE ON", true); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + statistic.end(); + double e1 = MPI_Wtime(); + double duration1 = statistic.event("ACCUMULATE ON").duration; + REQUIRE(std::abs(duration1 - (e1 - s1)) < 1e-2); + + double s2 = MPI_Wtime(); + statistic.start("ACCUMULATE ON", true); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + statistic.end(); + double e2 = MPI_Wtime(); + double duration2 = statistic.event("ACCUMULATE ON").duration; + REQUIRE(std::abs(duration2 - (e2 + e1 - s1 - s2)) < 1e-2); + + // Test case when Accumulate is OFF + statistic.start("ACCUMULATE OFF", false); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + statistic.end(); + double duration3 = statistic.event("ACCUMULATE OFF").duration; + + statistic.start("ACCUMULATE OFF", false); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + statistic.end(); + double duration4 = statistic.event("ACCUMULATE OFF").duration; + REQUIRE(std::abs(duration4 - duration3) < 1e-2); + } + + SECTION("Test Reset") { + green::utils::timing statistic; + statistic.start("ROOT"); + statistic.start("CHILD1"); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + statistic.end(); + statistic.start("CHILD2"); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + statistic.end(); + statistic.reset(); + statistic.end(); + + double duration_root = statistic.event("ROOT").duration; + double duration_child1 = statistic.event("ROOT").children["CHILD1"]->duration; + double duration_child2 = statistic.event("ROOT").children["CHILD2"]->duration; + + REQUIRE(duration_child1 == 0.0); + REQUIRE(duration_child2 == 0.0); + } } From 4a816f00cb90eb31b7188a117005907544958d13 Mon Sep 17 00:00:00 2001 From: Gaurav Harsha Date: Thu, 6 Nov 2025 00:28:36 -0500 Subject: [PATCH 4/8] set default accumulate=true --- src/green/utils/timing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/green/utils/timing.h b/src/green/utils/timing.h index b6954d3..d9f55b1 100644 --- a/src/green/utils/timing.h +++ b/src/green/utils/timing.h @@ -158,7 +158,7 @@ namespace green::utils { * @param name - event name to start time measurement * @param accumulate - whether to accumulate time for this event */ - void start(const std::string& name, bool accumulate=false) { + void start(const std::string& name, bool accumulate=true) { #ifndef NDEBUG if (_root_events.find(name) != _root_events.end() && _root_events[name]->active) { throw wrong_event_state("Event is already active"); From 701279b043f1a81e2dd3fa35e94841a9c1f4038f Mon Sep 17 00:00:00 2001 From: Gaurav Harsha Date: Thu, 6 Nov 2025 00:30:48 -0500 Subject: [PATCH 5/8] modify constructor for event_t --- src/green/utils/timing.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/green/utils/timing.h b/src/green/utils/timing.h index d9f55b1..b5b7449 100644 --- a/src/green/utils/timing.h +++ b/src/green/utils/timing.h @@ -38,7 +38,7 @@ namespace green::utils { struct event_t { event_t() : start(0), duration(0), active(false), accumulate(true) {} - event_t(double start_, double duration_) : start(start_), duration(duration_), active(false){}; + event_t(double start_, double duration_, bool accumulate_) : start(start_), duration(duration_), active(false), accumulate(accumulate_){}; double start; double duration; bool active; From 7a1c3985985ad0301d693ba1b780621ee504735f Mon Sep 17 00:00:00 2001 From: Gaurav Harsha Date: Thu, 6 Nov 2025 00:31:25 -0500 Subject: [PATCH 6/8] remove trailing white space --- test/utils_test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/utils_test.cpp b/test/utils_test.cpp index c75079b..6400f85 100644 --- a/test/utils_test.cpp +++ b/test/utils_test.cpp @@ -144,5 +144,5 @@ TEST_CASE("Timing") { REQUIRE(duration_child1 == 0.0); REQUIRE(duration_child2 == 0.0); - } + } } From 2fc9bb9805850829daedbf561237fad33fa858a1 Mon Sep 17 00:00:00 2001 From: Gaurav Harsha Date: Thu, 6 Nov 2025 00:36:20 -0500 Subject: [PATCH 7/8] add constructor for default behavior of accumulate --- src/green/utils/timing.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/green/utils/timing.h b/src/green/utils/timing.h index b5b7449..5231006 100644 --- a/src/green/utils/timing.h +++ b/src/green/utils/timing.h @@ -38,6 +38,7 @@ namespace green::utils { struct event_t { event_t() : start(0), duration(0), active(false), accumulate(true) {} + event_t(double start_, double duration_) : start(start_), duration(duration_), active(false), accumulate(true){}; event_t(double start_, double duration_, bool accumulate_) : start(start_), duration(duration_), active(false), accumulate(accumulate_){}; double start; double duration; From 2896ba50100904b6c2ef0c1ce0a22474f14f6269 Mon Sep 17 00:00:00 2001 From: Gaurav Harsha Date: Thu, 6 Nov 2025 00:38:52 -0500 Subject: [PATCH 8/8] update docs and expression for better readability --- src/green/utils/timing.h | 3 ++- test/utils_test.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/green/utils/timing.h b/src/green/utils/timing.h index 5231006..b5e5a5a 100644 --- a/src/green/utils/timing.h +++ b/src/green/utils/timing.h @@ -205,7 +205,8 @@ namespace green::utils { /** * @brief reset the `duration` attribute of all child events of the current event - * + * If there is no current event (i.e., at the root level when `_current_event` is nullptr), + * this method returns silently and does nothing. */ void reset() { if (!_current_event) return; diff --git a/test/utils_test.cpp b/test/utils_test.cpp index 6400f85..278a573 100644 --- a/test/utils_test.cpp +++ b/test/utils_test.cpp @@ -111,7 +111,7 @@ TEST_CASE("Timing") { statistic.end(); double e2 = MPI_Wtime(); double duration2 = statistic.event("ACCUMULATE ON").duration; - REQUIRE(std::abs(duration2 - (e2 + e1 - s1 - s2)) < 1e-2); + REQUIRE(std::abs(duration2 - ((e2 - s2) + (e1 - s1))) < 1e-2); // Test case when Accumulate is OFF statistic.start("ACCUMULATE OFF", false);