core_timing.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // Copyright 2016 Dolphin Emulator Project / 2017 Dolphin Emulator Project
  2. // Licensed under GPLv2+
  3. // Refer to the license.txt file included.
  4. #include <catch.hpp>
  5. #include <array>
  6. #include <bitset>
  7. #include <string>
  8. #include "common/file_util.h"
  9. #include "core/core.h"
  10. #include "core/core_timing.h"
  11. // Numbers are chosen randomly to make sure the correct one is given.
  12. static constexpr std::array<u64, 5> CB_IDS{{42, 144, 93, 1026, UINT64_C(0xFFFF7FFFF7FFFF)}};
  13. static constexpr int MAX_SLICE_LENGTH = 20000; // Copied from CoreTiming internals
  14. static std::bitset<CB_IDS.size()> callbacks_ran_flags;
  15. static u64 expected_callback = 0;
  16. static s64 lateness = 0;
  17. template <unsigned int IDX>
  18. void CallbackTemplate(u64 userdata, s64 cycles_late) {
  19. static_assert(IDX < CB_IDS.size(), "IDX out of range");
  20. callbacks_ran_flags.set(IDX);
  21. REQUIRE(CB_IDS[IDX] == userdata);
  22. REQUIRE(CB_IDS[IDX] == expected_callback);
  23. REQUIRE(lateness == cycles_late);
  24. }
  25. class ScopeInit final {
  26. public:
  27. ScopeInit() {
  28. CoreTiming::Init();
  29. }
  30. ~ScopeInit() {
  31. CoreTiming::Shutdown();
  32. }
  33. };
  34. static void AdvanceAndCheck(u32 idx, int downcount, int expected_lateness = 0,
  35. int cpu_downcount = 0) {
  36. callbacks_ran_flags = 0;
  37. expected_callback = CB_IDS[idx];
  38. lateness = expected_lateness;
  39. CoreTiming::AddTicks(CoreTiming::GetDowncount() -
  40. cpu_downcount); // Pretend we executed X cycles of instructions.
  41. CoreTiming::Advance();
  42. REQUIRE(decltype(callbacks_ran_flags)().set(idx) == callbacks_ran_flags);
  43. REQUIRE(downcount == CoreTiming::GetDowncount());
  44. }
  45. TEST_CASE("CoreTiming[BasicOrder]", "[core]") {
  46. ScopeInit guard;
  47. CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
  48. CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
  49. CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>);
  50. CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", CallbackTemplate<3>);
  51. CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", CallbackTemplate<4>);
  52. // Enter slice 0
  53. CoreTiming::Advance();
  54. // D -> B -> C -> A -> E
  55. CoreTiming::ScheduleEvent(1000, cb_a, CB_IDS[0]);
  56. REQUIRE(1000 == CoreTiming::GetDowncount());
  57. CoreTiming::ScheduleEvent(500, cb_b, CB_IDS[1]);
  58. REQUIRE(500 == CoreTiming::GetDowncount());
  59. CoreTiming::ScheduleEvent(800, cb_c, CB_IDS[2]);
  60. REQUIRE(500 == CoreTiming::GetDowncount());
  61. CoreTiming::ScheduleEvent(100, cb_d, CB_IDS[3]);
  62. REQUIRE(100 == CoreTiming::GetDowncount());
  63. CoreTiming::ScheduleEvent(1200, cb_e, CB_IDS[4]);
  64. REQUIRE(100 == CoreTiming::GetDowncount());
  65. AdvanceAndCheck(3, 400);
  66. AdvanceAndCheck(1, 300);
  67. AdvanceAndCheck(2, 200);
  68. AdvanceAndCheck(0, 200);
  69. AdvanceAndCheck(4, MAX_SLICE_LENGTH);
  70. }
  71. TEST_CASE("CoreTiming[Threadsave]", "[core]") {
  72. ScopeInit guard;
  73. CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
  74. CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
  75. CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>);
  76. CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", CallbackTemplate<3>);
  77. CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", CallbackTemplate<4>);
  78. // Enter slice 0
  79. CoreTiming::Advance();
  80. // D -> B -> C -> A -> E
  81. CoreTiming::ScheduleEventThreadsafe(1000, cb_a, CB_IDS[0]);
  82. // Manually force since ScheduleEventThreadsafe doesn't call it
  83. CoreTiming::ForceExceptionCheck(1000);
  84. REQUIRE(1000 == CoreTiming::GetDowncount());
  85. CoreTiming::ScheduleEventThreadsafe(500, cb_b, CB_IDS[1]);
  86. // Manually force since ScheduleEventThreadsafe doesn't call it
  87. CoreTiming::ForceExceptionCheck(500);
  88. REQUIRE(500 == CoreTiming::GetDowncount());
  89. CoreTiming::ScheduleEventThreadsafe(800, cb_c, CB_IDS[2]);
  90. // Manually force since ScheduleEventThreadsafe doesn't call it
  91. CoreTiming::ForceExceptionCheck(800);
  92. REQUIRE(500 == CoreTiming::GetDowncount());
  93. CoreTiming::ScheduleEventThreadsafe(100, cb_d, CB_IDS[3]);
  94. // Manually force since ScheduleEventThreadsafe doesn't call it
  95. CoreTiming::ForceExceptionCheck(100);
  96. REQUIRE(100 == CoreTiming::GetDowncount());
  97. CoreTiming::ScheduleEventThreadsafe(1200, cb_e, CB_IDS[4]);
  98. // Manually force since ScheduleEventThreadsafe doesn't call it
  99. CoreTiming::ForceExceptionCheck(1200);
  100. REQUIRE(100 == CoreTiming::GetDowncount());
  101. AdvanceAndCheck(3, 400);
  102. AdvanceAndCheck(1, 300);
  103. AdvanceAndCheck(2, 200);
  104. AdvanceAndCheck(0, 200);
  105. AdvanceAndCheck(4, MAX_SLICE_LENGTH);
  106. }
  107. namespace SharedSlotTest {
  108. static unsigned int counter = 0;
  109. template <unsigned int ID>
  110. void FifoCallback(u64 userdata, s64 cycles_late) {
  111. static_assert(ID < CB_IDS.size(), "ID out of range");
  112. callbacks_ran_flags.set(ID);
  113. REQUIRE(CB_IDS[ID] == userdata);
  114. REQUIRE(ID == counter);
  115. REQUIRE(lateness == cycles_late);
  116. ++counter;
  117. }
  118. } // namespace SharedSlotTest
  119. TEST_CASE("CoreTiming[SharedSlot]", "[core]") {
  120. using namespace SharedSlotTest;
  121. ScopeInit guard;
  122. CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", FifoCallback<0>);
  123. CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", FifoCallback<1>);
  124. CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", FifoCallback<2>);
  125. CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", FifoCallback<3>);
  126. CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", FifoCallback<4>);
  127. CoreTiming::ScheduleEvent(1000, cb_a, CB_IDS[0]);
  128. CoreTiming::ScheduleEvent(1000, cb_b, CB_IDS[1]);
  129. CoreTiming::ScheduleEvent(1000, cb_c, CB_IDS[2]);
  130. CoreTiming::ScheduleEvent(1000, cb_d, CB_IDS[3]);
  131. CoreTiming::ScheduleEvent(1000, cb_e, CB_IDS[4]);
  132. // Enter slice 0
  133. CoreTiming::Advance();
  134. REQUIRE(1000 == CoreTiming::GetDowncount());
  135. callbacks_ran_flags = 0;
  136. counter = 0;
  137. lateness = 0;
  138. CoreTiming::AddTicks(CoreTiming::GetDowncount());
  139. CoreTiming::Advance();
  140. REQUIRE(MAX_SLICE_LENGTH == CoreTiming::GetDowncount());
  141. REQUIRE(0x1FULL == callbacks_ran_flags.to_ullong());
  142. }
  143. TEST_CASE("CoreTiming[PredictableLateness]", "[core]") {
  144. ScopeInit guard;
  145. CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
  146. CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
  147. // Enter slice 0
  148. CoreTiming::Advance();
  149. CoreTiming::ScheduleEvent(100, cb_a, CB_IDS[0]);
  150. CoreTiming::ScheduleEvent(200, cb_b, CB_IDS[1]);
  151. AdvanceAndCheck(0, 90, 10, -10); // (100 - 10)
  152. AdvanceAndCheck(1, MAX_SLICE_LENGTH, 50, -50);
  153. }
  154. namespace ChainSchedulingTest {
  155. static int reschedules = 0;
  156. static void RescheduleCallback(u64 userdata, s64 cycles_late) {
  157. --reschedules;
  158. REQUIRE(reschedules >= 0);
  159. REQUIRE(lateness == cycles_late);
  160. if (reschedules > 0)
  161. CoreTiming::ScheduleEvent(1000, reinterpret_cast<CoreTiming::EventType*>(userdata),
  162. userdata);
  163. }
  164. } // namespace ChainSchedulingTest
  165. TEST_CASE("CoreTiming[ChainScheduling]", "[core]") {
  166. using namespace ChainSchedulingTest;
  167. ScopeInit guard;
  168. CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
  169. CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
  170. CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>);
  171. CoreTiming::EventType* cb_rs =
  172. CoreTiming::RegisterEvent("callbackReschedule", RescheduleCallback);
  173. // Enter slice 0
  174. CoreTiming::Advance();
  175. CoreTiming::ScheduleEvent(800, cb_a, CB_IDS[0]);
  176. CoreTiming::ScheduleEvent(1000, cb_b, CB_IDS[1]);
  177. CoreTiming::ScheduleEvent(2200, cb_c, CB_IDS[2]);
  178. CoreTiming::ScheduleEvent(1000, cb_rs, reinterpret_cast<u64>(cb_rs));
  179. REQUIRE(800 == CoreTiming::GetDowncount());
  180. reschedules = 3;
  181. AdvanceAndCheck(0, 200); // cb_a
  182. AdvanceAndCheck(1, 1000); // cb_b, cb_rs
  183. REQUIRE(2 == reschedules);
  184. CoreTiming::AddTicks(CoreTiming::GetDowncount());
  185. CoreTiming::Advance(); // cb_rs
  186. REQUIRE(1 == reschedules);
  187. REQUIRE(200 == CoreTiming::GetDowncount());
  188. AdvanceAndCheck(2, 800); // cb_c
  189. CoreTiming::AddTicks(CoreTiming::GetDowncount());
  190. CoreTiming::Advance(); // cb_rs
  191. REQUIRE(0 == reschedules);
  192. REQUIRE(MAX_SLICE_LENGTH == CoreTiming::GetDowncount());
  193. }