-
Notifications
You must be signed in to change notification settings - Fork 32
[Base] some cleaning in timers #1811
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
75cbb05
a76aba4
d5c2a2e
1be50b0
07a4a60
ad053c9
4e252c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,87 @@ | ||||||||||||||
| // -------------------------------------------------------// | ||||||||||||||
| // | ||||||||||||||
| // SHAMROCK code for hydrodynamics | ||||||||||||||
| // Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me> | ||||||||||||||
| // SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1 | ||||||||||||||
| // Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information | ||||||||||||||
| // | ||||||||||||||
| // -------------------------------------------------------// | ||||||||||||||
|
|
||||||||||||||
| #pragma once | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * @file Timer.hpp | ||||||||||||||
| * @author Timothée David--Cléris (tim.shamrock@proton.me) | ||||||||||||||
| * @brief High-resolution timer with plf_nanotimer (non-macOS) or std::chrono (macOS) backend | ||||||||||||||
| * | ||||||||||||||
| */ | ||||||||||||||
|
|
||||||||||||||
| #include "shambase/aliases_float.hpp" | ||||||||||||||
| #include "shambase/format_time.hpp" | ||||||||||||||
|
|
||||||||||||||
| #ifndef __MACH__ | ||||||||||||||
| #define USE_PLF_TIMER | ||||||||||||||
| #endif | ||||||||||||||
|
|
||||||||||||||
| #if defined(USE_PLF_TIMER) | ||||||||||||||
| #include <plf_nanotimer.h> | ||||||||||||||
| #else | ||||||||||||||
| #include <chrono> | ||||||||||||||
| #endif | ||||||||||||||
|
|
||||||||||||||
| namespace shambase { | ||||||||||||||
| /** | ||||||||||||||
| * @brief Class Timer measures the time elapsed since the timer was started. | ||||||||||||||
| */ | ||||||||||||||
| class Timer { | ||||||||||||||
| public: | ||||||||||||||
| #if defined(USE_PLF_TIMER) | ||||||||||||||
| plf::nanotimer timer; ///< Internal timer | ||||||||||||||
| #else | ||||||||||||||
| std::chrono::steady_clock::time_point t_start; ///< Internal timer | ||||||||||||||
| #endif | ||||||||||||||
| f64 nanosec; ///< Time in nanoseconds | ||||||||||||||
|
|
||||||||||||||
| /// Constructor, init nanosec to 0 | ||||||||||||||
| Timer() : nanosec(0.0) {} | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When using the
Suggested change
|
||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * @brief Starts the timer. | ||||||||||||||
| */ | ||||||||||||||
| inline void start() { | ||||||||||||||
| #if defined(USE_PLF_TIMER) | ||||||||||||||
| timer.start(); | ||||||||||||||
| #else | ||||||||||||||
| t_start = std::chrono::steady_clock::now(); | ||||||||||||||
| #endif | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * @brief Stops the timer and stores the elapsed time in nanoseconds. | ||||||||||||||
| * | ||||||||||||||
| * If the timer has already been stopped, calling this again updates `nanosec` to | ||||||||||||||
| * the new delta since `start()`. | ||||||||||||||
| */ | ||||||||||||||
| inline void stop() { | ||||||||||||||
| #if defined(USE_PLF_TIMER) | ||||||||||||||
| nanosec = f64(timer.get_elapsed_ns()); | ||||||||||||||
| #else | ||||||||||||||
| auto t_end = std::chrono::steady_clock::now(); | ||||||||||||||
| nanosec = f64( | ||||||||||||||
| std::chrono::duration_cast<std::chrono::nanoseconds>(t_end - t_start).count()); | ||||||||||||||
| #endif | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * @brief Converts the stored nanosecond time to a string representation. | ||||||||||||||
| * @return std::string A string representation of the elapsed time. | ||||||||||||||
| */ | ||||||||||||||
| inline std::string get_time_str() const { return nanosec_to_time_str(nanosec); } | ||||||||||||||
|
|
||||||||||||||
| /** | ||||||||||||||
| * @brief Converts the stored nanosecond time to a floating point representation in seconds. | ||||||||||||||
| * @return f64 The elapsed time in seconds. | ||||||||||||||
| */ | ||||||||||||||
| [[nodiscard]] inline f64 elapsed_sec() const { return nanosec * 1e-9; } | ||||||||||||||
| }; | ||||||||||||||
| } // namespace shambase | ||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| // -------------------------------------------------------// | ||
| // | ||
| // SHAMROCK code for hydrodynamics | ||
| // Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me> | ||
| // SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1 | ||
| // Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information | ||
| // | ||
| // -------------------------------------------------------// | ||
|
|
||
| #pragma once | ||
|
|
||
| /** | ||
| * @file format_time.hpp | ||
| * @author Timothée David--Cléris (tim.shamrock@proton.me) | ||
| * @brief Human-readable nanosecond duration formatting | ||
| * | ||
| */ | ||
|
|
||
| #include "shambase/string.hpp" | ||
|
|
||
| namespace shambase { | ||
|
|
||
| /** | ||
| * @brief Convert nanoseconds to a human-readable string representation. | ||
| * | ||
| * @param nanosec The duration in nanoseconds. | ||
| * @return std::string The duration in a human-readable format. | ||
| */ | ||
| inline std::string nanosec_to_time_str(double nanosec) { | ||
| double sec_int = nanosec; | ||
|
|
||
| std::string unit = "ns"; | ||
|
|
||
| if (sec_int > 2000) { | ||
| unit = "us"; | ||
| sec_int /= 1000; | ||
| } | ||
|
|
||
| if (sec_int > 2000) { | ||
| unit = "ms"; | ||
| sec_int /= 1000; | ||
| } | ||
|
|
||
| if (sec_int > 2000) { | ||
| unit = "s"; | ||
| sec_int /= 1000; | ||
| } | ||
|
|
||
| if (sec_int > 2000) { | ||
| unit = "ks"; | ||
| sec_int /= 1000; | ||
| } | ||
|
|
||
| if (sec_int > 2000) { | ||
| unit = "Ms"; | ||
| sec_int /= 1000; | ||
| } | ||
|
|
||
| if (sec_int > 2000) { | ||
| unit = "Gs"; | ||
| sec_int /= 1000; | ||
| } | ||
|
|
||
| return shambase::format("{:.2f} {}", sec_int, unit); | ||
| } | ||
| } // namespace shambase |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| // -------------------------------------------------------// | ||
| // | ||
| // SHAMROCK code for hydrodynamics | ||
| // Copyright (c) 2021-2026 Timothée David--Cléris <tim.shamrock@proton.me> | ||
| // SPDX-License-Identifier: CeCILL Free Software License Agreement v2.1 | ||
| // Shamrock is licensed under the CeCILL 2.1 License, see LICENSE for more information | ||
| // | ||
| // -------------------------------------------------------// | ||
|
|
||
| #include "shambase/time.hpp" | ||
| #include "shamtest/shamtest.hpp" | ||
| #include <thread> | ||
|
|
||
| TestStart(Unittest, "shambase/time/start_stop_elapsed_gt_zero", unitt_timer_start_stop_elapsed, 1) { | ||
|
|
||
| shambase::Timer timer; | ||
|
|
||
| timer.start(); | ||
| std::this_thread::sleep_for(std::chrono::milliseconds(50)); | ||
| timer.stop(); | ||
|
|
||
| REQUIRE(timer.elapsed_sec() > 0); | ||
|
|
||
| std::string time_str = timer.get_time_str(); | ||
| REQUIRE(!time_str.empty()); | ||
| } | ||
|
|
||
| TestStart(Unittest, "shambase/time/sleep_200ms_precision", unitt_timer_sleep_200ms, 1) { | ||
|
|
||
| shambase::Timer timer; | ||
| timer.start(); | ||
| std::this_thread::sleep_for(std::chrono::milliseconds(400)); | ||
| timer.stop(); | ||
|
|
||
| // sadly i must be verrrrrrry loose on the tolerances because of Github runners ... | ||
| REQUIRE_FLOAT_EQUAL(timer.elapsed_sec(), 0.4, 0.2); | ||
| } | ||
|
|
||
| TestStart(Unittest, "shambase/time/stop_overwrites_nanosec", unitt_timer_stop_overwrites, 1) { | ||
|
|
||
| shambase::Timer timer; | ||
|
|
||
| timer.start(); | ||
| std::this_thread::sleep_for(std::chrono::milliseconds(300)); | ||
| timer.stop(); | ||
| f64 elapsed1 = timer.elapsed_sec(); | ||
|
|
||
| std::this_thread::sleep_for(std::chrono::milliseconds(50)); | ||
| timer.stop(); | ||
| f64 elapsed2 = timer.elapsed_sec(); | ||
|
|
||
| REQUIRE(elapsed1 < elapsed2); | ||
| } | ||
|
|
||
| TestStart(Unittest, "shambase/time/reusability", unitt_timer_reusability, 1) { | ||
|
|
||
| shambase::Timer timer; | ||
|
|
||
| timer.start(); | ||
| std::this_thread::sleep_for(std::chrono::milliseconds(200)); | ||
| timer.stop(); | ||
| f64 elapsed1 = timer.elapsed_sec(); | ||
|
|
||
| timer.start(); | ||
| std::this_thread::sleep_for(std::chrono::milliseconds(100)); | ||
| timer.stop(); | ||
| f64 elapsed2 = timer.elapsed_sec(); | ||
|
|
||
| REQUIRE(elapsed1 > elapsed2); | ||
| } | ||
|
|
||
| TestStart(Unittest, "shambase/time/get_time_str_has_unit", unitt_timer_get_time_str_format, 1) { | ||
|
|
||
| shambase::Timer timer; | ||
| timer.start(); | ||
| std::this_thread::sleep_for(std::chrono::milliseconds(50)); | ||
| timer.stop(); | ||
|
|
||
| std::string s = timer.get_time_str(); | ||
|
|
||
| REQUIRE(!s.empty()); | ||
| REQUIRE(s.find("ms") != std::string::npos || s.find("us") != std::string::npos); | ||
| } | ||
|
|
||
| TestStart( | ||
| Unittest, "shambase/time/nanosec_to_time_str_all_units", unitt_nanosec_to_time_str_various, 1) { | ||
|
|
||
| using namespace shambase; | ||
|
|
||
| REQUIRE(nanosec_to_time_str(0) == "0.00 ns"); | ||
| REQUIRE(nanosec_to_time_str(500) == "500.00 ns"); | ||
| REQUIRE(nanosec_to_time_str(2500) == "2.50 us"); | ||
| REQUIRE(nanosec_to_time_str(5000000) == "5.00 ms"); | ||
| REQUIRE(nanosec_to_time_str(2500000) == "2.50 ms"); | ||
| REQUIRE(nanosec_to_time_str(5000000000) == "5.00 s"); | ||
| REQUIRE(nanosec_to_time_str(2500000000) == "2.50 s"); | ||
| REQUIRE(nanosec_to_time_str(2500000000000) == "2.50 ks"); | ||
| REQUIRE(nanosec_to_time_str(2500000000000000) == "2.50 Ms"); | ||
| REQUIRE(nanosec_to_time_str(2500000000000000000) == "2.50 Gs"); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The internal state of the
Timerclass (the backend timer/time_point and thenanosecaccumulator) is currently exposed as public members. To improve encapsulation and prevent accidental modification of the timer's state from outside the class, these should be madeprivate.