core_timing.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. // Copyright 2016 Dolphin Emulator Project / 2017 Dolphin Emulator Project
  2. // Licensed under GPLv2+
  3. // Refer to the license.txt file included.
  4. #include <catch2/catch.hpp>
  5. #include <array>
  6. #include <bitset>
  7. #include <cstdlib>
  8. #include <memory>
  9. #include <string>
  10. #include "common/file_util.h"
  11. #include "core/core.h"
  12. #include "core/core_timing.h"
  13. namespace {
  14. // Numbers are chosen randomly to make sure the correct one is given.
  15. constexpr std::array<u64, 5> CB_IDS{{42, 144, 93, 1026, UINT64_C(0xFFFF7FFFF7FFFF)}};
  16. constexpr int MAX_SLICE_LENGTH = 10000; // Copied from CoreTiming internals
  17. std::bitset<CB_IDS.size()> callbacks_ran_flags;
  18. u64 expected_callback = 0;
  19. s64 lateness = 0;
  20. template <unsigned int IDX>
  21. void CallbackTemplate(u64 userdata, s64 cycles_late) {
  22. static_assert(IDX < CB_IDS.size(), "IDX out of range");
  23. callbacks_ran_flags.set(IDX);
  24. REQUIRE(CB_IDS[IDX] == userdata);
  25. REQUIRE(CB_IDS[IDX] == expected_callback);
  26. REQUIRE(lateness == cycles_late);
  27. }
  28. u64 callbacks_done = 0;
  29. void EmptyCallback(u64 userdata, s64 cycles_late) {
  30. ++callbacks_done;
  31. }
  32. struct ScopeInit final {
  33. ScopeInit() {
  34. core_timing.Initialize();
  35. }
  36. ~ScopeInit() {
  37. core_timing.Shutdown();
  38. }
  39. Core::Timing::CoreTiming core_timing;
  40. };
  41. void AdvanceAndCheck(Core::Timing::CoreTiming& core_timing, u32 idx, u32 context = 0,
  42. int expected_lateness = 0, int cpu_downcount = 0) {
  43. callbacks_ran_flags = 0;
  44. expected_callback = CB_IDS[idx];
  45. lateness = expected_lateness;
  46. // Pretend we executed X cycles of instructions.
  47. core_timing.SwitchContext(context);
  48. core_timing.AddTicks(core_timing.GetDowncount() - cpu_downcount);
  49. core_timing.Advance();
  50. core_timing.SwitchContext((context + 1) % 4);
  51. REQUIRE(decltype(callbacks_ran_flags)().set(idx) == callbacks_ran_flags);
  52. }
  53. } // Anonymous namespace
  54. TEST_CASE("CoreTiming[BasicOrder]", "[core]") {
  55. ScopeInit guard;
  56. auto& core_timing = guard.core_timing;
  57. std::shared_ptr<Core::Timing::EventType> cb_a =
  58. Core::Timing::CreateEvent("callbackA", CallbackTemplate<0>);
  59. std::shared_ptr<Core::Timing::EventType> cb_b =
  60. Core::Timing::CreateEvent("callbackB", CallbackTemplate<1>);
  61. std::shared_ptr<Core::Timing::EventType> cb_c =
  62. Core::Timing::CreateEvent("callbackC", CallbackTemplate<2>);
  63. std::shared_ptr<Core::Timing::EventType> cb_d =
  64. Core::Timing::CreateEvent("callbackD", CallbackTemplate<3>);
  65. std::shared_ptr<Core::Timing::EventType> cb_e =
  66. Core::Timing::CreateEvent("callbackE", CallbackTemplate<4>);
  67. // Enter slice 0
  68. core_timing.ResetRun();
  69. // D -> B -> C -> A -> E
  70. core_timing.SwitchContext(0);
  71. core_timing.ScheduleEvent(1000, cb_a, CB_IDS[0]);
  72. REQUIRE(1000 == core_timing.GetDowncount());
  73. core_timing.ScheduleEvent(500, cb_b, CB_IDS[1]);
  74. REQUIRE(500 == core_timing.GetDowncount());
  75. core_timing.ScheduleEvent(800, cb_c, CB_IDS[2]);
  76. REQUIRE(500 == core_timing.GetDowncount());
  77. core_timing.ScheduleEvent(100, cb_d, CB_IDS[3]);
  78. REQUIRE(100 == core_timing.GetDowncount());
  79. core_timing.ScheduleEvent(1200, cb_e, CB_IDS[4]);
  80. REQUIRE(100 == core_timing.GetDowncount());
  81. AdvanceAndCheck(core_timing, 3, 0);
  82. AdvanceAndCheck(core_timing, 1, 1);
  83. AdvanceAndCheck(core_timing, 2, 2);
  84. AdvanceAndCheck(core_timing, 0, 3);
  85. AdvanceAndCheck(core_timing, 4, 0);
  86. }
  87. TEST_CASE("CoreTiming[FairSharing]", "[core]") {
  88. ScopeInit guard;
  89. auto& core_timing = guard.core_timing;
  90. std::shared_ptr<Core::Timing::EventType> empty_callback =
  91. Core::Timing::CreateEvent("empty_callback", EmptyCallback);
  92. callbacks_done = 0;
  93. u64 MAX_CALLBACKS = 10;
  94. for (std::size_t i = 0; i < 10; i++) {
  95. core_timing.ScheduleEvent(i * 3333U, empty_callback, 0);
  96. }
  97. const s64 advances = MAX_SLICE_LENGTH / 10;
  98. core_timing.ResetRun();
  99. u64 current_time = core_timing.GetTicks();
  100. bool keep_running{};
  101. do {
  102. keep_running = false;
  103. for (u32 active_core = 0; active_core < 4; ++active_core) {
  104. core_timing.SwitchContext(active_core);
  105. if (core_timing.CanCurrentContextRun()) {
  106. core_timing.AddTicks(std::min<s64>(advances, core_timing.GetDowncount()));
  107. core_timing.Advance();
  108. }
  109. keep_running |= core_timing.CanCurrentContextRun();
  110. }
  111. } while (keep_running);
  112. u64 current_time_2 = core_timing.GetTicks();
  113. REQUIRE(MAX_CALLBACKS == callbacks_done);
  114. REQUIRE(current_time_2 == current_time + MAX_SLICE_LENGTH * 4);
  115. }
  116. TEST_CASE("Core::Timing[PredictableLateness]", "[core]") {
  117. ScopeInit guard;
  118. auto& core_timing = guard.core_timing;
  119. std::shared_ptr<Core::Timing::EventType> cb_a =
  120. Core::Timing::CreateEvent("callbackA", CallbackTemplate<0>);
  121. std::shared_ptr<Core::Timing::EventType> cb_b =
  122. Core::Timing::CreateEvent("callbackB", CallbackTemplate<1>);
  123. // Enter slice 0
  124. core_timing.ResetRun();
  125. core_timing.ScheduleEvent(100, cb_a, CB_IDS[0]);
  126. core_timing.ScheduleEvent(200, cb_b, CB_IDS[1]);
  127. AdvanceAndCheck(core_timing, 0, 0, 10, -10); // (100 - 10)
  128. AdvanceAndCheck(core_timing, 1, 1, 50, -50);
  129. }