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 <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;
}

View File

@ -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();

View File

@ -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()

View File

@ -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)
{

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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!)

View File

@ -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)

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 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;

View File

@ -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)

View File

@ -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));

View File

@ -21,7 +21,7 @@
namespace CommandProcessor
{
static int et_UpdateInterrupts;
static CoreTiming::EventType* et_UpdateInterrupts;
// 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 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;

View File

@ -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
{