Core: Change CoreTiming event key from int to EventType*

Replace 'int' keys with something that carries type information.
Performance is neutral.
This commit is contained in:
EmptyChaos 2016-09-01 10:54:18 +00:00
parent f15e4fb35e
commit aa16282516
18 changed files with 73 additions and 85 deletions

View File

@ -6,6 +6,7 @@
#include <cinttypes> #include <cinttypes>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <unordered_map>
#include <vector> #include <vector>
#include "Common/Assert.h" #include "Common/Assert.h"
@ -28,16 +29,14 @@ namespace CoreTiming
struct EventType struct EventType
{ {
TimedCallback callback; TimedCallback callback;
std::string name; const std::string* name;
}; };
static std::vector<EventType> s_event_types;
struct Event struct Event
{ {
s64 time; s64 time;
u64 userdata; u64 userdata;
int type; EventType* type;
}; };
constexpr bool operator>(const Event& left, const Event& right) constexpr bool operator>(const Event& left, const Event& right)
@ -49,6 +48,10 @@ constexpr bool operator<(const Event& left, const Event& right)
return left.time < right.time; return left.time < right.time;
} }
// 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> s_event_types;
// STATE_TO_SAVE // STATE_TO_SAVE
// The queue is a min-heap using std::make_heap/push_heap/pop_heap. // 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 // We don't use std::priority_queue because we need to be able to serialize, unserialize and
@ -74,7 +77,7 @@ s64 g_global_timer;
u64 g_fake_TB_start_value; u64 g_fake_TB_start_value;
u64 g_fake_TB_start_ticks; u64 g_fake_TB_start_ticks;
static int s_ev_lost; static EventType* s_ev_lost = nullptr;
static void EmptyTimedCallback(u64 userdata, s64 cyclesLate) static void EmptyTimedCallback(u64 userdata, s64 cyclesLate)
{ {
@ -97,38 +100,25 @@ static int CyclesToDowncount(int cycles)
return static_cast<int>(cycles * s_last_OC_factor); return static_cast<int>(cycles * s_last_OC_factor);
} }
int RegisterEvent(const std::string& name, TimedCallback callback) EventType* RegisterEvent(const std::string& name, TimedCallback callback)
{ {
EventType type;
type.name = name;
type.callback = callback;
// check for existing type with same name. // check for existing type with same name.
// we want event type names to remain unique so that we can use them for serialization. // we want event type names to remain unique so that we can use them for serialization.
for (auto& event_type : s_event_types) _assert_msg_(POWERPC, s_event_types.find(name) == s_event_types.end(),
{ "CoreTiming Event \"%s\" is already registered. Events should only be registered "
if (name == event_type.name) "during Init to avoid breaking save states.",
{ name.c_str());
WARN_LOG(
POWERPC,
"Discarded old event type \"%s\" because a new type with the same name was registered.",
name.c_str());
// we don't know if someone might be holding on to the type index,
// so we gut the old event type instead of actually removing it.
event_type.name = "_discarded_event";
event_type.callback = &EmptyTimedCallback;
}
}
s_event_types.push_back(type); auto info = s_event_types.emplace(name, EventType{callback, nullptr});
return static_cast<int>(s_event_types.size() - 1); EventType* event_type = &info.first->second;
event_type->name = &info.first->first;
return event_type;
} }
void UnregisterAllEvents() void UnregisterAllEvents()
{ {
_assert_msg_(POWERPC, s_event_queue.empty(), "Cannot unregister events with events pending"); _assert_msg_(POWERPC, s_event_queue.empty(), "Cannot unregister events with events pending");
s_event_types.clear(); s_event_types.clear();
s_event_types.shrink_to_fit();
} }
void Init() void Init()
@ -179,16 +169,15 @@ void DoState(PointerWrap& p)
// so, we savestate the event's type's name, and derive ev.type from that when loading. // so, we savestate the event's type's name, and derive ev.type from that when loading.
std::string name; std::string name;
if (pw.GetMode() != PointerWrap::MODE_READ) if (pw.GetMode() != PointerWrap::MODE_READ)
name = s_event_types[ev.type].name; name = *ev.type->name;
pw.Do(name); pw.Do(name);
if (pw.GetMode() == PointerWrap::MODE_READ) if (pw.GetMode() == PointerWrap::MODE_READ)
{ {
auto itr = std::find_if(s_event_types.begin(), s_event_types.end(), auto itr = s_event_types.find(name);
[&](const EventType& evt) { return evt.name == name; });
if (itr != s_event_types.end()) if (itr != s_event_types.end())
{ {
ev.type = static_cast<int>(itr - s_event_types.begin()); ev.type = &itr->second;
} }
else else
{ {
@ -231,8 +220,10 @@ void ClearPendingEvents()
s_event_queue.clear(); s_event_queue.clear();
} }
void ScheduleEvent(s64 cycles_into_future, int event_type, u64 userdata, FromThread from) void ScheduleEvent(s64 cycles_into_future, EventType* event_type, u64 userdata, FromThread from)
{ {
_assert_msg_(POWERPC, event_type, "Event type is nullptr, will crash now.");
bool from_cpu_thread; bool from_cpu_thread;
if (from == FromThread::ANY) if (from == FromThread::ANY)
{ {
@ -262,7 +253,7 @@ void ScheduleEvent(s64 cycles_into_future, int event_type, u64 userdata, FromThr
{ {
ERROR_LOG(POWERPC, "Someone scheduled an off-thread \"%s\" event while netplay or " ERROR_LOG(POWERPC, "Someone scheduled an off-thread \"%s\" event while netplay or "
"movie play/record was active. This is likely to cause a desync.", "movie play/record was active. This is likely to cause a desync.",
s_event_types[event_type].name.c_str()); event_type->name->c_str());
} }
std::lock_guard<std::mutex> lk(s_ts_write_lock); std::lock_guard<std::mutex> lk(s_ts_write_lock);
@ -270,7 +261,7 @@ void ScheduleEvent(s64 cycles_into_future, int event_type, u64 userdata, FromThr
} }
} }
void RemoveEvent(int event_type) void RemoveEvent(EventType* event_type)
{ {
auto itr = std::remove_if(s_event_queue.begin(), s_event_queue.end(), auto itr = std::remove_if(s_event_queue.begin(), s_event_queue.end(),
[&](const Event& e) { return e.type == event_type; }); [&](const Event& e) { return e.type == event_type; });
@ -283,7 +274,7 @@ void RemoveEvent(int event_type)
} }
} }
void RemoveAllEvents(int event_type) void RemoveAllEvents(EventType* event_type)
{ {
MoveEvents(); MoveEvents();
RemoveEvent(event_type); RemoveEvent(event_type);
@ -328,7 +319,7 @@ void Advance()
s_event_queue.pop_back(); s_event_queue.pop_back();
// NOTICE_LOG(POWERPC, "[Scheduler] %-20s (%lld, %lld)", evt.type->name->c_str(), // NOTICE_LOG(POWERPC, "[Scheduler] %-20s (%lld, %lld)", evt.type->name->c_str(),
// g_global_timer, evt.time); // g_global_timer, evt.time);
s_event_types[evt.type].callback(evt.userdata, g_global_timer - evt.time); evt.type->callback(evt.userdata, g_global_timer - evt.time);
} }
s_is_global_timer_sane = false; s_is_global_timer_sane = false;
@ -355,10 +346,8 @@ void LogPendingEvents()
std::sort(clone.begin(), clone.end()); std::sort(clone.begin(), clone.end());
for (const Event& ev : clone) for (const Event& ev : clone)
{ {
INFO_LOG(POWERPC, "PENDING: Now: %" PRId64 " Pending: %" PRId64 " Type: %s (%d)", INFO_LOG(POWERPC, "PENDING: Now: %" PRId64 " Pending: %" PRId64 " Type: %s", g_global_timer,
g_global_timer, ev.time, ev.time, ev.type->name->c_str());
ev.type < s_event_types.size() ? s_event_types[ev.type].name.c_str() : "<INVALID>",
ev.type);
} }
} }
@ -385,17 +374,8 @@ std::string GetScheduledEventsSummary()
std::sort(clone.begin(), clone.end()); std::sort(clone.begin(), clone.end());
for (const Event& ev : clone) for (const Event& ev : clone)
{ {
unsigned int t = ev.type; text += StringFromFormat("%s : %" PRIi64 " %016" PRIx64 "\n", ev.type->name->c_str(), ev.time,
if (t >= s_event_types.size()) ev.userdata);
{
PanicAlertT("Invalid event type %i", t);
continue;
}
const std::string& name = s_event_types[ev.type].name;
text +=
StringFromFormat("%s : %" PRIi64 " %016" PRIx64 "\n", name.c_str(), ev.time, ev.userdata);
} }
return text; return text;
} }

