/ src / core / core_timing.h
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)