summaryrefslogtreecommitdiffstats
path: root/src/core/core_timing.cpp
diff options
context:
space:
mode:
authorLioncash <mathew1800@gmail.com>2019-02-14 18:42:58 +0100
committerLioncash <mathew1800@gmail.com>2019-02-16 03:50:25 +0100
commitbd983414f643b734a1f8bebe3183723733344f72 (patch)
treebda0421458439e25cba9d772a6a79b56e473d72e /src/core/core_timing.cpp
parentMerge pull request #2113 from ReinUsesLisp/vulkan-base (diff)
downloadyuzu-bd983414f643b734a1f8bebe3183723733344f72.tar
yuzu-bd983414f643b734a1f8bebe3183723733344f72.tar.gz
yuzu-bd983414f643b734a1f8bebe3183723733344f72.tar.bz2
yuzu-bd983414f643b734a1f8bebe3183723733344f72.tar.lz
yuzu-bd983414f643b734a1f8bebe3183723733344f72.tar.xz
yuzu-bd983414f643b734a1f8bebe3183723733344f72.tar.zst
yuzu-bd983414f643b734a1f8bebe3183723733344f72.zip
Diffstat (limited to 'src/core/core_timing.cpp')
-rw-r--r--src/core/core_timing.cpp189
1 files changed, 80 insertions, 109 deletions
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 4ea00c277..a0dd5db24 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -8,94 +8,42 @@
#include <mutex>
#include <string>
#include <tuple>
-#include <unordered_map>
-#include <vector>
+
#include "common/assert.h"
#include "common/thread.h"
-#include "common/threadsafe_queue.h"
#include "core/core_timing_util.h"
namespace Core::Timing {
-static s64 global_timer;
-static int slice_length;
-static int downcount;
-
-struct EventType {
- TimedCallback callback;
- const std::string* name;
-};
+constexpr int MAX_SLICE_LENGTH = 20000;
-struct Event {
+struct CoreTiming::Event {
s64 time;
u64 fifo_order;
u64 userdata;
const EventType* type;
-};
-
-// Sort by time, unless the times are the same, in which case sort by the order added to the queue
-static bool operator>(const Event& left, const Event& right) {
- return std::tie(left.time, left.fifo_order) > std::tie(right.time, right.fifo_order);
-}
-
-static bool operator<(const Event& left, const Event& right) {
- return std::tie(left.time, left.fifo_order) < std::tie(right.time, right.fifo_order);
-}
-
-// unordered_map stores each element separately as a linked list node so pointers to elements
-// remain stable regardless of rehashes/resizing.
-static std::unordered_map<std::string, EventType> event_types;
-// The queue is a min-heap using std::make_heap/push_heap/pop_heap.
-// We don't use std::priority_queue because we need to be able to serialize, unserialize and
-// erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't accomodated
-// by the standard adaptor class.
-static std::vector<Event> event_queue;
-static u64 event_fifo_id;
-// the queue for storing the events from other threads threadsafe until they will be added
-// to the event_queue by the emu thread
-static Common::MPSCQueue<Event> ts_queue;
-
-// the queue for unscheduling the events from other threads threadsafe
-static Common::MPSCQueue<std::pair<const EventType*, u64>> unschedule_queue;
-
-constexpr int MAX_SLICE_LENGTH = 20000;
-
-static s64 idled_cycles;
-
-// Are we in a function that has been called from Advance()
-// If events are sheduled from a function that gets called from Advance(),
-// don't change slice_length and downcount.
-static bool is_global_timer_sane;
-
-static EventType* ev_lost = nullptr;
-
-EventType* RegisterEvent(const std::string& name, TimedCallback callback) {
- // check for existing type with same name.
- // we want event type names to remain unique so that we can use them for serialization.
- ASSERT_MSG(event_types.find(name) == event_types.end(),
- "CoreTiming Event \"{}\" is already registered. Events should only be registered "
- "during Init to avoid breaking save states.",
- name.c_str());
+ // Sort by time, unless the times are the same, in which case sort by
+ // the order added to the queue
+ friend bool operator>(const Event& left, const Event& right) {
+ return std::tie(left.time, left.fifo_order) > std::tie(right.time, right.fifo_order);
+ }
- auto info = event_types.emplace(name, EventType{callback, nullptr});
- EventType* event_type = &info.first->second;
- event_type->name = &info.first->first;
- return event_type;
-}
+ friend bool operator<(const Event& left, const Event& right) {
+ return std::tie(left.time, left.fifo_order) < std::tie(right.time, right.fifo_order);
+ }
+};
-void UnregisterAllEvents() {
- ASSERT_MSG(event_queue.empty(), "Cannot unregister events with events pending");
- event_types.clear();
-}
+CoreTiming::CoreTiming() = default;
+CoreTiming::~CoreTiming() = default;
-void Init() {
+void CoreTiming::Initialize() {
downcount = MAX_SLICE_LENGTH;
slice_length = MAX_SLICE_LENGTH;
global_timer = 0;
idled_cycles = 0;
- // The time between CoreTiming being intialized and the first call to Advance() is considered
+ // The time between CoreTiming being initialized and the first call to Advance() is considered
// the slice boundary between slice -1 and slice 0. Dispatcher loops must call Advance() before
// executing the first cycle of each slice to prepare the slice length and downcount for
// that slice.
@@ -107,50 +55,51 @@ void Init() {
ev_lost = RegisterEvent("_lost_event", empty_timed_callback);
}
-void Shutdown() {
+void CoreTiming::Shutdown() {
MoveEvents();
ClearPendingEvents();
UnregisterAllEvents();
}
-// This should only be called from the CPU thread. If you are calling
-// it from any other thread, you are doing something evil
-u64 GetTicks() {
- u64 ticks = static_cast<u64>(global_timer);
- if (!is_global_timer_sane) {
- ticks += slice_length - downcount;
- }
- return ticks;
-}
-
-void AddTicks(u64 ticks) {
- downcount -= static_cast<int>(ticks);
-}
+EventType* CoreTiming::RegisterEvent(const std::string& name, TimedCallback callback) {
+ // check for existing type with same name.
+ // we want event type names to remain unique so that we can use them for serialization.
+ ASSERT_MSG(event_types.find(name) == event_types.end(),
+ "CoreTiming Event \"{}\" is already registered. Events should only be registered "
+ "during Init to avoid breaking save states.",
+ name.c_str());
-u64 GetIdleTicks() {
- return static_cast<u64>(idled_cycles);
+ auto info = event_types.emplace(name, EventType{callback, nullptr});
+ EventType* event_type = &info.first->second;
+ event_type->name = &info.first->first;
+ return event_type;
}
-void ClearPendingEvents() {
- event_queue.clear();
+void CoreTiming::UnregisterAllEvents() {
+ ASSERT_MSG(event_queue.empty(), "Cannot unregister events with events pending");
+ event_types.clear();
}
-void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
+void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
ASSERT(event_type != nullptr);
- s64 timeout = GetTicks() + cycles_into_future;
+ const s64 timeout = GetTicks() + cycles_into_future;
+
// If this event needs to be scheduled before the next advance(), force one early
- if (!is_global_timer_sane)
+ if (!is_global_timer_sane) {
ForceExceptionCheck(cycles_into_future);
+ }
+
event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type});
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
}
-void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
+void CoreTiming::ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type,
+ u64 userdata) {
ts_queue.Push(Event{global_timer + cycles_into_future, 0, userdata, event_type});
}
-void UnscheduleEvent(const EventType* event_type, u64 userdata) {
- auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
+void CoreTiming::UnscheduleEvent(const EventType* event_type, u64 userdata) {
+ const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
return e.type == event_type && e.userdata == userdata;
});
@@ -161,13 +110,33 @@ void UnscheduleEvent(const EventType* event_type, u64 userdata) {
}
}
-void UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata) {
+void CoreTiming::UnscheduleEventThreadsafe(const EventType* event_type, u64 userdata) {
unschedule_queue.Push(std::make_pair(event_type, userdata));
}
-void RemoveEvent(const EventType* event_type) {
- auto itr = std::remove_if(event_queue.begin(), event_queue.end(),
- [&](const Event& e) { return e.type == event_type; });
+u64 CoreTiming::GetTicks() const {
+ u64 ticks = static_cast<u64>(global_timer);
+ if (!is_global_timer_sane) {
+ ticks += slice_length - downcount;
+ }
+ return ticks;
+}
+
+u64 CoreTiming::GetIdleTicks() const {
+ return static_cast<u64>(idled_cycles);
+}
+
+void CoreTiming::AddTicks(u64 ticks) {
+ downcount -= static_cast<int>(ticks);
+}
+
+void CoreTiming::ClearPendingEvents() {
+ event_queue.clear();
+}
+
+void CoreTiming::RemoveEvent(const EventType* event_type) {
+ const auto itr = std::remove_if(event_queue.begin(), event_queue.end(),
+ [&](const Event& e) { return e.type == event_type; });
// Removing random items breaks the invariant so we have to re-establish it.
if (itr != event_queue.end()) {
@@ -176,22 +145,24 @@ void RemoveEvent(const EventType* event_type) {
}
}
-void RemoveNormalAndThreadsafeEvent(const EventType* event_type) {
+void CoreTiming::RemoveNormalAndThreadsafeEvent(const EventType* event_type) {
MoveEvents();
RemoveEvent(event_type);
}
-void ForceExceptionCheck(s64 cycles) {
+void CoreTiming::ForceExceptionCheck(s64 cycles) {
cycles = std::max<s64>(0, cycles);
- if (downcount > cycles) {
- // downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int
- // here. Account for cycles already executed by adjusting the g.slice_length
- slice_length -= downcount - static_cast<int>(cycles);
- downcount = static_cast<int>(cycles);
+ if (downcount <= cycles) {
+ return;
}
+
+ // downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int
+ // here. Account for cycles already executed by adjusting the g.slice_length
+ slice_length -= downcount - static_cast<int>(cycles);
+ downcount = static_cast<int>(cycles);
}
-void MoveEvents() {
+void CoreTiming::MoveEvents() {
for (Event ev; ts_queue.Pop(ev);) {
ev.fifo_order = event_fifo_id++;
event_queue.emplace_back(std::move(ev));
@@ -199,13 +170,13 @@ void MoveEvents() {
}
}
-void Advance() {
+void CoreTiming::Advance() {
MoveEvents();
for (std::pair<const EventType*, u64> ev; unschedule_queue.Pop(ev);) {
UnscheduleEvent(ev.first, ev.second);
}
- int cycles_executed = slice_length - downcount;
+ const int cycles_executed = slice_length - downcount;
global_timer += cycles_executed;
slice_length = MAX_SLICE_LENGTH;
@@ -229,16 +200,16 @@ void Advance() {
downcount = slice_length;
}
-void Idle() {
+void CoreTiming::Idle() {
idled_cycles += downcount;
downcount = 0;
}
-std::chrono::microseconds GetGlobalTimeUs() {
+std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
return std::chrono::microseconds{GetTicks() * 1000000 / BASE_CLOCK_RATE};
}
-int GetDowncount() {
+int CoreTiming::GetDowncount() const {
return downcount;
}