View File

@ -43,9 +43,11 @@ u64 GetIdleTicks();
void DoState(PointerWrap& p); void DoState(PointerWrap& p);
struct EventType;
// Returns the event_type identifier. if name is not unique, an existing event_type will be // Returns the event_type identifier. if name is not unique, an existing event_type will be
// discarded. // discarded.
int RegisterEvent(const std::string& name, TimedCallback callback); EventType* RegisterEvent(const std::string& name, TimedCallback callback);
void UnregisterAllEvents(); void UnregisterAllEvents();
enum class FromThread enum class FromThread
@ -58,12 +60,12 @@ enum class FromThread
}; };
// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from savestates. // userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from savestates.
void ScheduleEvent(s64 cycles_into_future, int event_type, u64 userdata = 0, void ScheduleEvent(s64 cycles_into_future, EventType* event_type, u64 userdata = 0,
FromThread from = FromThread::CPU); FromThread from = FromThread::CPU);
// We only permit one event of each type in the queue at a time. // We only permit one event of each type in the queue at a time.
void RemoveEvent(int event_type); void RemoveEvent(EventType* event_type);
void RemoveAllEvents(int event_type); void RemoveAllEvents(EventType* event_type);
void Advance(); void Advance();
void MoveEvents(); void MoveEvents();

