core_timing.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // SPDX-FileCopyrightText: 2016 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <catch2/catch_test_macros.hpp>
  4. #include <array>
  5. #include <bitset>
  6. #include <chrono>
  7. #include <cstdlib>
  8. #include <memory>
  9. #include <optional>
  10. #include <string>
  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> calls_order{{2, 0, 1, 4, 3}};
  16. std::array<s64, 5> delays{};
  17. std::bitset<5> callbacks_ran_flags;
  18. u64 expected_callback = 0;
  19. template <unsigned int IDX>
  20. std::optional<std::chrono::nanoseconds> HostCallbackTemplate(s64 time,
  21. std::chrono::nanoseconds ns_late) {
  22. static_assert(IDX < callbacks_ran_flags.size(), "IDX out of range");
  23. callbacks_ran_flags.set(IDX);
  24. delays[IDX] = ns_late.count();
  25. ++expected_callback;
  26. return std::nullopt;
  27. }
  28. struct ScopeInit final {
  29. ScopeInit() {
  30. core_timing.SetMulticore(true);
  31. core_timing.Initialize([]() {});
  32. }
  33. Core::Timing::CoreTiming core_timing;
  34. };
  35. u64 TestTimerSpeed(Core::Timing::CoreTiming& core_timing) {
  36. const u64 start = core_timing.GetGlobalTimeNs().count();
  37. volatile u64 placebo = 0;
  38. for (std::size_t i = 0; i < 1000; i++) {
  39. placebo = placebo + core_timing.GetGlobalTimeNs().count();
  40. }
  41. const u64 end = core_timing.GetGlobalTimeNs().count();
  42. return end - start;
  43. }
  44. } // Anonymous namespace
  45. TEST_CASE("CoreTiming[BasicOrder]", "[core]") {
  46. ScopeInit guard;
  47. auto& core_timing = guard.core_timing;
  48. std::vector<std::shared_ptr<Core::Timing::EventType>> events{
  49. Core::Timing::CreateEvent("callbackA", HostCallbackTemplate<0>),
  50. Core::Timing::CreateEvent("callbackB", HostCallbackTemplate<1>),
  51. Core::Timing::CreateEvent("callbackC", HostCallbackTemplate<2>),
  52. Core::Timing::CreateEvent("callbackD", HostCallbackTemplate<3>),
  53. Core::Timing::CreateEvent("callbackE", HostCallbackTemplate<4>),
  54. };
  55. expected_callback = 0;
  56. core_timing.SyncPause(true);
  57. const u64 one_micro = 1000U;
  58. for (std::size_t i = 0; i < events.size(); i++) {
  59. const u64 order = calls_order[i];
  60. const auto future_ns = std::chrono::nanoseconds{static_cast<s64>(i * one_micro + 100)};
  61. core_timing.ScheduleEvent(future_ns, events[order]);
  62. }
  63. /// test pause
  64. REQUIRE(callbacks_ran_flags.none());
  65. core_timing.Pause(false); // No need to sync
  66. while (core_timing.HasPendingEvents())
  67. ;
  68. REQUIRE(callbacks_ran_flags.all());
  69. for (std::size_t i = 0; i < delays.size(); i++) {
  70. const double delay = static_cast<double>(delays[i]);
  71. const double micro = delay / 1000.0f;
  72. const double mili = micro / 1000.0f;
  73. printf("HostTimer Pausing Delay[%zu]: %.3f %.6f\n", i, micro, mili);
  74. }
  75. }
  76. TEST_CASE("CoreTiming[BasicOrderNoPausing]", "[core]") {
  77. ScopeInit guard;
  78. auto& core_timing = guard.core_timing;
  79. std::vector<std::shared_ptr<Core::Timing::EventType>> events{
  80. Core::Timing::CreateEvent("callbackA", HostCallbackTemplate<0>),
  81. Core::Timing::CreateEvent("callbackB", HostCallbackTemplate<1>),
  82. Core::Timing::CreateEvent("callbackC", HostCallbackTemplate<2>),
  83. Core::Timing::CreateEvent("callbackD", HostCallbackTemplate<3>),
  84. Core::Timing::CreateEvent("callbackE", HostCallbackTemplate<4>),
  85. };
  86. core_timing.SyncPause(true);
  87. core_timing.SyncPause(false);
  88. expected_callback = 0;
  89. const u64 start = core_timing.GetGlobalTimeNs().count();
  90. const u64 one_micro = 1000U;
  91. for (std::size_t i = 0; i < events.size(); i++) {
  92. const u64 order = calls_order[i];
  93. const auto future_ns = std::chrono::nanoseconds{static_cast<s64>(i * one_micro + 100)};
  94. core_timing.ScheduleEvent(future_ns, events[order]);
  95. }
  96. const u64 end = core_timing.GetGlobalTimeNs().count();
  97. const double scheduling_time = static_cast<double>(end - start);
  98. const double timer_time = static_cast<double>(TestTimerSpeed(core_timing));
  99. while (core_timing.HasPendingEvents())
  100. ;
  101. REQUIRE(callbacks_ran_flags.all());
  102. for (std::size_t i = 0; i < delays.size(); i++) {
  103. const double delay = static_cast<double>(delays[i]);
  104. const double micro = delay / 1000.0f;
  105. const double mili = micro / 1000.0f;
  106. printf("HostTimer No Pausing Delay[%zu]: %.3f %.6f\n", i, micro, mili);
  107. }
  108. const double micro = scheduling_time / 1000.0f;
  109. const double mili = micro / 1000.0f;
  110. printf("HostTimer No Pausing Scheduling Time: %.3f %.6f\n", micro, mili);
  111. printf("HostTimer No Pausing Timer Time: %.3f %.6f\n", timer_time / 1000.f,
  112. timer_time / 1000000.f);
  113. }