Skip to content

Commit c8dc2df

Browse files
committed
Add NearEWventsStorage
1 parent c9e469f commit c8dc2df

5 files changed

Lines changed: 152 additions & 34 deletions

File tree

source/scheduler/event/event.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#include "event.hpp"
2+
3+
namespace sim {
4+
bool Event::operator>(const Event &other) const {
5+
return m_time > other.m_time;
6+
}
7+
} // namespace sim
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#include "near_events_storage.hpp"
2+
3+
namespace sim {
4+
5+
void NearEventsStorage::add(std::unique_ptr<Event> event, TimeNs current_time) {
6+
std::uint32_t relative_event_time =
7+
(event->get_time() - current_time).value_nanoseconds();
8+
9+
auto add_to_storage =
10+
[](std::deque<std::queue<std::unique_ptr<Event> > >& storage,
11+
std::size_t index, std::unique_ptr<Event> event) {
12+
if (index >= storage.size()) {
13+
storage.resize(index + 1);
14+
}
15+
storage[index].emplace(std::move(event));
16+
};
17+
18+
std::uint32_t first_storage_bucket_index =
19+
m_current_bucket + relative_event_time;
20+
if (first_storage_bucket_index < m_max_buckets_count) {
21+
// its enough place to put event to first bucket; use it
22+
add_to_storage(m_first_event_buckets_storage,
23+
first_storage_bucket_index, std::move(event));
24+
m_first_bucket_empty = false;
25+
} else {
26+
// event could not be stores in first bucket; put it to second one
27+
add_to_storage(m_second_event_buckets_storage,
28+
first_storage_bucket_index - m_max_buckets_count,
29+
std::move(event));
30+
m_second_bucket_empty = false;
31+
}
32+
}
33+
34+
std::unique_ptr<Event> NearEventsStorage::pop_first() {
35+
correctify_state();
36+
// state is correct
37+
if (empty()) {
38+
throw std::runtime_error("call from on empty storage");
39+
}
40+
std::unique_ptr<Event> event =
41+
std::move(m_first_event_buckets_storage[m_current_bucket].front());
42+
// be careful: after next line state should be correctified (current bucket
43+
// might become empty or all m_first_storage)
44+
m_first_event_buckets_storage[m_current_bucket].pop();
45+
return event;
46+
}
47+
48+
bool NearEventsStorage::empty() {
49+
correctify_state();
50+
return m_first_bucket_empty;
51+
}
52+
53+
void NearEventsStorage::correctify_state() {
54+
if (!m_first_bucket_empty) {
55+
while (m_current_bucket < m_first_event_buckets_storage.size() &&
56+
m_first_event_buckets_storage[m_current_bucket].empty()) {
57+
m_current_bucket++;
58+
}
59+
if (m_current_bucket != m_first_event_buckets_storage.size()) {
60+
// m_first_event_buckets_storage[m_current_bucket] is not empty ->
61+
// state is correct
62+
return;
63+
}
64+
}
65+
66+
// all events in first storages are done => first bucket is <<empty>>
67+
m_first_bucket_empty = true;
68+
m_current_bucket = 0;
69+
70+
if (m_second_bucket_empty) {
71+
// second bucket is empty => all buckets are empty
72+
return;
73+
}
74+
75+
while (m_current_bucket < m_first_event_buckets_storage.size() &&
76+
m_second_event_buckets_storage[m_current_bucket].empty()) {
77+
m_current_bucket++;
78+
}
79+
80+
// swap storages
81+
m_first_event_buckets_storage.swap(m_second_event_buckets_storage);
82+
std::swap(m_first_bucket_empty, m_second_bucket_empty);
83+
}
84+
85+
} // namespace sim
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#pragma once
2+
#include <deque>
3+
#include <queue>
4+
5+
#include "event/event.hpp"
6+
#include "types.hpp"
7+
8+
namespace sim {
9+
10+
class NearEventsStorage {
11+
public:
12+
explicit NearEventsStorage(std::size_t a_max_buckets_count)
13+
: m_current_bucket(0), m_max_buckets_count(a_max_buckets_count) {
14+
m_first_event_buckets_storage.emplace_back(
15+
std::queue<std::unique_ptr<Event> >());
16+
m_second_event_buckets_storage.emplace_back(
17+
std::queue<std::unique_ptr<Event> >());
18+
}
19+
20+
void add(std::unique_ptr<Event> event, TimeNs current_time);
21+
std::unique_ptr<Event> pop_first();
22+
bool empty();
23+
24+
private:
25+
// forwards m_current_bucket while it points to empty bucket
26+
void correctify_state();
27+
28+
std::deque<std::queue<std::unique_ptr<Event> > >
29+
m_first_event_buckets_storage;
30+
std::deque<std::queue<std::unique_ptr<Event> > >
31+
m_second_event_buckets_storage;
32+
33+
std::size_t m_current_bucket;
34+
std::size_t m_max_buckets_count;
35+
36+
bool m_first_bucket_empty = true;
37+
bool m_second_bucket_empty = true;
38+
};
39+
40+
} // namespace sim

