From 383c8e8d1d23dc111b210d4eef7f72bf7527b5ac Mon Sep 17 00:00:00 2001 From: wesfiala Date: Fri, 15 Mar 2019 14:08:02 -0700 Subject: [PATCH 1/4] Sleep the manager when waiting for the next scheduled process to run. --- include/manager.h | 7 ++++- include/process.h | 5 ++++ src/manager.cc | 32 +++++++++++++++++------ test/sleep_manager.cc | 60 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 test/sleep_manager.cc diff --git a/include/manager.h b/include/manager.h index 2a8b9a5..22f6be4 100644 --- a/include/manager.h +++ b/include/manager.h @@ -28,7 +28,7 @@ namespace elma { public: //! Default constructor - Manager() : _running(false), _simulated_time(false) {} + Manager() : _running(false), _simulated_time(false), _update_time_calls(0) {} Manager& schedule(Process& process, high_resolution_clock::duration period); Manager& all(std::function f); @@ -65,6 +65,11 @@ namespace elma { Manager& emit(const Event& event); Client& client() { return _client; } + protected: + + // Used for testing purposes. + int _update_time_calls; + private: void update_elapsed_time(); diff --git a/include/process.h b/include/process.h index de6c3de..d8cee20 100644 --- a/include/process.h +++ b/include/process.h @@ -97,6 +97,11 @@ namespace elma { //! time the Manager called the update() method. inline high_resolution_clock::duration previous_update() { return _previous_update; } + //! Getter + //! \return The duration of time between the start time and the next scheduled + //! time the Manager should call the update() method. + inline high_resolution_clock::duration next_update() { return period() * num_updates();}; + // documentation for these methods is in process.cc Channel& channel(string name); double milli_time(); diff --git a/src/manager.cc b/src/manager.cc index d86dd7d..1599d8b 100644 --- a/src/manager.cc +++ b/src/manager.cc @@ -118,7 +118,7 @@ namespace elma { Manager& Manager::update() { _client.process_responses(); return all([this](Process& p) { - if ( _elapsed >= p.last_update() + p.period() ) { + if ( _elapsed >= p.next_update() ) { p._update(_elapsed); } }); @@ -207,14 +207,22 @@ namespace elma { } //! Updates the elapsed time of the manager. - //! In normal mode, elapsed is the time since starting the manager. + //! In realtime mode, sleeps until the next scheduled process update. //! In simulated mode, elapsed is set to the time of the next scheduled event. - //! If no processes are scheduled, will always runs in normal mode. + //! If no processes are scheduled, will always run in realtime mode. void Manager::update_elapsed_time() { + // Used for testing purposes only. + ++_update_time_calls; + // Only run in simulated time if we have the flag set and have processes. - if(_simulated_time && !_processes.empty()) { + if (_processes.empty()) + { + + _elapsed = high_resolution_clock::now() - _start_time; + } else { + // Find the process that has the smallest time till next update. auto min_iter = std::min_element(_processes.begin(), _processes.end() ,[](Process * lhs, Process * rhs) { auto lhsTime = lhs->last_update() + lhs->period(); @@ -223,15 +231,23 @@ namespace elma { }); Process* nextup = *min_iter; + auto nextUpdateTime = nextup->next_update(); - auto newTime = nextup->last_update() + nextup->period(); + // When simulating time, jump to the next scheduled update time. + if(_simulated_time) { - _elapsed = newTime; + _elapsed = nextUpdateTime; - } else { + // In realtime sleep until the next scheduled update time. + } else { - _elapsed = high_resolution_clock::now() - _start_time; + _elapsed = high_resolution_clock::now() - _start_time; + auto sleepTime = nextUpdateTime - _elapsed; + + std::this_thread::sleep_for(sleepTime); + _elapsed = high_resolution_clock::now() - _start_time; + } } } diff --git a/test/sleep_manager.cc b/test/sleep_manager.cc new file mode 100644 index 0000000..25c598d --- /dev/null +++ b/test/sleep_manager.cc @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include "gtest/gtest.h" +#include "elma.h" + +namespace { + + using namespace elma; + + class TestManager : public Manager { + public: + TestManager() : Manager() {} + + using Manager::_update_time_calls; + }; + + class SimProcess : public Process { + public: + SimProcess(string name) : Process(name) {} + void init() {} + void start() {} + void update() {} + void stop() {} + }; + + TEST(SleepManager, Realtime) { + SimProcess tp("Realtime Process"); + TestManager m; + m.schedule(tp, 10_ms) + .init() + .run([&](){return tp.num_updates() <= 100;}); + + EXPECT_GE(m._update_time_calls, 99); + EXPECT_LE(m._update_time_calls, 101); + } + + TEST(SleepManager, Simulated) { + SimProcess tp("Realtime Process"); + TestManager m; + m.schedule(tp, 10_ms) + .init() + .use_simulated_time() + .run([&](){return tp.num_updates() <= 100;}); + + EXPECT_GE(m._update_time_calls, 99); + EXPECT_LE(m._update_time_calls, 101); + } + + TEST(SleepManager, NoProcesses) { + TestManager m; + m.init() + .use_simulated_time() + .run(100ms); + + EXPECT_GT(m._update_time_calls, 1000); + } + +} \ No newline at end of file From 74a782511cc4a1011c9286ab9ae89169e7763f91 Mon Sep 17 00:00:00 2001 From: wesfiala Date: Fri, 15 Mar 2019 14:08:02 -0700 Subject: [PATCH 2/4] Sleep the manager when waiting for the next scheduled process to run. --- include/manager.h | 7 ++++- include/process.h | 5 ++++ src/manager.cc | 32 +++++++++++++++++------ test/sleep_manager.cc | 60 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 test/sleep_manager.cc diff --git a/include/manager.h b/include/manager.h index 2a8b9a5..22f6be4 100644 --- a/include/manager.h +++ b/include/manager.h @@ -28,7 +28,7 @@ namespace elma { public: //! Default constructor - Manager() : _running(false), _simulated_time(false) {} + Manager() : _running(false), _simulated_time(false), _update_time_calls(0) {} Manager& schedule(Process& process, high_resolution_clock::duration period); Manager& all(std::function f); @@ -65,6 +65,11 @@ namespace elma { Manager& emit(const Event& event); Client& client() { return _client; } + protected: + + // Used for testing purposes. + int _update_time_calls; + private: void update_elapsed_time(); diff --git a/include/process.h b/include/process.h index de6c3de..d8cee20 100644 --- a/include/process.h +++ b/include/process.h @@ -97,6 +97,11 @@ namespace elma { //! time the Manager called the update() method. inline high_resolution_clock::duration previous_update() { return _previous_update; } + //! Getter + //! \return The duration of time between the start time and the next scheduled + //! time the Manager should call the update() method. + inline high_resolution_clock::duration next_update() { return period() * num_updates();}; + // documentation for these methods is in process.cc Channel& channel(string name); double milli_time(); diff --git a/src/manager.cc b/src/manager.cc index d86dd7d..1599d8b 100644 --- a/src/manager.cc +++ b/src/manager.cc @@ -118,7 +118,7 @@ namespace elma { Manager& Manager::update() { _client.process_responses(); return all([this](Process& p) { - if ( _elapsed >= p.last_update() + p.period() ) { + if ( _elapsed >= p.next_update() ) { p._update(_elapsed); } }); @@ -207,14 +207,22 @@ namespace elma { } //! Updates the elapsed time of the manager. - //! In normal mode, elapsed is the time since starting the manager. + //! In realtime mode, sleeps until the next scheduled process update. //! In simulated mode, elapsed is set to the time of the next scheduled event. - //! If no processes are scheduled, will always runs in normal mode. + //! If no processes are scheduled, will always run in realtime mode. void Manager::update_elapsed_time() { + // Used for testing purposes only. + ++_update_time_calls; + // Only run in simulated time if we have the flag set and have processes. - if(_simulated_time && !_processes.empty()) { + if (_processes.empty()) + { + + _elapsed = high_resolution_clock::now() - _start_time; + } else { + // Find the process that has the smallest time till next update. auto min_iter = std::min_element(_processes.begin(), _processes.end() ,[](Process * lhs, Process * rhs) { auto lhsTime = lhs->last_update() + lhs->period(); @@ -223,15 +231,23 @@ namespace elma { }); Process* nextup = *min_iter; + auto nextUpdateTime = nextup->next_update(); - auto newTime = nextup->last_update() + nextup->period(); + // When simulating time, jump to the next scheduled update time. + if(_simulated_time) { - _elapsed = newTime; + _elapsed = nextUpdateTime; - } else { + // In realtime sleep until the next scheduled update time. + } else { - _elapsed = high_resolution_clock::now() - _start_time; + _elapsed = high_resolution_clock::now() - _start_time; + auto sleepTime = nextUpdateTime - _elapsed; + + std::this_thread::sleep_for(sleepTime); + _elapsed = high_resolution_clock::now() - _start_time; + } } } diff --git a/test/sleep_manager.cc b/test/sleep_manager.cc new file mode 100644 index 0000000..25c598d --- /dev/null +++ b/test/sleep_manager.cc @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include "gtest/gtest.h" +#include "elma.h" + +namespace { + + using namespace elma; + + class TestManager : public Manager { + public: + TestManager() : Manager() {} + + using Manager::_update_time_calls; + }; + + class SimProcess : public Process { + public: + SimProcess(string name) : Process(name) {} + void init() {} + void start() {} + void update() {} + void stop() {} + }; + + TEST(SleepManager, Realtime) { + SimProcess tp("Realtime Process"); + TestManager m; + m.schedule(tp, 10_ms) + .init() + .run([&](){return tp.num_updates() <= 100;}); + + EXPECT_GE(m._update_time_calls, 99); + EXPECT_LE(m._update_time_calls, 101); + } + + TEST(SleepManager, Simulated) { + SimProcess tp("Realtime Process"); + TestManager m; + m.schedule(tp, 10_ms) + .init() + .use_simulated_time() + .run([&](){return tp.num_updates() <= 100;}); + + EXPECT_GE(m._update_time_calls, 99); + EXPECT_LE(m._update_time_calls, 101); + } + + TEST(SleepManager, NoProcesses) { + TestManager m; + m.init() + .use_simulated_time() + .run(100ms); + + EXPECT_GT(m._update_time_calls, 1000); + } + +} \ No newline at end of file From bf4566194cce4ea57acde84d5ec690179bd40e20 Mon Sep 17 00:00:00 2001 From: wesfiala Date: Fri, 15 Mar 2019 14:28:13 -0700 Subject: [PATCH 3/4] Use the new next_update method when finding the next method to run --- src/manager.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/manager.cc b/src/manager.cc index 1599d8b..b8f3475 100644 --- a/src/manager.cc +++ b/src/manager.cc @@ -225,8 +225,8 @@ namespace elma { // Find the process that has the smallest time till next update. auto min_iter = std::min_element(_processes.begin(), _processes.end() ,[](Process * lhs, Process * rhs) { - auto lhsTime = lhs->last_update() + lhs->period(); - auto rhsTime = rhs->last_update() + rhs->period(); + auto lhsTime = lhs->next_update(); + auto rhsTime = rhs->next_update(); return lhsTime < rhsTime; }); From 75522869b87b2a95dbec3a77311db0fbaf6f97a1 Mon Sep 17 00:00:00 2001 From: wesfiala Date: Fri, 15 Mar 2019 14:30:43 -0700 Subject: [PATCH 4/4] Caught a typo in a test file --- test/sleep_manager.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/sleep_manager.cc b/test/sleep_manager.cc index 25c598d..fa9f25c 100644 --- a/test/sleep_manager.cc +++ b/test/sleep_manager.cc @@ -37,7 +37,7 @@ namespace { } TEST(SleepManager, Simulated) { - SimProcess tp("Realtime Process"); + SimProcess tp("Simulated Process"); TestManager m; m.schedule(tp, 10_ms) .init()