core_timing.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // Copyright 2008 Dolphin Emulator Project / 2017 Citra Emulator Project
  2. // Licensed under GPLv2+
  3. // Refer to the license.txt file included.
  4. #include "core/core_timing.h"
  5. #include <algorithm>
  6. #include <mutex>
  7. #include <string>
  8. #include <tuple>
  9. #include "common/assert.h"
  10. #include "common/thread.h"
  11. #include "core/core_timing_util.h"
  12. #pragma optoimize("", off)
  13. namespace Core::Timing {
  14. constexpr int MAX_SLICE_LENGTH = 10000;
  15. struct CoreTiming::Event {
  16. s64 time;
  17. u64 fifo_order;
  18. u64 userdata;
  19. const EventType* type;
  20. // Sort by time, unless the times are the same, in which case sort by
  21. // the order added to the queue
  22. friend bool operator>(const Event& left, const Event& right) {
  23. return std::tie(left.time, left.fifo_order) > std::tie(right.time, right.fifo_order);
  24. }
  25. friend bool operator<(const Event& left, const Event& right) {
  26. return std::tie(left.time, left.fifo_order) < std::tie(right.time, right.fifo_order);
  27. }
  28. };
  29. CoreTiming::CoreTiming() = default;
  30. CoreTiming::~CoreTiming() = default;
  31. void CoreTiming::Initialize() {
  32. for (std::size_t core = 0; core < num_cpu_cores; core++) {
  33. downcounts[core] = MAX_SLICE_LENGTH;
  34. time_slice[core] = MAX_SLICE_LENGTH;
  35. }
  36. slice_length = MAX_SLICE_LENGTH;
  37. global_timer = 0;
  38. idled_cycles = 0;
  39. current_context = 0;
  40. // The time between CoreTiming being initialized and the first call to Advance() is considered
  41. // the slice boundary between slice -1 and slice 0. Dispatcher loops must call Advance() before
  42. // executing the first cycle of each slice to prepare the slice length and downcount for
  43. // that slice.
  44. is_global_timer_sane = true;
  45. event_fifo_id = 0;
  46. const auto empty_timed_callback = [](u64, s64) {};
  47. ev_lost = RegisterEvent("_lost_event", empty_timed_callback);
  48. }
  49. void CoreTiming::Shutdown() {
  50. ClearPendingEvents();
  51. UnregisterAllEvents();
  52. }
  53. EventType* CoreTiming::RegisterEvent(const std::string& name, TimedCallback callback) {
  54. std::lock_guard guard{inner_mutex};
  55. // check for existing type with same name.
  56. // we want event type names to remain unique so that we can use them for serialization.
  57. ASSERT_MSG(event_types.find(name) == event_types.end(),
  58. "CoreTiming Event \"{}\" is already registered. Events should only be registered "
  59. "during Init to avoid breaking save states.",
  60. name.c_str());
  61. auto info = event_types.emplace(name, EventType{callback, nullptr});
  62. EventType* event_type = &info.first->second;
  63. event_type->name = &info.first->first;
  64. return event_type;
  65. }
  66. void CoreTiming::UnregisterAllEvents() {
  67. ASSERT_MSG(event_queue.empty(), "Cannot unregister events with events pending");
  68. event_types.clear();
  69. }
  70. void CoreTiming::ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
  71. ASSERT(event_type != nullptr);
  72. std::lock_guard guard{inner_mutex};
  73. const s64 timeout = GetTicks() + cycles_into_future;
  74. // If this event needs to be scheduled before the next advance(), force one early
  75. if (!is_global_timer_sane) {
  76. ForceExceptionCheck(cycles_into_future);
  77. }
  78. event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type});
  79. std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
  80. }
  81. void CoreTiming::UnscheduleEvent(const EventType* event_type, u64 userdata) {
  82. std::lock_guard guard{inner_mutex};
  83. const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
  84. return e.type == event_type && e.userdata == userdata;
  85. });
  86. // Removing random items breaks the invariant so we have to re-establish it.
  87. if (itr != event_queue.end()) {
  88. event_queue.erase(itr, event_queue.end());
  89. std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
  90. }
  91. }
  92. u64 CoreTiming::GetTicks() const {
  93. u64 ticks = static_cast<u64>(global_timer);
  94. if (!is_global_timer_sane) {
  95. ticks += accumulated_ticks;
  96. }
  97. return ticks;
  98. }
  99. u64 CoreTiming::GetIdleTicks() const {
  100. return static_cast<u64>(idled_cycles);
  101. }
  102. void CoreTiming::AddTicks(u64 ticks) {
  103. accumulated_ticks += ticks;
  104. downcounts[current_context] -= static_cast<s64>(ticks);
  105. }
  106. void CoreTiming::ClearPendingEvents() {
  107. event_queue.clear();
  108. }
  109. void CoreTiming::RemoveEvent(const EventType* event_type) {
  110. std::lock_guard guard{inner_mutex};
  111. const auto itr = std::remove_if(event_queue.begin(), event_queue.end(),
  112. [&](const Event& e) { return e.type == event_type; });
  113. // Removing random items breaks the invariant so we have to re-establish it.
  114. if (itr != event_queue.end()) {
  115. event_queue.erase(itr, event_queue.end());
  116. std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>());
  117. }
  118. }
  119. void CoreTiming::ForceExceptionCheck(s64 cycles) {
  120. cycles = std::max<s64>(0, cycles);
  121. if (downcounts[current_context] <= cycles) {
  122. return;
  123. }
  124. // downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int
  125. // here. Account for cycles already executed by adjusting the g.slice_length
  126. downcounts[current_context] = static_cast<int>(cycles);
  127. }
  128. std::optional<u64> CoreTiming::NextAvailableCore(const s64 needed_ticks) const {
  129. const u64 original_context = current_context;
  130. u64 next_context = (original_context + 1) % num_cpu_cores;
  131. while (next_context != original_context) {
  132. if (time_slice[next_context] >= needed_ticks) {
  133. return {next_context};
  134. } else if (time_slice[next_context] >= 0) {
  135. return {};
  136. }
  137. next_context = (next_context + 1) % num_cpu_cores;
  138. }
  139. return {};
  140. }
  141. void CoreTiming::Advance() {
  142. std::unique_lock<std::mutex> guard(inner_mutex);
  143. const int cycles_executed = accumulated_ticks;
  144. time_slice[current_context] = std::max<s64>(0, time_slice[current_context] - accumulated_ticks);
  145. global_timer += cycles_executed;
  146. is_global_timer_sane = true;
  147. while (!event_queue.empty() && event_queue.front().time <= global_timer) {
  148. Event evt = std::move(event_queue.front());
  149. std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>());
  150. event_queue.pop_back();
  151. inner_mutex.unlock();
  152. evt.type->callback(evt.userdata, global_timer - evt.time);
  153. inner_mutex.lock();
  154. }
  155. is_global_timer_sane = false;
  156. // Still events left (scheduled in the future)
  157. if (!event_queue.empty()) {
  158. s64 needed_ticks = std::min<s64>(event_queue.front().time - global_timer, MAX_SLICE_LENGTH);
  159. const auto next_core = NextAvailableCore(needed_ticks);
  160. if (next_core) {
  161. downcounts[*next_core] = needed_ticks;
  162. }
  163. }
  164. accumulated_ticks = 0;
  165. downcounts[current_context] = time_slice[current_context];
  166. }
  167. void CoreTiming::ResetRun() {
  168. for (std::size_t core = 0; core < num_cpu_cores; core++) {
  169. downcounts[core] = MAX_SLICE_LENGTH;
  170. time_slice[core] = MAX_SLICE_LENGTH;
  171. }
  172. current_context = 0;
  173. // Still events left (scheduled in the future)
  174. if (!event_queue.empty()) {
  175. s64 needed_ticks = std::min<s64>(event_queue.front().time - global_timer, MAX_SLICE_LENGTH);
  176. downcounts[current_context] = needed_ticks;
  177. }
  178. is_global_timer_sane = false;
  179. accumulated_ticks = 0;
  180. }
  181. void CoreTiming::Idle() {
  182. idled_cycles += downcounts[current_context];
  183. downcounts[current_context] = 0;
  184. }
  185. std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
  186. return std::chrono::microseconds{GetTicks() * 1000000 / BASE_CLOCK_RATE};
  187. }
  188. s64 CoreTiming::GetDowncount() const {
  189. return downcounts[current_context];
  190. }
  191. } // namespace Core::Timing