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:
parent
f15e4fb35e
commit
aa16282516
|
@ -6,6 +6,7 @@
|
|||
#include <cinttypes>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/Assert.h"
|
||||
|
@ -28,16 +29,14 @@ namespace CoreTiming
|
|||
struct EventType
|
||||
{
|
||||
TimedCallback callback;
|
||||
std::string name;
|
||||
const std::string* name;
|
||||
};
|
||||
|
||||
static std::vector<EventType> s_event_types;
|
||||
|
||||
struct Event
|
||||
{
|
||||
s64 time;
|
||||
u64 userdata;
|
||||
int type;
|
||||
EventType* type;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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
|
||||
// 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
|
||||
|
@ -74,7 +77,7 @@ s64 g_global_timer;
|
|||
u64 g_fake_TB_start_value;
|
||||
u64 g_fake_TB_start_ticks;
|
||||
|
||||
static int s_ev_lost;
|
||||
static EventType* s_ev_lost = nullptr;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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.
|
||||
// we want event type names to remain unique so that we can use them for serialization.
|
||||
for (auto& event_type : s_event_types)
|
||||
{
|
||||
if (name == event_type.name)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
_assert_msg_(POWERPC, s_event_types.find(name) == s_event_types.end(),
|
||||
"CoreTiming Event \"%s\" is already registered. Events should only be registered "
|
||||
"during Init to avoid breaking save states.",
|
||||
name.c_str());
|
||||
|
||||
s_event_types.push_back(type);
|
||||
return static_cast<int>(s_event_types.size() - 1);
|
||||
auto info = s_event_types.emplace(name, EventType{callback, nullptr});
|
||||
EventType* event_type = &info.first->second;
|
||||
event_type->name = &info.first->first;
|
||||
return event_type;
|
||||
}
|
||||
|
||||
void UnregisterAllEvents()
|
||||
{
|
||||
_assert_msg_(POWERPC, s_event_queue.empty(), "Cannot unregister events with events pending");
|
||||
s_event_types.clear();
|
||||
s_event_types.shrink_to_fit();
|
||||
}
|
||||
|
||||
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.
|
||||
std::string name;
|
||||
if (pw.GetMode() != PointerWrap::MODE_READ)
|
||||
name = s_event_types[ev.type].name;
|
||||
name = *ev.type->name;
|
||||
|
||||
pw.Do(name);
|
||||
if (pw.GetMode() == PointerWrap::MODE_READ)
|
||||
{
|
||||
auto itr = std::find_if(s_event_types.begin(), s_event_types.end(),
|
||||
[&](const EventType& evt) { return evt.name == name; });
|
||||
auto itr = s_event_types.find(name);
|
||||
if (itr != s_event_types.end())
|
||||
{
|
||||
ev.type = static_cast<int>(itr - s_event_types.begin());
|
||||
ev.type = &itr->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -231,8 +220,10 @@ void ClearPendingEvents()
|
|||
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;
|
||||
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 "
|
||||
"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);
|
||||
|
@ -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(),
|
||||
[&](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();
|
||||
RemoveEvent(event_type);
|
||||
|
@ -328,7 +319,7 @@ void Advance()
|
|||
s_event_queue.pop_back();
|
||||
// NOTICE_LOG(POWERPC, "[Scheduler] %-20s (%lld, %lld)", evt.type->name->c_str(),
|
||||
// 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;
|
||||
|
@ -355,10 +346,8 @@ void LogPendingEvents()
|
|||
std::sort(clone.begin(), clone.end());
|
||||
for (const Event& ev : clone)
|
||||
{
|
||||
INFO_LOG(POWERPC, "PENDING: Now: %" PRId64 " Pending: %" PRId64 " Type: %s (%d)",
|
||||
g_global_timer, ev.time,
|
||||
ev.type < s_event_types.size() ? s_event_types[ev.type].name.c_str() : "<INVALID>",
|
||||
ev.type);
|
||||
INFO_LOG(POWERPC, "PENDING: Now: %" PRId64 " Pending: %" PRId64 " Type: %s", g_global_timer,
|
||||
ev.time, ev.type->name->c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -385,17 +374,8 @@ std::string GetScheduledEventsSummary()
|
|||
std::sort(clone.begin(), clone.end());
|
||||
for (const Event& ev : clone)
|
||||
{
|
||||
unsigned int t = ev.type;
|
||||
if (t >= s_event_types.size())
|
||||
{
|
||||
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);
|
||||
text += StringFromFormat("%s : %" PRIi64 " %016" PRIx64 "\n", ev.type->name->c_str(), ev.time,
|
||||
ev.userdata);
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
|
|
@ -43,9 +43,11 @@ u64 GetIdleTicks();
|
|||
|
||||
void DoState(PointerWrap& p);
|
||||
|
||||
struct EventType;
|
||||
|
||||
// Returns the event_type identifier. if name is not unique, an existing event_type will be
|
||||
// discarded.
|
||||
int RegisterEvent(const std::string& name, TimedCallback callback);
|
||||
EventType* RegisterEvent(const std::string& name, TimedCallback callback);
|
||||
void UnregisterAllEvents();
|
||||
|
||||
enum class FromThread
|
||||
|
@ -58,12 +60,12 @@ enum class FromThread
|
|||
};
|
||||
|
||||
// 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);
|
||||
|
||||
// We only permit one event of each type in the queue at a time.
|
||||
void RemoveEvent(int event_type);
|
||||
void RemoveAllEvents(int event_type);
|
||||
void RemoveEvent(EventType* event_type);
|
||||
void RemoveAllEvents(EventType* event_type);
|
||||
void Advance();
|
||||
void MoveEvents();
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ static void GenerateAudioInterrupt();
|
|||
static void UpdateInterrupts();
|
||||
static void IncreaseSampleCount(const u32 _uAmount);
|
||||
static int GetAIPeriod();
|
||||
static int et_AI;
|
||||
static CoreTiming::EventType* et_AI;
|
||||
static void Update(u64 userdata, s64 cyclesLate);
|
||||
|
||||
void Init()
|
||||
|
|
|
@ -188,8 +188,8 @@ static void UpdateInterrupts();
|
|||
static void Do_ARAM_DMA();
|
||||
static void GenerateDSPInterrupt(u64 DSPIntType, s64 cyclesLate = 0);
|
||||
|
||||
static int et_GenerateDSPInterrupt;
|
||||
static int et_CompleteARAM;
|
||||
static CoreTiming::EventType* et_GenerateDSPInterrupt;
|
||||
static CoreTiming::EventType* et_CompleteARAM;
|
||||
|
||||
static void CompleteARAM(u64 userdata, s64 cyclesLate)
|
||||
{
|
||||
|
|
|
@ -238,14 +238,14 @@ static u32 s_error_code = 0;
|
|||
static bool s_disc_inside = false;
|
||||
static bool s_stream = false;
|
||||
static bool s_stop_at_track_end = false;
|
||||
static int s_finish_executing_command = 0;
|
||||
static int s_dtk = 0;
|
||||
static CoreTiming::EventType* s_finish_executing_command;
|
||||
static CoreTiming::EventType* s_dtk;
|
||||
|
||||
static u64 s_last_read_offset;
|
||||
static u64 s_last_read_time;
|
||||
|
||||
static int s_eject_disc;
|
||||
static int s_insert_disc;
|
||||
static CoreTiming::EventType* s_eject_disc;
|
||||
static CoreTiming::EventType* s_insert_disc;
|
||||
|
||||
static void EjectDiscCallback(u64 userdata, s64 cyclesLate);
|
||||
static void InsertDiscCallback(u64 userdata, s64 cyclesLate);
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace DVDThread
|
|||
static void DVDThread();
|
||||
|
||||
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 Common::Event s_dvd_thread_start_working;
|
||||
|
|
|
@ -23,8 +23,8 @@ bool g_SRAM_netplay_initialized = false;
|
|||
|
||||
namespace ExpansionInterface
|
||||
{
|
||||
static int changeDevice;
|
||||
static int updateInterrupts;
|
||||
static CoreTiming::EventType* changeDevice;
|
||||
static CoreTiming::EventType* updateInterrupts;
|
||||
|
||||
static std::array<std::unique_ptr<CEXIChannel>, MAX_EXI_CHANNELS> g_Channels;
|
||||
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
|
||||
#include "Core/HW/EXI_Device.h"
|
||||
|
||||
namespace CoreTiming
|
||||
{
|
||||
struct EventType;
|
||||
}
|
||||
class MemoryCardBase;
|
||||
class PointerWrap;
|
||||
|
||||
|
@ -67,7 +71,8 @@ private:
|
|||
};
|
||||
|
||||
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
|
||||
|
||||
// STATE_TO_SAVE
|
||||
|
|
|
@ -31,10 +31,10 @@ static u32 m_FlipperRev;
|
|||
static u32 m_Unknown;
|
||||
|
||||
// ID and callback for scheduling reset button presses/releases
|
||||
static int toggleResetButton;
|
||||
static CoreTiming::EventType* toggleResetButton;
|
||||
static void ToggleResetButtonCallback(u64 userdata, s64 cyclesLate);
|
||||
|
||||
static int iosNotifyResetButton;
|
||||
static CoreTiming::EventType* iosNotifyResetButton;
|
||||
static void IOSNotifyResetButtonCallback(u64 userdata, s64 cyclesLate);
|
||||
|
||||
// Let the PPC know that an external exception is set/cleared
|
||||
|
|
|
@ -23,8 +23,8 @@
|
|||
|
||||
namespace SerialInterface
|
||||
{
|
||||
static int changeDevice;
|
||||
static int et_transfer_pending;
|
||||
static CoreTiming::EventType* changeDevice;
|
||||
static CoreTiming::EventType* et_transfer_pending;
|
||||
|
||||
static void RunSIBuffer(u64 userdata, s64 cyclesLate);
|
||||
static void UpdateInterrupts();
|
||||
|
|
|
@ -64,13 +64,14 @@ IPC_HLE_PERIOD: For the Wiimote this is the call schedule:
|
|||
|
||||
namespace SystemTimers
|
||||
{
|
||||
static int et_Dec;
|
||||
static int et_VI;
|
||||
static int et_AudioDMA;
|
||||
static int et_DSP;
|
||||
static int et_IPC_HLE;
|
||||
static int et_PatchEngine; // PatchEngine updates every 1/60th of a second by default
|
||||
static int et_Throttle;
|
||||
static CoreTiming::EventType* et_Dec;
|
||||
static CoreTiming::EventType* et_VI;
|
||||
static CoreTiming::EventType* et_AudioDMA;
|
||||
static CoreTiming::EventType* et_DSP;
|
||||
static CoreTiming::EventType* et_IPC_HLE;
|
||||
// PatchEngine updates every 1/60th of a second by default
|
||||
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!)
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ static u32 arm_irq_masks;
|
|||
|
||||
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);
|
||||
|
||||
void DoState(PointerWrap& p)
|
||||
|
|
|
@ -76,8 +76,8 @@ static ipc_msg_queue request_queue; // ppc -> arm
|
|||
static ipc_msg_queue reply_queue; // arm -> ppc
|
||||
static ipc_msg_queue ack_queue; // arm -> ppc
|
||||
|
||||
static int event_enqueue;
|
||||
static int event_sdio_notify;
|
||||
static CoreTiming::EventType* event_enqueue;
|
||||
static CoreTiming::EventType* event_sdio_notify;
|
||||
|
||||
static u64 last_reply_time;
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "Core/MemoryWatcher.h"
|
||||
|
||||
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 void MWCallback(u64 userdata, s64 cyclesLate)
|
||||
|
|
|
@ -36,7 +36,7 @@ BreakPoints breakpoints;
|
|||
MemChecks memchecks;
|
||||
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)
|
||||
{
|
||||
ppcState.iCache.Invalidate(static_cast<u32>(userdata));
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
namespace CommandProcessor
|
||||
{
|
||||
static int et_UpdateInterrupts;
|
||||
static CoreTiming::EventType* et_UpdateInterrupts;
|
||||
|
||||
// TODO(ector): Warn on bbox read/write
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ static u8* s_fifo_aux_read_ptr;
|
|||
static bool s_use_deterministic_gpu_thread;
|
||||
|
||||
static u64 s_last_sync_gpu_tick;
|
||||
static int s_event_sync_gpu;
|
||||
static CoreTiming::EventType* s_event_sync_gpu;
|
||||
|
||||
// STATE_TO_SAVE
|
||||
static u8* s_video_buffer;
|
||||
|
|
|
@ -100,7 +100,7 @@ static bool s_event_raised;
|
|||
static bool s_signal_token_interrupt;
|
||||
static bool s_signal_finish_interrupt;
|
||||
|
||||
static int et_SetTokenFinishOnMainThread;
|
||||
static CoreTiming::EventType* et_SetTokenFinishOnMainThread;
|
||||
|
||||
enum
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue