Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion include/manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<void(Process&)> f);
Expand Down Expand Up @@ -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();
Expand Down
5 changes: 5 additions & 0 deletions include/process.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
36 changes: 26 additions & 10 deletions src/manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
});
Expand Down Expand Up @@ -207,31 +207,47 @@ 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();
auto rhsTime = rhs->last_update() + rhs->period();
auto lhsTime = lhs->next_update();
auto rhsTime = rhs->next_update();
return lhsTime < rhsTime;
});

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;

}
}
}

Expand Down
60 changes: 60 additions & 0 deletions test/sleep_manager.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include <iostream>
#include <vector>
#include <string>
#include <chrono>
#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("Simulated 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);
}

}