core_timing.h
1 // Copyright 2008 Dolphin Emulator Project / 2017 Citra Emulator Project 2 // Licensed under GPLv2+ 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 /** 8 * This is a system to schedule events into the emulated machine's future. Time is measured 9 * in main CPU clock cycles. 10 * 11 * To schedule an event, you first have to register its type. This is where you pass in the 12 * callback. You then schedule events using the type id you get back. 13 * 14 * The int cyclesLate that the callbacks get is how many cycles late it was. 15 * So to schedule a new event on a regular basis: 16 * inside callback: 17 * ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever") 18 */ 19 20 #include <chrono> 21 #include <functional> 22 #include <limits> 23 #include <string> 24 #include <unordered_map> 25 #include <vector> 26 #include <boost/serialization/split_member.hpp> 27 #include <boost/serialization/vector.hpp> 28 #include "common/common_types.h" 29 #include "common/logging/log.h" 30 #include "common/threadsafe_queue.h" 31 #include "core/global.h" 32 33 // The timing we get from the assembly is 268,111,855.956 Hz 34 // It is possible that this number isn't just an integer because the compiler could have 35 // optimized the multiplication by a multiply-by-constant division. 36 // Rounding to the nearest integer should be fine 37 constexpr u64 BASE_CLOCK_RATE_ARM11 = 268111856; 38 constexpr u64 MAX_VALUE_TO_MULTIPLY = std::numeric_limits<s64>::max() / BASE_CLOCK_RATE_ARM11; 39 40 /// Refresh rate defined by ratio of ARM11 frequency to ARM11 ticks per frame 41 /// (268,111,856) / (4,481,136) = 59.83122493939037Hz 42 constexpr double SCREEN_REFRESH_RATE = BASE_CLOCK_RATE_ARM11 / static_cast<double>(4481136ull); 43 44 constexpr s64 msToCycles(int ms) { 45 // since ms is int there is no way to overflow 46 return BASE_CLOCK_RATE_ARM11 * static_cast<s64>(ms) / 1000; 47 } 48 49 constexpr s64 msToCycles(float ms) { 50 return static_cast<s64>(BASE_CLOCK_RATE_ARM11 * (0.001f) * ms); 51 } 52 53 constexpr s64 msToCycles(double ms) { 54 return static_cast<s64>(BASE_CLOCK_RATE_ARM11 * (0.001) * ms); 55 } 56 57 constexpr s64 usToCycles(float us) { 58 return static_cast<s64>(BASE_CLOCK_RATE_ARM11 * (0.000001f) * us); 59 } 60 61 constexpr s64 usToCycles(int us) { 62 return (BASE_CLOCK_RATE_ARM11 * static_cast<s64>(us) / 1000000); 63 } 64 65 inline s64 usToCycles(s64 us) { 66 if (us / 1000000 > static_cast<s64>(MAX_VALUE_TO_MULTIPLY)) { 67 LOG_ERROR(Core_Timing, "Integer overflow, use max value"); 68 return std::numeric_limits<s64>::max(); 69 } 70 if (us > static_cast<s64>(MAX_VALUE_TO_MULTIPLY)) { 71 LOG_DEBUG(Core_Timing, "Time very big, do rounding"); 72 return BASE_CLOCK_RATE_ARM11 * (us / 1000000); 73 } 74 return (BASE_CLOCK_RATE_ARM11 * us) / 1000000; 75 } 76 77 inline s64 usToCycles(u64 us) { 78 if (us / 1000000 > MAX_VALUE_TO_MULTIPLY) { 79 LOG_ERROR(Core_Timing, "Integer overflow, use max value"); 80 return std::numeric_limits<s64>::max(); 81 } 82 if (us > MAX_VALUE_TO_MULTIPLY) { 83 LOG_DEBUG(Core_Timing, "Time very big, do rounding"); 84 return BASE_CLOCK_RATE_ARM11 * static_cast<s64>(us / 1000000); 85 } 86 return (BASE_CLOCK_RATE_ARM11 * static_cast<s64>(us)) / 1000000; 87 } 88 89 constexpr s64 nsToCycles(float ns) { 90 return static_cast<s64>(BASE_CLOCK_RATE_ARM11 * (0.000000001f) * ns); 91 } 92 93 constexpr s64 nsToCycles(int ns) { 94 return BASE_CLOCK_RATE_ARM11 * static_cast<s64>(ns) / 1000000000; 95 } 96 97 inline s64 nsToCycles(s64 ns) { 98 if (ns / 1000000000 > static_cast<s64>(MAX_VALUE_TO_MULTIPLY)) { 99 LOG_ERROR(Core_Timing, "Integer overflow, use max value"); 100 return std::numeric_limits<s64>::max(); 101 } 102 if (ns > static_cast<s64>(MAX_VALUE_TO_MULTIPLY)) { 103 LOG_DEBUG(Core_Timing, "Time very big, do rounding"); 104 return BASE_CLOCK_RATE_ARM11 * (ns / 1000000000); 105 } 106 return (BASE_CLOCK_RATE_ARM11 * ns) / 1000000000; 107 } 108 109 inline s64 nsToCycles(u64 ns) { 110 if (ns / 1000000000 > MAX_VALUE_TO_MULTIPLY) { 111 LOG_ERROR(Core_Timing, "Integer overflow, use max value"); 112 return std::numeric_limits<s64>::max(); 113 } 114 if (ns > MAX_VALUE_TO_MULTIPLY) { 115 LOG_DEBUG(Core_Timing, "Time very big, do rounding"); 116 return BASE_CLOCK_RATE_ARM11 * (static_cast<s64>(ns) / 1000000000); 117 } 118 return (BASE_CLOCK_RATE_ARM11 * static_cast<s64>(ns)) / 1000000000; 119 } 120 121 constexpr u64 cyclesToNs(s64 cycles) { 122 return cycles * 1000000000 / BASE_CLOCK_RATE_ARM11; 123 } 124 125 constexpr s64 cyclesToUs(s64 cycles) { 126 return cycles * 1000000 / BASE_CLOCK_RATE_ARM11; 127 } 128 129 constexpr u64 cyclesToMs(s64 cycles) { 130 return cycles * 1000 / BASE_CLOCK_RATE_ARM11; 131 } 132 133 namespace Core { 134 135 using TimedCallback = std::function<void(std::uintptr_t user_data, int cycles_late)>; 136 137 struct TimingEventType { 138 TimedCallback callback; 139 const std::string* name; 140 }; 141 142 class Timing { 143 144 public: 145 struct Event { 146 s64 time; 147 u64 fifo_order; 148 std::uintptr_t user_data; 149 const TimingEventType* type; 150 151 bool operator>(const Event& right) const; 152 bool operator<(const Event& right) const; 153 154 private: 155 template <class Archive> 156 void save(Archive& ar, const unsigned int) const { 157 ar& time; 158 ar& fifo_order; 159 ar& user_data; 160 std::string name = *(type->name); 161 ar << name; 162 } 163 164 template <class Archive> 165 void load(Archive& ar, const unsigned int) { 166 ar& time; 167 ar& fifo_order; 168 ar& user_data; 169 std::string name; 170 ar >> name; 171 type = Global<Timing>().RegisterEvent(name, nullptr); 172 } 173 friend class boost::serialization::access; 174 175 BOOST_SERIALIZATION_SPLIT_MEMBER() 176 }; 177 178 // currently Service::HID::pad_update_ticks is the smallest interval for an event that gets 179 // always scheduled. Therfore we use this as orientation for the MAX_SLICE_LENGTH 180 // For performance bigger slice length are desired, though this will lead to cores desync 181 // But we never want to schedule events into the current slice, because then cores might to 182 // run small slices to sync up again. This is especially important for events that are always 183 // scheduled and repated. 184 static constexpr int MAX_SLICE_LENGTH = BASE_CLOCK_RATE_ARM11 / 234; 185 186 class Timer { 187 public: 188 Timer(s64 base_ticks = 0); 189 ~Timer(); 190 191 s64 GetMaxSliceLength() const; 192 193 void Advance(); 194 195 void SetNextSlice(s64 max_slice_length = MAX_SLICE_LENGTH); 196 197 void Idle(); 198 199 u64 GetTicks() const; 200 u64 GetIdleTicks() const; 201 202 void AddTicks(u64 ticks); 203 204 s64 GetDowncount() const; 205 206 void ForceExceptionCheck(s64 cycles); 207 208 void MoveEvents(); 209 210 private: 211 friend class Timing; 212 // The queue is a min-heap using std::make_heap/push_heap/pop_heap. 213 // We don't use std::priority_queue because we need to be able to serialize, unserialize and 214 // erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't 215 // accommodated by the standard adaptor class. 216 std::vector<Event> event_queue; 217 u64 event_fifo_id = 0; 218 // the queue for storing the events from other threads threadsafe until they will be added 219 // to the event_queue by the emu thread 220 Common::MPSCQueue<Event> ts_queue; 221 // Are we in a function that has been called from Advance() 222 // If events are sheduled from a function that gets called from Advance(), 223 // don't change slice_length and downcount. 224 // The time between CoreTiming being intialized and the first call to Advance() is 225 // considered the slice boundary between slice -1 and slice 0. Dispatcher loops must call 226 // Advance() before executing the first cycle of each slice to prepare the slice length and 227 // downcount for that slice. 228 bool is_timer_sane = true; 229 230 s64 slice_length = MAX_SLICE_LENGTH; 231 s64 downcount = MAX_SLICE_LENGTH; 232 s64 executed_ticks = 0; 233 u64 idled_cycles = 0; 234 235 // Stores a scaling for the internal clockspeed. Changing this number results in 236 // under/overclocking the guest cpu 237 double cpu_clock_scale = 1.0; 238 239 template <class Archive> 240 void serialize(Archive& ar, const unsigned int) { 241 MoveEvents(); 242 ar& event_queue; 243 ar& event_fifo_id; 244 ar& slice_length; 245 ar& downcount; 246 ar& executed_ticks; 247 ar& idled_cycles; 248 } 249 friend class boost::serialization::access; 250 }; 251 252 explicit Timing(std::size_t num_cores, u32 cpu_clock_percentage, s64 override_base_ticks = -1); 253 254 ~Timing(){}; 255 256 /** 257 * Returns the event_type identifier. if name is not unique, it will assert. 258 */ 259 TimingEventType* RegisterEvent(const std::string& name, TimedCallback callback); 260 261 // Make sure to use thread_safe_mode = true if called from a different thread than the 262 // emulator thread, such as coroutines. 263 void ScheduleEvent(s64 cycles_into_future, const TimingEventType* event_type, 264 std::uintptr_t user_data = 0, 265 std::size_t core_id = std::numeric_limits<std::size_t>::max(), 266 bool thread_safe_mode = false); 267 268 void UnscheduleEvent(const TimingEventType* event_type, std::uintptr_t user_data); 269 270 /// We only permit one event of each type in the queue at a time. 271 void RemoveEvent(const TimingEventType* event_type); 272 273 void SetCurrentTimer(std::size_t core_id); 274 275 s64 GetTicks() const; 276 277 s64 GetGlobalTicks() const; 278 279 /** 280 * Updates the value of the cpu clock scaling to the new percentage. 281 */ 282 void UpdateClockSpeed(u32 cpu_clock_percentage); 283 284 std::chrono::microseconds GetGlobalTimeUs() const; 285 286 std::shared_ptr<Timer> GetTimer(std::size_t cpu_id); 287 288 // Used after deserializing to unprotect the event queue. 289 void UnlockEventQueue() { 290 event_queue_locked = false; 291 } 292 293 /// Generates a random tick count to seed the system tick timer with. 294 static s64 GenerateBaseTicks(); 295 296 private: 297 // unordered_map stores each element separately as a linked list node so pointers to 298 // elements remain stable regardless of rehashes/resizing. 299 std::unordered_map<std::string, TimingEventType> event_types = {}; 300 301 std::vector<std::shared_ptr<Timer>> timers; 302 Timer* current_timer = nullptr; 303 304 // When true, the event queue can't be modified. Used while deserializing to workaround 305 // destructor side effects. 306 bool event_queue_locked = false; 307 308 template <class Archive> 309 void serialize(Archive& ar, const unsigned int file_version) { 310 // event_types set during initialization of other things 311 ar& timers; 312 ar& current_timer; 313 if (Archive::is_loading::value) { 314 event_queue_locked = true; 315 } 316 } 317 friend class boost::serialization::access; 318 }; 319 320 } // namespace Core 321 322 BOOST_CLASS_VERSION(Core::Timing, 1)