summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/core/core_timing.cpp56
-rw-r--r--src/core/core_timing.h12
2 files changed, 35 insertions, 33 deletions
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index b98a0cb33..65f0df115 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -32,6 +32,7 @@ struct CoreTiming::Event {
32 std::uintptr_t user_data; 32 std::uintptr_t user_data;
33 std::weak_ptr<EventType> type; 33 std::weak_ptr<EventType> type;
34 s64 reschedule_time; 34 s64 reschedule_time;
35 heap_t::handle_type handle{};
35 36
36 // Sort by time, unless the times are the same, in which case sort by 37 // Sort by time, unless the times are the same, in which case sort by
37 // the order added to the queue 38 // the order added to the queue
@@ -122,9 +123,9 @@ void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
122 std::scoped_lock scope{basic_lock}; 123 std::scoped_lock scope{basic_lock};
123 const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future}; 124 const auto next_time{absolute_time ? ns_into_future : GetGlobalTimeNs() + ns_into_future};
124 125
125 event_queue.emplace_back( 126 auto h{event_queue.emplace(
126 Event{next_time.count(), event_fifo_id++, user_data, event_type, 0}); 127 Event{next_time.count(), event_fifo_id++, user_data, event_type, 0})};
127 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); 128 (*h).handle = h;
128 } 129 }
129 130
130 event.Set(); 131 event.Set();
@@ -138,10 +139,9 @@ void CoreTiming::ScheduleLoopingEvent(std::chrono::nanoseconds start_time,
138 std::scoped_lock scope{basic_lock}; 139 std::scoped_lock scope{basic_lock};
139 const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time}; 140 const auto next_time{absolute_time ? start_time : GetGlobalTimeNs() + start_time};
140 141
141 event_queue.emplace_back( 142 auto h{event_queue.emplace(Event{next_time.count(), event_fifo_id++, user_data, event_type,
142 Event{next_time.count(), event_fifo_id++, user_data, event_type, resched_time.count()}); 143 resched_time.count()})};
143 144 (*h).handle = h;
144 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
145 } 145 }
146 146
147 event.Set(); 147 event.Set();
@@ -151,15 +151,17 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
151 std::uintptr_t user_data, bool wait) { 151 std::uintptr_t user_data, bool wait) {
152 { 152 {
153 std::scoped_lock lk{basic_lock}; 153 std::scoped_lock lk{basic_lock};
154 const auto itr = 154
155 std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { 155 std::vector<heap_t::handle_type> to_remove;
156 return e.type.lock().get() == event_type.get() && e.user_data == user_data; 156 for (auto itr = event_queue.begin(); itr != event_queue.end(); itr++) {
157 }); 157 const Event& e = *itr;
158 158 if (e.type.lock().get() == event_type.get() && e.user_data == user_data) {
159 // Removing random items breaks the invariant so we have to re-establish it. 159 to_remove.push_back(itr->handle);
160 if (itr != event_queue.end()) { 160 }
161 event_queue.erase(itr, event_queue.end()); 161 }
162 std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>()); 162
163 for (auto h : to_remove) {
164 event_queue.erase(h);
163 } 165 }
164 } 166 }
165 167
@@ -200,10 +202,9 @@ std::optional<s64> CoreTiming::Advance() {
200 std::scoped_lock lock{advance_lock, basic_lock}; 202 std::scoped_lock lock{advance_lock, basic_lock};
201 global_timer = GetGlobalTimeNs().count(); 203 global_timer = GetGlobalTimeNs().count();
202 204
203 while (!event_queue.empty() && event_queue.front().time <= global_timer) { 205 while (!event_queue.empty() && event_queue.top().time <= global_timer) {
204 Event evt = std::move(event_queue.front()); 206 Event evt = event_queue.top();
205 std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>()); 207 event_queue.pop();
206 event_queue.pop_back();
207 208
208 if (const auto event_type{evt.type.lock()}) { 209 if (const auto event_type{evt.type.lock()}) {
209 basic_lock.unlock(); 210 basic_lock.unlock();
@@ -219,16 +220,16 @@ std::optional<s64> CoreTiming::Advance() {
219 ? new_schedule_time.value().count() 220 ? new_schedule_time.value().count()
220 : evt.reschedule_time}; 221 : evt.reschedule_time};
221 222
222 // If this event was scheduled into a pause, its time now is going to be way behind. 223 // If this event was scheduled into a pause, its time now is going to be way
223 // Re-set this event to continue from the end of the pause. 224 // behind. Re-set this event to continue from the end of the pause.
224 auto next_time{evt.time + next_schedule_time}; 225 auto next_time{evt.time + next_schedule_time};
225 if (evt.time < pause_end_time) { 226 if (evt.time < pause_end_time) {
226 next_time = pause_end_time + next_schedule_time; 227 next_time = pause_end_time + next_schedule_time;
227 } 228 }
228 229
229 event_queue.emplace_back( 230 auto h{event_queue.emplace(Event{next_time, event_fifo_id++, evt.user_data,
230 Event{next_time, event_fifo_id++, evt.user_data, evt.type, next_schedule_time}); 231 evt.type, next_schedule_time})};
231 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); 232 (*h).handle = h;
232 } 233 }
233 } 234 }
234 235
@@ -236,7 +237,7 @@ std::optional<s64> CoreTiming::Advance() {
236 } 237 }
237 238
238 if (!event_queue.empty()) { 239 if (!event_queue.empty()) {
239 return event_queue.front().time; 240 return event_queue.top().time;
240 } else { 241 } else {
241 return std::nullopt; 242 return std::nullopt;
242 } 243 }
@@ -274,7 +275,8 @@ void CoreTiming::ThreadLoop() {
274#endif 275#endif
275 } 276 }
276 } else { 277 } else {
277 // Queue is empty, wait until another event is scheduled and signals us to continue. 278 // Queue is empty, wait until another event is scheduled and signals us to
279 // continue.
278 wait_set = true; 280 wait_set = true;
279 event.Wait(); 281 event.Wait();
280 } 282 }
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index c20e906fb..26a8b93a7 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -11,7 +11,8 @@
11#include <optional> 11#include <optional>
12#include <string> 12#include <string>
13#include <thread> 13#include <thread>
14#include <vector> 14
15#include <boost/heap/fibonacci_heap.hpp>
15 16
16#include "common/common_types.h" 17#include "common/common_types.h"
17#include "common/thread.h" 18#include "common/thread.h"
@@ -151,11 +152,10 @@ private:
151 s64 timer_resolution_ns; 152 s64 timer_resolution_ns;
152#endif 153#endif
153 154
154 // The queue is a min-heap using std::make_heap/push_heap/pop_heap. 155 using heap_t =
155 // We don't use std::priority_queue because we need to be able to serialize, unserialize and 156 boost::heap::fibonacci_heap<CoreTiming::Event, boost::heap::compare<std::greater<>>>;
156 // erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't 157
157 // accommodated by the standard adaptor class. 158 heap_t event_queue;
158 std::vector<Event> event_queue;
159 u64 event_fifo_id = 0; 159 u64 event_fifo_id = 0;
160 160
161 std::shared_ptr<EventType> ev_lost; 161 std::shared_ptr<EventType> ev_lost;