View File

@ -130,7 +130,7 @@ static void GenerateAudioInterrupt();
static void UpdateInterrupts(); static void UpdateInterrupts();
static void IncreaseSampleCount(const u32 _uAmount); static void IncreaseSampleCount(const u32 _uAmount);
static int GetAIPeriod(); static int GetAIPeriod();
static int et_AI; static CoreTiming::EventType* et_AI;
static void Update(u64 userdata, s64 cyclesLate); static void Update(u64 userdata, s64 cyclesLate);
void Init() void Init()

View File

@ -188,8 +188,8 @@ static void UpdateInterrupts();
static void Do_ARAM_DMA(); static void Do_ARAM_DMA();
static void GenerateDSPInterrupt(u64 DSPIntType, s64 cyclesLate = 0); static void GenerateDSPInterrupt(u64 DSPIntType, s64 cyclesLate = 0);
static int et_GenerateDSPInterrupt; static CoreTiming::EventType* et_GenerateDSPInterrupt;
static int et_CompleteARAM; static CoreTiming::EventType* et_CompleteARAM;
static void CompleteARAM(u64 userdata, s64 cyclesLate) static void CompleteARAM(u64 userdata, s64 cyclesLate)
{ {

View File

@ -238,14 +238,14 @@ static u32 s_error_code = 0;
static bool s_disc_inside = false; static bool s_disc_inside = false;
static bool s_stream = false; static bool s_stream = false;
static bool s_stop_at_track_end = false; static bool s_stop_at_track_end = false;
static int s_finish_executing_command = 0; static CoreTiming::EventType* s_finish_executing_command;
static int s_dtk = 0; static CoreTiming::EventType* s_dtk;
static u64 s_last_read_offset; static u64 s_last_read_offset;
static u64 s_last_read_time; static u64 s_last_read_time;
static int s_eject_disc; static CoreTiming::EventType* s_eject_disc;
static int s_insert_disc; static CoreTiming::EventType* s_insert_disc;
static void EjectDiscCallback(u64 userdata, s64 cyclesLate); static void EjectDiscCallback(u64 userdata, s64 cyclesLate);
static void InsertDiscCallback(u64 userdata, s64 cyclesLate); static void InsertDiscCallback(u64 userdata, s64 cyclesLate);

View File

@ -30,7 +30,7 @@ namespace DVDThread
static void DVDThread(); static void DVDThread();
static void FinishRead(u64 userdata, s64 cycles_late); static void FinishRead(u64 userdata, s64 cycles_late);
static int s_finish_read; static CoreTiming::EventType* s_finish_read;
static std::thread s_dvd_thread; static std::thread s_dvd_thread;
static Common::Event s_dvd_thread_start_working; static Common::Event s_dvd_thread_start_working;

View File

@ -23,8 +23,8 @@ bool g_SRAM_netplay_initialized = false;
namespace ExpansionInterface namespace ExpansionInterface
{ {
static int changeDevice; static CoreTiming::EventType* changeDevice;
static int updateInterrupts; static CoreTiming::EventType* updateInterrupts;
static std::array<std::unique_ptr<CEXIChannel>, MAX_EXI_CHANNELS> g_Channels; static std::array<std::unique_ptr<CEXIChannel>, MAX_EXI_CHANNELS> g_Channels;

View File

@ -9,6 +9,10 @@
#include "Core/HW/EXI_Device.h" #include "Core/HW/EXI_Device.h"
namespace CoreTiming
{
struct EventType;
}
class MemoryCardBase; class MemoryCardBase;
class PointerWrap; class PointerWrap;
@ -67,7 +71,8 @@ private:
}; };
int card_index; int card_index;
int et_cmd_done, et_transfer_complete; CoreTiming::EventType* et_cmd_done = nullptr;
CoreTiming::EventType* et_transfer_complete = nullptr;
//! memory card state //! memory card state
// STATE_TO_SAVE // STATE_TO_SAVE

View File

@ -31,10 +31,10 @@ static u32 m_FlipperRev;
static u32 m_Unknown; static u32 m_Unknown;
// ID and callback for scheduling reset button presses/releases // ID and callback for scheduling reset button presses/releases
static int toggleResetButton; static CoreTiming::EventType* toggleResetButton;
static void ToggleResetButtonCallback(u64 userdata, s64 cyclesLate); static void ToggleResetButtonCallback(u64 userdata, s64 cyclesLate);
static int iosNotifyResetButton; static CoreTiming::EventType* iosNotifyResetButton;
static void IOSNotifyResetButtonCallback(u64 userdata, s64 cyclesLate); static void IOSNotifyResetButtonCallback(u64 userdata, s64 cyclesLate);
// Let the PPC know that an external exception is set/cleared // Let the PPC know that an external exception is set/cleared

View File

@ -23,8 +23,8 @@
namespace SerialInterface namespace SerialInterface
{ {
static int changeDevice; static CoreTiming::EventType* changeDevice;
static int et_transfer_pending; static CoreTiming::EventType* et_transfer_pending;
static void RunSIBuffer(u64 userdata, s64 cyclesLate); static void RunSIBuffer(u64 userdata, s64 cyclesLate);
static void UpdateInterrupts(); static void UpdateInterrupts();

View File

@ -64,13 +64,14 @@ IPC_HLE_PERIOD: For the Wiimote this is the call schedule:
namespace SystemTimers namespace SystemTimers
{ {
static int et_Dec; static CoreTiming::EventType* et_Dec;
static int et_VI; static CoreTiming::EventType* et_VI;
static int et_AudioDMA; static CoreTiming::EventType* et_AudioDMA;
static int et_DSP; static CoreTiming::EventType* et_DSP;
static int et_IPC_HLE; static CoreTiming::EventType* et_IPC_HLE;
static int et_PatchEngine; // PatchEngine updates every 1/60th of a second by default // PatchEngine updates every 1/60th of a second by default
static int et_Throttle; static CoreTiming::EventType* et_PatchEngine;
static CoreTiming::EventType* et_Throttle;
static u32 s_cpu_core_clock = 486000000u; // 486 mhz (its not 485, stop bugging me!) static u32 s_cpu_core_clock = 486000000u; // 486 mhz (its not 485, stop bugging me!)

View File

@ -98,7 +98,7 @@ static u32 arm_irq_masks;
static u32 sensorbar_power; // do we need to care about this? static u32 sensorbar_power; // do we need to care about this?
static int updateInterrupts; static CoreTiming::EventType* updateInterrupts;
static void UpdateInterrupts(u64 = 0, s64 cyclesLate = 0); static void UpdateInterrupts(u64 = 0, s64 cyclesLate = 0);
void DoState(PointerWrap& p) void DoState(PointerWrap& p)

View File

@ -76,8 +76,8 @@ static ipc_msg_queue request_queue; // ppc -> arm
static ipc_msg_queue reply_queue; // arm -> ppc static ipc_msg_queue reply_queue; // arm -> ppc
static ipc_msg_queue ack_queue; // arm -> ppc static ipc_msg_queue ack_queue; // arm -> ppc
static int event_enqueue; static CoreTiming::EventType* event_enqueue;
static int event_sdio_notify; static CoreTiming::EventType* event_sdio_notify;
static u64 last_reply_time; static u64 last_reply_time;

View File

@ -15,7 +15,7 @@
#include "Core/MemoryWatcher.h" #include "Core/MemoryWatcher.h"
static std::unique_ptr<MemoryWatcher> s_memory_watcher; static std::unique_ptr<MemoryWatcher> s_memory_watcher;
static int s_event; static CoreTiming::EventType* s_event;
static const int MW_RATE = 600; // Steps per second static const int MW_RATE = 600; // Steps per second
static void MWCallback(u64 userdata, s64 cyclesLate) static void MWCallback(u64 userdata, s64 cyclesLate)

View File

@ -36,7 +36,7 @@ BreakPoints breakpoints;
MemChecks memchecks; MemChecks memchecks;
PPCDebugInterface debug_interface; PPCDebugInterface debug_interface;
static int s_invalidate_cache_thread_safe; static CoreTiming::EventType* s_invalidate_cache_thread_safe;
static void InvalidateCacheThreadSafe(u64 userdata, s64 cyclesLate) static void InvalidateCacheThreadSafe(u64 userdata, s64 cyclesLate)
{ {
ppcState.iCache.Invalidate(static_cast<u32>(userdata)); ppcState.iCache.Invalidate(static_cast<u32>(userdata));

View File

@ -21,7 +21,7 @@
namespace CommandProcessor namespace CommandProcessor
{ {
static int et_UpdateInterrupts; static CoreTiming::EventType* et_UpdateInterrupts;
// TODO(ector): Warn on bbox read/write // TODO(ector): Warn on bbox read/write

View File

@ -48,7 +48,7 @@ static u8* s_fifo_aux_read_ptr;
static bool s_use_deterministic_gpu_thread; static bool s_use_deterministic_gpu_thread;
static u64 s_last_sync_gpu_tick; static u64 s_last_sync_gpu_tick;
static int s_event_sync_gpu; static CoreTiming::EventType* s_event_sync_gpu;
// STATE_TO_SAVE // STATE_TO_SAVE
static u8* s_video_buffer; static u8* s_video_buffer;

View File

@ -100,7 +100,7 @@ static bool s_event_raised;
static bool s_signal_token_interrupt; static bool s_signal_token_interrupt;
static bool s_signal_finish_interrupt; static bool s_signal_finish_interrupt;
static int et_SetTokenFinishOnMainThread; static CoreTiming::EventType* et_SetTokenFinishOnMainThread;
enum enum
{ {