From dfdbea3c6c006babec1474fdb4c09d6ace3ec976 Mon Sep 17 00:00:00 2001 From: David Heejong Park Date: Tue, 30 Apr 2024 12:36:26 +0200 Subject: [PATCH 1/8] Introduced cosim::real_time_config.step_duration_to_monitor for computing the rolling average real time factor using the specified period in second. --- include/cosim/timer.hpp | 11 +++++++++++ src/cosim/timer.cpp | 34 +++++++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/include/cosim/timer.hpp b/include/cosim/timer.hpp index 8b560d86..c51b8638 100644 --- a/include/cosim/timer.hpp +++ b/include/cosim/timer.hpp @@ -15,6 +15,7 @@ #include #include +#include namespace cosim { @@ -36,6 +37,15 @@ struct real_time_config * This value is used for monitoring purposes only. */ std::atomic steps_to_monitor = 5; + + /** + * A sampling period in second(s) used in the rolling average real time factor calculation. + * This can be useful when simulation step size is small and a fixed value for `steps_to_monitor` + * would not compute an accurate rolling average real time factor. + * When the value is greater than zero, the real time factor is computed periodically using the + * specified time instead of the `steps_to_monitor` value. + */ + std::atomic sampling_period_to_monitor = -1; }; } // namespace cosim @@ -54,6 +64,7 @@ class hash boost::hash_combine(seed, v.real_time_simulation.load()); boost::hash_combine(seed, v.real_time_factor_target.load()); boost::hash_combine(seed, v.steps_to_monitor.load()); + boost::hash_combine(seed, v.sampling_period_to_monitor.load()); return seed; } }; diff --git a/src/cosim/timer.cpp b/src/cosim/timer.cpp index 28309ca9..6c14132b 100644 --- a/src/cosim/timer.cpp +++ b/src/cosim/timer.cpp @@ -7,7 +7,6 @@ #include #include - typedef std::chrono::steady_clock Time; constexpr std::chrono::microseconds MIN_SLEEP(100); @@ -37,6 +36,12 @@ class real_time_timer::impl const auto newHash = std::hash()(*config_); if (newHash != configHashValue_) { start(currentTime); + auto step_duration_ = config_->sampling_period_to_monitor.load(); + if (step_duration_ > 0) { + sampling_period_to_monitor_ = to_duration(config_->sampling_period_to_monitor.load()); + } else { + sampling_period_to_monitor_ = std::nullopt; + } configHashValue_ = newHash; } double rtfTarget = config_->real_time_factor_target.load(); @@ -72,6 +77,19 @@ class real_time_timer::impl std::shared_ptr config_; size_t configHashValue_; std::shared_ptr metrics_; + std::optional sampling_period_to_monitor_ = std::nullopt; + + void update_rolling_average_real_time_factor( + Time::time_point& currentTime, + time_point& currentSimulationTime, + const duration& elapsedRealTime) + { + const auto elapsedSimTime = currentSimulationTime - rtSimulationStartTime_; + metrics_->rolling_average_real_time_factor = elapsedSimTime.count() / (1.0 * elapsedRealTime.count()); + rtStartTime_ = currentTime; + rtSimulationStartTime_ = currentSimulationTime; + rtCounter_ = 0L; + } void update_real_time_factor(Time::time_point currentTime, time_point currentSimulationTime) { @@ -79,14 +97,16 @@ class real_time_timer::impl const auto relativeRealTime = currentTime - startTime_; metrics_->total_average_real_time_factor = relativeSimTime.count() / (1.0 * relativeRealTime.count()); - if (rtCounter_ >= config_->steps_to_monitor.load()) { - const auto elapsedSimTime = currentSimulationTime - rtSimulationStartTime_; + if (sampling_period_to_monitor_.has_value()) { + const auto elapsedRealTime = currentTime - rtStartTime_; + + if (elapsedRealTime > sampling_period_to_monitor_.value()) { + update_rolling_average_real_time_factor(currentTime, currentSimulationTime, elapsedRealTime); + } + } else if (rtCounter_ >= config_->steps_to_monitor.load()) { const auto elapsedRealTime = currentTime - rtStartTime_; - metrics_->rolling_average_real_time_factor = elapsedSimTime.count() / (1.0 * elapsedRealTime.count()); - rtStartTime_ = currentTime; - rtSimulationStartTime_ = currentSimulationTime; - rtCounter_ = 0L; + update_rolling_average_real_time_factor(currentTime, currentSimulationTime, elapsedRealTime); } rtCounter_++; } From c86b331e2b4525e79ca557024aa92d70cca0fbc9 Mon Sep 17 00:00:00 2001 From: David Heejong Park Date: Tue, 30 Apr 2024 12:55:21 +0200 Subject: [PATCH 2/8] Removed mutex --- include/cosim/timer.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/include/cosim/timer.hpp b/include/cosim/timer.hpp index c51b8638..1fad5c2c 100644 --- a/include/cosim/timer.hpp +++ b/include/cosim/timer.hpp @@ -15,7 +15,6 @@ #include #include -#include namespace cosim { From 540f0b2ecaa3e148e685e7aa357fb552c5cc9c85 Mon Sep 17 00:00:00 2001 From: David Heejong Park Date: Tue, 30 Apr 2024 17:10:47 +0200 Subject: [PATCH 3/8] Added transitive_libs=True for ms-gsl. Else complaining about not finding Microsoft.GSL when consuming libcosim. --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 9e5337e4..41ab8d02 100755 --- a/conanfile.py +++ b/conanfile.py @@ -40,7 +40,7 @@ def requirements(self): self.tool_requires("cmake/[>=3.19]") self.requires("fmilibrary/[~2.3]") self.requires("libzip/[>=1.7 <1.10]") # 1.10 deprecates some functions we use - self.requires("ms-gsl/[>=3 <5]", transitive_headers=True) + self.requires("ms-gsl/[>=3 <5]", transitive_headers=True, transitive_libs=True) if self.options.proxyfmu: self.requires("proxyfmu/0.3.2@osp/stable") self.requires("boost/[~1.81]", transitive_headers=True, transitive_libs=True) # Required by Thrift From 9bb9d4587b34231cd933bc8baba2133c38805a07 Mon Sep 17 00:00:00 2001 From: David Heejong Park Date: Tue, 30 Apr 2024 23:25:05 +0200 Subject: [PATCH 4/8] Local variable naming change. --- src/cosim/timer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cosim/timer.cpp b/src/cosim/timer.cpp index 6c14132b..255c0a41 100644 --- a/src/cosim/timer.cpp +++ b/src/cosim/timer.cpp @@ -36,9 +36,9 @@ class real_time_timer::impl const auto newHash = std::hash()(*config_); if (newHash != configHashValue_) { start(currentTime); - auto step_duration_ = config_->sampling_period_to_monitor.load(); - if (step_duration_ > 0) { - sampling_period_to_monitor_ = to_duration(config_->sampling_period_to_monitor.load()); + auto samping_period = config_->sampling_period_to_monitor.load(); + if (samping_period > 0) { + sampling_period_to_monitor_ = to_duration(samping_period); } else { sampling_period_to_monitor_ = std::nullopt; } From 8519ba2f484f4b54eb1f1470d98f786cfbe8c8c0 Mon Sep 17 00:00:00 2001 From: David Heejong Park Date: Tue, 7 May 2024 14:39:15 +0200 Subject: [PATCH 5/8] Addressed comments --- conanfile.py | 2 +- include/cosim/timer.hpp | 6 +++--- src/cosim/timer.cpp | 14 +++++++------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/conanfile.py b/conanfile.py index 41ab8d02..9e5337e4 100755 --- a/conanfile.py +++ b/conanfile.py @@ -40,7 +40,7 @@ def requirements(self): self.tool_requires("cmake/[>=3.19]") self.requires("fmilibrary/[~2.3]") self.requires("libzip/[>=1.7 <1.10]") # 1.10 deprecates some functions we use - self.requires("ms-gsl/[>=3 <5]", transitive_headers=True, transitive_libs=True) + self.requires("ms-gsl/[>=3 <5]", transitive_headers=True) if self.options.proxyfmu: self.requires("proxyfmu/0.3.2@osp/stable") self.requires("boost/[~1.81]", transitive_headers=True, transitive_libs=True) # Required by Thrift diff --git a/include/cosim/timer.hpp b/include/cosim/timer.hpp index 1fad5c2c..cb2ba0f3 100644 --- a/include/cosim/timer.hpp +++ b/include/cosim/timer.hpp @@ -38,13 +38,13 @@ struct real_time_config std::atomic steps_to_monitor = 5; /** - * A sampling period in second(s) used in the rolling average real time factor calculation. + * A sampling period in real time (wall clock) in milliseconds used in the rolling average real time factor calculation. * This can be useful when simulation step size is small and a fixed value for `steps_to_monitor` * would not compute an accurate rolling average real time factor. * When the value is greater than zero, the real time factor is computed periodically using the * specified time instead of the `steps_to_monitor` value. */ - std::atomic sampling_period_to_monitor = -1; + std::atomic sampling_period_to_monitor = std::chrono::milliseconds(-1); }; } // namespace cosim @@ -63,7 +63,7 @@ class hash boost::hash_combine(seed, v.real_time_simulation.load()); boost::hash_combine(seed, v.real_time_factor_target.load()); boost::hash_combine(seed, v.steps_to_monitor.load()); - boost::hash_combine(seed, v.sampling_period_to_monitor.load()); + boost::hash_combine(seed, v.sampling_period_to_monitor.load().count()); return seed; } }; diff --git a/src/cosim/timer.cpp b/src/cosim/timer.cpp index 255c0a41..8a7b5ed7 100644 --- a/src/cosim/timer.cpp +++ b/src/cosim/timer.cpp @@ -36,9 +36,9 @@ class real_time_timer::impl const auto newHash = std::hash()(*config_); if (newHash != configHashValue_) { start(currentTime); - auto samping_period = config_->sampling_period_to_monitor.load(); - if (samping_period > 0) { - sampling_period_to_monitor_ = to_duration(samping_period); + const auto sampling_period = config_->sampling_period_to_monitor.load(); + if (sampling_period.count() > 0) { + sampling_period_to_monitor_ = sampling_period; } else { sampling_period_to_monitor_ = std::nullopt; } @@ -77,14 +77,14 @@ class real_time_timer::impl std::shared_ptr config_; size_t configHashValue_; std::shared_ptr metrics_; - std::optional sampling_period_to_monitor_ = std::nullopt; + std::optional sampling_period_to_monitor_ = std::nullopt; void update_rolling_average_real_time_factor( Time::time_point& currentTime, time_point& currentSimulationTime, const duration& elapsedRealTime) { - const auto elapsedSimTime = currentSimulationTime - rtSimulationStartTime_; + const auto elapsedSimTime = std::chrono::duration_cast(currentSimulationTime - rtSimulationStartTime_); metrics_->rolling_average_real_time_factor = elapsedSimTime.count() / (1.0 * elapsedRealTime.count()); rtStartTime_ = currentTime; rtSimulationStartTime_ = currentSimulationTime; @@ -93,8 +93,8 @@ class real_time_timer::impl void update_real_time_factor(Time::time_point currentTime, time_point currentSimulationTime) { - const auto relativeSimTime = currentSimulationTime - simulationStartTime_; - const auto relativeRealTime = currentTime - startTime_; + const auto relativeSimTime = std::chrono::duration_cast(currentSimulationTime - simulationStartTime_); + const auto relativeRealTime = std::chrono::duration_cast(currentTime - startTime_); metrics_->total_average_real_time_factor = relativeSimTime.count() / (1.0 * relativeRealTime.count()); if (sampling_period_to_monitor_.has_value()) { From 2ff7de3fa2f1abb7b26c21b9645d5bf7c378911a Mon Sep 17 00:00:00 2001 From: David Heejong Park Date: Tue, 7 May 2024 18:36:27 +0200 Subject: [PATCH 6/8] Addressed comments - 02 --- include/cosim/timer.hpp | 4 ++-- src/cosim/timer.cpp | 21 ++++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/include/cosim/timer.hpp b/include/cosim/timer.hpp index cb2ba0f3..5ae67c25 100644 --- a/include/cosim/timer.hpp +++ b/include/cosim/timer.hpp @@ -44,7 +44,7 @@ struct real_time_config * When the value is greater than zero, the real time factor is computed periodically using the * specified time instead of the `steps_to_monitor` value. */ - std::atomic sampling_period_to_monitor = std::chrono::milliseconds(-1); + std::atomic sampling_period_to_monitor = -1; }; } // namespace cosim @@ -63,7 +63,7 @@ class hash boost::hash_combine(seed, v.real_time_simulation.load()); boost::hash_combine(seed, v.real_time_factor_target.load()); boost::hash_combine(seed, v.steps_to_monitor.load()); - boost::hash_combine(seed, v.sampling_period_to_monitor.load().count()); + boost::hash_combine(seed, v.sampling_period_to_monitor.load()); return seed; } }; diff --git a/src/cosim/timer.cpp b/src/cosim/timer.cpp index 8a7b5ed7..99026229 100644 --- a/src/cosim/timer.cpp +++ b/src/cosim/timer.cpp @@ -37,8 +37,8 @@ class real_time_timer::impl if (newHash != configHashValue_) { start(currentTime); const auto sampling_period = config_->sampling_period_to_monitor.load(); - if (sampling_period.count() > 0) { - sampling_period_to_monitor_ = sampling_period; + if (sampling_period > 0) { + sampling_period_to_monitor_ = std::chrono::milliseconds(sampling_period); } else { sampling_period_to_monitor_ = std::nullopt; } @@ -78,13 +78,16 @@ class real_time_timer::impl size_t configHashValue_; std::shared_ptr metrics_; std::optional sampling_period_to_monitor_ = std::nullopt; + const volatile bool tick_period_match_ = std::is_same::value; void update_rolling_average_real_time_factor( Time::time_point& currentTime, time_point& currentSimulationTime, - const duration& elapsedRealTime) + const cosim::duration& elapsedRealTime) { - const auto elapsedSimTime = std::chrono::duration_cast(currentSimulationTime - rtSimulationStartTime_); + const auto elapsedSimTime = + tick_period_match_ ? currentSimulationTime - rtSimulationStartTime_ : std::chrono::duration_cast(currentSimulationTime - rtSimulationStartTime_); + metrics_->rolling_average_real_time_factor = elapsedSimTime.count() / (1.0 * elapsedRealTime.count()); rtStartTime_ = currentTime; rtSimulationStartTime_ = currentSimulationTime; @@ -93,12 +96,16 @@ class real_time_timer::impl void update_real_time_factor(Time::time_point currentTime, time_point currentSimulationTime) { - const auto relativeSimTime = std::chrono::duration_cast(currentSimulationTime - simulationStartTime_); - const auto relativeRealTime = std::chrono::duration_cast(currentTime - startTime_); + const auto relativeSimTime = + tick_period_match_ ? currentSimulationTime - simulationStartTime_ : std::chrono::duration_cast(currentSimulationTime - simulationStartTime_); + const auto relativeRealTime = + tick_period_match_ ? currentTime - startTime_ : std::chrono::duration_cast(currentTime - startTime_); + metrics_->total_average_real_time_factor = relativeSimTime.count() / (1.0 * relativeRealTime.count()); if (sampling_period_to_monitor_.has_value()) { - const auto elapsedRealTime = currentTime - rtStartTime_; + const auto elapsedRealTime = + tick_period_match_ ? currentTime - rtStartTime_ : std::chrono::duration_cast(currentTime - rtStartTime_); if (elapsedRealTime > sampling_period_to_monitor_.value()) { update_rolling_average_real_time_factor(currentTime, currentSimulationTime, elapsedRealTime); From 55ce42e75ac5d5fc00dd3f577ee9c7925eda5b02 Mon Sep 17 00:00:00 2001 From: David Heejong Park Date: Tue, 7 May 2024 19:33:18 +0200 Subject: [PATCH 7/8] Additional fix --- src/cosim/timer.cpp | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/cosim/timer.cpp b/src/cosim/timer.cpp index 99026229..c273775e 100644 --- a/src/cosim/timer.cpp +++ b/src/cosim/timer.cpp @@ -85,10 +85,13 @@ class real_time_timer::impl time_point& currentSimulationTime, const cosim::duration& elapsedRealTime) { - const auto elapsedSimTime = - tick_period_match_ ? currentSimulationTime - rtSimulationStartTime_ : std::chrono::duration_cast(currentSimulationTime - rtSimulationStartTime_); - - metrics_->rolling_average_real_time_factor = elapsedSimTime.count() / (1.0 * elapsedRealTime.count()); + const auto elapsedSimTime = currentSimulationTime - rtSimulationStartTime_; + if (tick_period_match_) { + metrics_->rolling_average_real_time_factor = elapsedSimTime.count() / (1.0 * elapsedRealTime.count()); + } else { + metrics_->rolling_average_real_time_factor = + std::chrono::duration_cast(elapsedSimTime).count() / (1.0 * std::chrono::duration_cast(elapsedRealTime).count()); + } rtStartTime_ = currentTime; rtSimulationStartTime_ = currentSimulationTime; rtCounter_ = 0L; @@ -96,16 +99,18 @@ class real_time_timer::impl void update_real_time_factor(Time::time_point currentTime, time_point currentSimulationTime) { - const auto relativeSimTime = - tick_period_match_ ? currentSimulationTime - simulationStartTime_ : std::chrono::duration_cast(currentSimulationTime - simulationStartTime_); - const auto relativeRealTime = - tick_period_match_ ? currentTime - startTime_ : std::chrono::duration_cast(currentTime - startTime_); - - metrics_->total_average_real_time_factor = relativeSimTime.count() / (1.0 * relativeRealTime.count()); + const auto relativeSimTime = currentSimulationTime - simulationStartTime_; + const auto relativeRealTime = currentTime - startTime_; + + if (tick_period_match_) { + metrics_->total_average_real_time_factor = relativeSimTime.count() / (1.0 * relativeRealTime.count()); + } else { + metrics_->total_average_real_time_factor = + std::chrono::duration_cast(relativeSimTime).count() / (1.0 * std::chrono::duration_cast(relativeRealTime).count()); + } if (sampling_period_to_monitor_.has_value()) { - const auto elapsedRealTime = - tick_period_match_ ? currentTime - rtStartTime_ : std::chrono::duration_cast(currentTime - rtStartTime_); + const auto elapsedRealTime = currentTime - rtStartTime_; if (elapsedRealTime > sampling_period_to_monitor_.value()) { update_rolling_average_real_time_factor(currentTime, currentSimulationTime, elapsedRealTime); From af7bf1f4cd987bc9112e9ee3fec85e1d8add52fd Mon Sep 17 00:00:00 2001 From: David Heejong Park Date: Tue, 7 May 2024 21:41:54 +0200 Subject: [PATCH 8/8] Using duration_cast --- include/cosim/timer.hpp | 4 ++-- src/cosim/timer.cpp | 35 +++++++++++++---------------------- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/include/cosim/timer.hpp b/include/cosim/timer.hpp index 5ae67c25..cb2ba0f3 100644 --- a/include/cosim/timer.hpp +++ b/include/cosim/timer.hpp @@ -44,7 +44,7 @@ struct real_time_config * When the value is greater than zero, the real time factor is computed periodically using the * specified time instead of the `steps_to_monitor` value. */ - std::atomic sampling_period_to_monitor = -1; + std::atomic sampling_period_to_monitor = std::chrono::milliseconds(-1); }; } // namespace cosim @@ -63,7 +63,7 @@ class hash boost::hash_combine(seed, v.real_time_simulation.load()); boost::hash_combine(seed, v.real_time_factor_target.load()); boost::hash_combine(seed, v.steps_to_monitor.load()); - boost::hash_combine(seed, v.sampling_period_to_monitor.load()); + boost::hash_combine(seed, v.sampling_period_to_monitor.load().count()); return seed; } }; diff --git a/src/cosim/timer.cpp b/src/cosim/timer.cpp index c273775e..1a191bab 100644 --- a/src/cosim/timer.cpp +++ b/src/cosim/timer.cpp @@ -37,8 +37,8 @@ class real_time_timer::impl if (newHash != configHashValue_) { start(currentTime); const auto sampling_period = config_->sampling_period_to_monitor.load(); - if (sampling_period > 0) { - sampling_period_to_monitor_ = std::chrono::milliseconds(sampling_period); + if (sampling_period.count() > 0) { + sampling_period_to_monitor_ = sampling_period; } else { sampling_period_to_monitor_ = std::nullopt; } @@ -78,20 +78,17 @@ class real_time_timer::impl size_t configHashValue_; std::shared_ptr metrics_; std::optional sampling_period_to_monitor_ = std::nullopt; - const volatile bool tick_period_match_ = std::is_same::value; + template void update_rolling_average_real_time_factor( - Time::time_point& currentTime, - time_point& currentSimulationTime, - const cosim::duration& elapsedRealTime) + const Time::time_point& currentTime, + const time_point& currentSimulationTime, + const std::chrono::duration& elapsedRealTime) { const auto elapsedSimTime = currentSimulationTime - rtSimulationStartTime_; - if (tick_period_match_) { - metrics_->rolling_average_real_time_factor = elapsedSimTime.count() / (1.0 * elapsedRealTime.count()); - } else { - metrics_->rolling_average_real_time_factor = - std::chrono::duration_cast(elapsedSimTime).count() / (1.0 * std::chrono::duration_cast(elapsedRealTime).count()); - } + + metrics_->rolling_average_real_time_factor = + std::chrono::duration_cast(elapsedSimTime).count() / (1.0 * std::chrono::duration_cast(elapsedRealTime).count()); rtStartTime_ = currentTime; rtSimulationStartTime_ = currentSimulationTime; rtCounter_ = 0L; @@ -99,25 +96,19 @@ class real_time_timer::impl void update_real_time_factor(Time::time_point currentTime, time_point currentSimulationTime) { - const auto relativeSimTime = currentSimulationTime - simulationStartTime_; - const auto relativeRealTime = currentTime - startTime_; - - if (tick_period_match_) { - metrics_->total_average_real_time_factor = relativeSimTime.count() / (1.0 * relativeRealTime.count()); - } else { - metrics_->total_average_real_time_factor = - std::chrono::duration_cast(relativeSimTime).count() / (1.0 * std::chrono::duration_cast(relativeRealTime).count()); - } + const auto relativeSimTime = std::chrono::duration_cast(currentSimulationTime - simulationStartTime_); + const auto relativeRealTime = std::chrono::duration_cast(currentTime - startTime_); + metrics_->total_average_real_time_factor = relativeSimTime.count() / (1.0 * relativeRealTime.count()); if (sampling_period_to_monitor_.has_value()) { const auto elapsedRealTime = currentTime - rtStartTime_; if (elapsedRealTime > sampling_period_to_monitor_.value()) { + const auto elapsedSimTime = currentSimulationTime - rtSimulationStartTime_; update_rolling_average_real_time_factor(currentTime, currentSimulationTime, elapsedRealTime); } } else if (rtCounter_ >= config_->steps_to_monitor.load()) { const auto elapsedRealTime = currentTime - rtStartTime_; - update_rolling_average_real_time_factor(currentTime, currentSimulationTime, elapsedRealTime); } rtCounter_++;