diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/core_timing.cpp | 56 | ||||
| -rw-r--r-- | src/core/core_timing.h | 12 |
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; |