source/scheduler/scheduler.cpp

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,34 +18,27 @@ bool Scheduler::tick() {
1818
event->operator()();
1919
};
2020

21-
while (!m_near_events.empty() && m_near_events.front().empty()) {
22-
m_near_events.pop_front();
23-
}
24-
// now m_near_events is empty or its first storage is not empty
25-
2621
if (!m_near_events.empty()) {
27-
// run first near event
28-
std::unique_ptr<Event> event = std::move(m_near_events[0].front());
29-
m_near_events[0].pop();
30-
run_event(std::move(event));
22+
run_event(m_near_events.pop_first());
3123
return true;
3224
}
25+
// no near events
3326

34-
if (!m_far_events.empty()) {
35-
// no near events, but have some far ones => run first from far ones
36-
run_event(take_top_far_event());
37-
return true;
27+
if (m_far_events.empty()) {
28+
return false;
3829
}
3930

31+
// no near events, but have some far ones => run first from far ones
32+
run_event(take_top_far_event());
33+
return true;
34+
4035
// no near nor fat events => nothing to do
4136
return false;
4237
}
4338

4439
void Scheduler::clear() {
45-
std::priority_queue<std::unique_ptr<Event>,
46-
std::vector<std::unique_ptr<Event>>, EventComparator>()
47-
.swap(m_far_events);
48-
std::deque<std::queue<std::unique_ptr<Event>>>().swap(m_near_events);
40+
m_near_events =
41+
NearEventsStorage(M_MAX_COUNTSORT_CAPACITY.value_nanoseconds());
4942
m_current_event_local_time = TimeNs(0);
5043
}
5144

source/scheduler/scheduler.hpp

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <queue>
66

77
#include "event/event.hpp"
8+
#include "near_events_storage.hpp"
89
#include "types.hpp"
910

1011
namespace sim {
@@ -41,7 +42,7 @@ class Scheduler {
4142
}
4243

4344
if (is_near_event(event)) {
44-
add_near_event(std::move(event));
45+
m_near_events.add(std::move(event), m_current_event_local_time);
4546
} else {
4647
m_far_events.emplace(std::move(event));
4748
}
@@ -52,10 +53,13 @@ class Scheduler {
5253
TimeNs get_current_time();
5354

5455
private:
55-
static constexpr inline TimeNs M_MAX_COUNTSORT_CAPACITY = TimeNs(100'000);
56+
static constexpr inline TimeNs M_MAX_COUNTSORT_CAPACITY = TimeNs(50'000);
5657

5758
// Private constructor to prevent instantiation
58-
Scheduler() : m_current_event_local_time(TimeNs(0)) {}
59+
Scheduler()
60+
: m_near_events(M_MAX_COUNTSORT_CAPACITY.value_nanoseconds()),
61+
m_current_event_local_time(TimeNs(0)) {}
62+
5963
// No copy constructor and assignment operators
6064
Scheduler(const Scheduler&) = delete;
6165
Scheduler& operator=(const Scheduler&) = delete;
@@ -66,18 +70,6 @@ class Scheduler {
6670
m_current_event_local_time + M_MAX_COUNTSORT_CAPACITY;
6771
}
6872

69-
inline void add_near_event(std::unique_ptr<Event> event) {
70-
std::uint32_t relative_event_time =
71-
(event->get_time() - m_current_event_local_time)
72-
.value_nanoseconds();
73-
74-
if (m_near_events.size() <= relative_event_time) {
75-
m_near_events.resize(relative_event_time + 1);
76-
}
77-
78-
m_near_events[relative_event_time].emplace(std::move(event));
79-
}
80-
8173
inline std::unique_ptr<Event> take_top_far_event() {
8274
std::unique_ptr<Event> event =
8375
std::move(const_cast<std::unique_ptr<Event>&>(m_far_events.top()));
@@ -90,14 +82,15 @@ class Scheduler {
9082
const std::unique_ptr<Event>& event = m_far_events.top();
9183

9284
if (is_near_event(event)) {
93-
add_near_event(take_top_far_event());
85+
m_near_events.add(take_top_far_event(),
86+
m_current_event_local_time);
9487
} else {
9588
break;
9689
}
9790
}
9891
}
9992

100-
std::deque<std::queue<std::unique_ptr<Event>>> m_near_events;
93+
NearEventsStorage m_near_events;
10194

10295
std::priority_queue<std::unique_ptr<Event>,
10396
std::vector<std::unique_ptr<Event>>, EventComparator>

0 commit comments

Comments
 (0)