diff options
| author | 2023-09-13 22:49:41 +0100 | |
|---|---|---|
| committer | 2023-09-16 07:42:45 +0100 | |
| commit | 3ad7eec9de119afa6f5ca2db073070a8cdf62f69 (patch) | |
| tree | 4705cadc186386a69697ea3de023a75e8eec2b41 /src/core/core_timing.cpp | |
| parent | vcpkg: Add boost.heap (diff) | |
| download | yuzu-3ad7eec9de119afa6f5ca2db073070a8cdf62f69.tar.gz yuzu-3ad7eec9de119afa6f5ca2db073070a8cdf62f69.tar.xz yuzu-3ad7eec9de119afa6f5ca2db073070a8cdf62f69.zip | |
core_timing: Use a fibonacci heap
Diffstat (limited to 'src/core/core_timing.cpp')
| -rw-r--r-- | src/core/core_timing.cpp | 56 |
1 files changed, 29 insertions, 27 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 | } |