diff options
Diffstat (limited to 'src/tests')
-rw-r--r-- | src/tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/tests/common/fibers.cpp | 2 | ||||
-rw-r--r-- | src/tests/core/core_timing.cpp | 182 | ||||
-rw-r--r-- | src/tests/core/host_timing.cpp | 142 |
4 files changed, 86 insertions, 241 deletions
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 3f750b51c..47ef30aa9 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -8,7 +8,6 @@ add_executable(tests core/arm/arm_test_common.cpp core/arm/arm_test_common.h core/core_timing.cpp - core/host_timing.cpp tests.cpp ) diff --git a/src/tests/common/fibers.cpp b/src/tests/common/fibers.cpp index 12536b6d8..4fd92428f 100644 --- a/src/tests/common/fibers.cpp +++ b/src/tests/common/fibers.cpp @@ -68,7 +68,7 @@ static void ThreadStart1(u32 id, TestControl1& test_control) { * doing all the work required. */ TEST_CASE("Fibers::Setup", "[common]") { - constexpr u32 num_threads = 7; + constexpr std::size_t num_threads = 7; TestControl1 test_control{}; test_control.thread_fibers.resize(num_threads); test_control.work_fibers.resize(num_threads); diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp index ff2d11cc8..e66db1940 100644 --- a/src/tests/core/core_timing.cpp +++ b/src/tests/core/core_timing.cpp @@ -18,29 +18,26 @@ namespace { // Numbers are chosen randomly to make sure the correct one is given. constexpr std::array<u64, 5> CB_IDS{{42, 144, 93, 1026, UINT64_C(0xFFFF7FFFF7FFFF)}}; constexpr int MAX_SLICE_LENGTH = 10000; // Copied from CoreTiming internals +constexpr std::array<u64, 5> calls_order{{2, 0, 1, 4, 3}}; +std::array<s64, 5> delays{}; std::bitset<CB_IDS.size()> callbacks_ran_flags; u64 expected_callback = 0; -s64 lateness = 0; template <unsigned int IDX> -void CallbackTemplate(u64 userdata, s64 cycles_late) { +void HostCallbackTemplate(u64 userdata, s64 nanoseconds_late) { static_assert(IDX < CB_IDS.size(), "IDX out of range"); callbacks_ran_flags.set(IDX); REQUIRE(CB_IDS[IDX] == userdata); - REQUIRE(CB_IDS[IDX] == expected_callback); - REQUIRE(lateness == cycles_late); -} - -u64 callbacks_done = 0; - -void EmptyCallback(u64 userdata, s64 cycles_late) { - ++callbacks_done; + REQUIRE(CB_IDS[IDX] == CB_IDS[calls_order[expected_callback]]); + delays[IDX] = nanoseconds_late; + ++expected_callback; } struct ScopeInit final { ScopeInit() { - core_timing.Initialize(); + core_timing.SetMulticore(true); + core_timing.Initialize([]() {}); } ~ScopeInit() { core_timing.Shutdown(); @@ -49,110 +46,101 @@ struct ScopeInit final { Core::Timing::CoreTiming core_timing; }; -void AdvanceAndCheck(Core::Timing::CoreTiming& core_timing, u32 idx, u32 context = 0, - int expected_lateness = 0, int cpu_downcount = 0) { - callbacks_ran_flags = 0; - expected_callback = CB_IDS[idx]; - lateness = expected_lateness; - - // Pretend we executed X cycles of instructions. - core_timing.SwitchContext(context); - core_timing.AddTicks(core_timing.GetDowncount() - cpu_downcount); - core_timing.Advance(); - core_timing.SwitchContext((context + 1) % 4); +#pragma optimize("", off) - REQUIRE(decltype(callbacks_ran_flags)().set(idx) == callbacks_ran_flags); +u64 TestTimerSpeed(Core::Timing::CoreTiming& core_timing) { + u64 start = core_timing.GetGlobalTimeNs().count(); + u64 placebo = 0; + for (std::size_t i = 0; i < 1000; i++) { + placebo += core_timing.GetGlobalTimeNs().count(); + } + u64 end = core_timing.GetGlobalTimeNs().count(); + return (end - start); } + +#pragma optimize("", on) + } // Anonymous namespace TEST_CASE("CoreTiming[BasicOrder]", "[core]") { ScopeInit guard; auto& core_timing = guard.core_timing; + std::vector<std::shared_ptr<Core::Timing::EventType>> events{ + Core::Timing::CreateEvent("callbackA", HostCallbackTemplate<0>), + Core::Timing::CreateEvent("callbackB", HostCallbackTemplate<1>), + Core::Timing::CreateEvent("callbackC", HostCallbackTemplate<2>), + Core::Timing::CreateEvent("callbackD", HostCallbackTemplate<3>), + Core::Timing::CreateEvent("callbackE", HostCallbackTemplate<4>), + }; + + expected_callback = 0; + + core_timing.SyncPause(true); + + u64 one_micro = 1000U; + for (std::size_t i = 0; i < events.size(); i++) { + u64 order = calls_order[i]; + core_timing.ScheduleEvent(i * one_micro + 100U, events[order], CB_IDS[order]); + } + /// test pause + REQUIRE(callbacks_ran_flags.none()); - std::shared_ptr<Core::Timing::EventType> cb_a = - Core::Timing::CreateEvent("callbackA", CallbackTemplate<0>); - std::shared_ptr<Core::Timing::EventType> cb_b = - Core::Timing::CreateEvent("callbackB", CallbackTemplate<1>); - std::shared_ptr<Core::Timing::EventType> cb_c = - Core::Timing::CreateEvent("callbackC", CallbackTemplate<2>); - std::shared_ptr<Core::Timing::EventType> cb_d = - Core::Timing::CreateEvent("callbackD", CallbackTemplate<3>); - std::shared_ptr<Core::Timing::EventType> cb_e = - Core::Timing::CreateEvent("callbackE", CallbackTemplate<4>); - - // Enter slice 0 - core_timing.ResetRun(); - - // D -> B -> C -> A -> E - core_timing.SwitchContext(0); - core_timing.ScheduleEvent(1000, cb_a, CB_IDS[0]); - REQUIRE(1000 == core_timing.GetDowncount()); - core_timing.ScheduleEvent(500, cb_b, CB_IDS[1]); - REQUIRE(500 == core_timing.GetDowncount()); - core_timing.ScheduleEvent(800, cb_c, CB_IDS[2]); - REQUIRE(500 == core_timing.GetDowncount()); - core_timing.ScheduleEvent(100, cb_d, CB_IDS[3]); - REQUIRE(100 == core_timing.GetDowncount()); - core_timing.ScheduleEvent(1200, cb_e, CB_IDS[4]); - REQUIRE(100 == core_timing.GetDowncount()); - - AdvanceAndCheck(core_timing, 3, 0); - AdvanceAndCheck(core_timing, 1, 1); - AdvanceAndCheck(core_timing, 2, 2); - AdvanceAndCheck(core_timing, 0, 3); - AdvanceAndCheck(core_timing, 4, 0); -} - -TEST_CASE("CoreTiming[FairSharing]", "[core]") { + core_timing.Pause(false); // No need to sync - ScopeInit guard; - auto& core_timing = guard.core_timing; + while (core_timing.HasPendingEvents()) + ; - std::shared_ptr<Core::Timing::EventType> empty_callback = - Core::Timing::CreateEvent("empty_callback", EmptyCallback); + REQUIRE(callbacks_ran_flags.all()); - callbacks_done = 0; - u64 MAX_CALLBACKS = 10; - for (std::size_t i = 0; i < 10; i++) { - core_timing.ScheduleEvent(i * 3333U, empty_callback, 0); + for (std::size_t i = 0; i < delays.size(); i++) { + const double delay = static_cast<double>(delays[i]); + const double micro = delay / 1000.0f; + const double mili = micro / 1000.0f; + printf("HostTimer Pausing Delay[%zu]: %.3f %.6f\n", i, micro, mili); } - - const s64 advances = MAX_SLICE_LENGTH / 10; - core_timing.ResetRun(); - u64 current_time = core_timing.GetTicks(); - bool keep_running{}; - do { - keep_running = false; - for (u32 active_core = 0; active_core < 4; ++active_core) { - core_timing.SwitchContext(active_core); - if (core_timing.CanCurrentContextRun()) { - core_timing.AddTicks(std::min<s64>(advances, core_timing.GetDowncount())); - core_timing.Advance(); - } - keep_running |= core_timing.CanCurrentContextRun(); - } - } while (keep_running); - u64 current_time_2 = core_timing.GetTicks(); - - REQUIRE(MAX_CALLBACKS == callbacks_done); - REQUIRE(current_time_2 == current_time + MAX_SLICE_LENGTH * 4); } -TEST_CASE("Core::Timing[PredictableLateness]", "[core]") { +TEST_CASE("CoreTiming[BasicOrderNoPausing]", "[core]") { ScopeInit guard; auto& core_timing = guard.core_timing; + std::vector<std::shared_ptr<Core::Timing::EventType>> events{ + Core::Timing::CreateEvent("callbackA", HostCallbackTemplate<0>), + Core::Timing::CreateEvent("callbackB", HostCallbackTemplate<1>), + Core::Timing::CreateEvent("callbackC", HostCallbackTemplate<2>), + Core::Timing::CreateEvent("callbackD", HostCallbackTemplate<3>), + Core::Timing::CreateEvent("callbackE", HostCallbackTemplate<4>), + }; + + core_timing.SyncPause(true); + core_timing.SyncPause(false); + + expected_callback = 0; + + u64 start = core_timing.GetGlobalTimeNs().count(); + u64 one_micro = 1000U; + for (std::size_t i = 0; i < events.size(); i++) { + u64 order = calls_order[i]; + core_timing.ScheduleEvent(i * one_micro + 100U, events[order], CB_IDS[order]); + } + u64 end = core_timing.GetGlobalTimeNs().count(); + const double scheduling_time = static_cast<double>(end - start); + const double timer_time = static_cast<double>(TestTimerSpeed(core_timing)); - std::shared_ptr<Core::Timing::EventType> cb_a = - Core::Timing::CreateEvent("callbackA", CallbackTemplate<0>); - std::shared_ptr<Core::Timing::EventType> cb_b = - Core::Timing::CreateEvent("callbackB", CallbackTemplate<1>); + while (core_timing.HasPendingEvents()) + ; - // Enter slice 0 - core_timing.ResetRun(); + REQUIRE(callbacks_ran_flags.all()); - core_timing.ScheduleEvent(100, cb_a, CB_IDS[0]); - core_timing.ScheduleEvent(200, cb_b, CB_IDS[1]); + for (std::size_t i = 0; i < delays.size(); i++) { + const double delay = static_cast<double>(delays[i]); + const double micro = delay / 1000.0f; + const double mili = micro / 1000.0f; + printf("HostTimer No Pausing Delay[%zu]: %.3f %.6f\n", i, micro, mili); + } - AdvanceAndCheck(core_timing, 0, 0, 10, -10); // (100 - 10) - AdvanceAndCheck(core_timing, 1, 1, 50, -50); + const double micro = scheduling_time / 1000.0f; + const double mili = micro / 1000.0f; + printf("HostTimer No Pausing Scheduling Time: %.3f %.6f\n", micro, mili); + printf("HostTimer No Pausing Timer Time: %.3f %.6f\n", timer_time / 1000.f, + timer_time / 1000000.f); } diff --git a/src/tests/core/host_timing.cpp b/src/tests/core/host_timing.cpp deleted file mode 100644 index 556254098..000000000 --- a/src/tests/core/host_timing.cpp +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright 2016 Dolphin Emulator Project / 2017 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include <catch2/catch.hpp> - -#include <array> -#include <bitset> -#include <cstdlib> -#include <memory> -#include <string> - -#include "common/file_util.h" -#include "core/core.h" -#include "core/host_timing.h" - -// Numbers are chosen randomly to make sure the correct one is given. -static constexpr std::array<u64, 5> CB_IDS{{42, 144, 93, 1026, UINT64_C(0xFFFF7FFFF7FFFF)}}; -static constexpr int MAX_SLICE_LENGTH = 10000; // Copied from CoreTiming internals -static constexpr std::array<u64, 5> calls_order{{2, 0, 1, 4, 3}}; -static std::array<s64, 5> delays{}; - -static std::bitset<CB_IDS.size()> callbacks_ran_flags; -static u64 expected_callback = 0; - -template <unsigned int IDX> -void HostCallbackTemplate(u64 userdata, s64 nanoseconds_late) { - static_assert(IDX < CB_IDS.size(), "IDX out of range"); - callbacks_ran_flags.set(IDX); - REQUIRE(CB_IDS[IDX] == userdata); - REQUIRE(CB_IDS[IDX] == CB_IDS[calls_order[expected_callback]]); - delays[IDX] = nanoseconds_late; - ++expected_callback; -} - -struct ScopeInit final { - ScopeInit() { - core_timing.Initialize(); - } - ~ScopeInit() { - core_timing.Shutdown(); - } - - Core::HostTiming::CoreTiming core_timing; -}; - -#pragma optimize("", off) - -static u64 TestTimerSpeed(Core::HostTiming::CoreTiming& core_timing) { - u64 start = core_timing.GetGlobalTimeNs().count(); - u64 placebo = 0; - for (std::size_t i = 0; i < 1000; i++) { - placebo += core_timing.GetGlobalTimeNs().count(); - } - u64 end = core_timing.GetGlobalTimeNs().count(); - return (end - start); -} - -#pragma optimize("", on) - -TEST_CASE("HostTiming[BasicOrder]", "[core]") { - ScopeInit guard; - auto& core_timing = guard.core_timing; - std::vector<std::shared_ptr<Core::HostTiming::EventType>> events{ - Core::HostTiming::CreateEvent("callbackA", HostCallbackTemplate<0>), - Core::HostTiming::CreateEvent("callbackB", HostCallbackTemplate<1>), - Core::HostTiming::CreateEvent("callbackC", HostCallbackTemplate<2>), - Core::HostTiming::CreateEvent("callbackD", HostCallbackTemplate<3>), - Core::HostTiming::CreateEvent("callbackE", HostCallbackTemplate<4>), - }; - - expected_callback = 0; - - core_timing.SyncPause(true); - - u64 one_micro = 1000U; - for (std::size_t i = 0; i < events.size(); i++) { - u64 order = calls_order[i]; - core_timing.ScheduleEvent(i * one_micro + 100U, events[order], CB_IDS[order]); - } - /// test pause - REQUIRE(callbacks_ran_flags.none()); - - core_timing.Pause(false); // No need to sync - - while (core_timing.HasPendingEvents()) - ; - - REQUIRE(callbacks_ran_flags.all()); - - for (std::size_t i = 0; i < delays.size(); i++) { - const double delay = static_cast<double>(delays[i]); - const double micro = delay / 1000.0f; - const double mili = micro / 1000.0f; - printf("HostTimer Pausing Delay[%zu]: %.3f %.6f\n", i, micro, mili); - } -} - -TEST_CASE("HostTiming[BasicOrderNoPausing]", "[core]") { - ScopeInit guard; - auto& core_timing = guard.core_timing; - std::vector<std::shared_ptr<Core::HostTiming::EventType>> events{ - Core::HostTiming::CreateEvent("callbackA", HostCallbackTemplate<0>), - Core::HostTiming::CreateEvent("callbackB", HostCallbackTemplate<1>), - Core::HostTiming::CreateEvent("callbackC", HostCallbackTemplate<2>), - Core::HostTiming::CreateEvent("callbackD", HostCallbackTemplate<3>), - Core::HostTiming::CreateEvent("callbackE", HostCallbackTemplate<4>), - }; - - core_timing.SyncPause(true); - core_timing.SyncPause(false); - - expected_callback = 0; - - u64 start = core_timing.GetGlobalTimeNs().count(); - u64 one_micro = 1000U; - for (std::size_t i = 0; i < events.size(); i++) { - u64 order = calls_order[i]; - core_timing.ScheduleEvent(i * one_micro + 100U, events[order], CB_IDS[order]); - } - u64 end = core_timing.GetGlobalTimeNs().count(); - const double scheduling_time = static_cast<double>(end - start); - const double timer_time = static_cast<double>(TestTimerSpeed(core_timing)); - - while (core_timing.HasPendingEvents()) - ; - - REQUIRE(callbacks_ran_flags.all()); - - for (std::size_t i = 0; i < delays.size(); i++) { - const double delay = static_cast<double>(delays[i]); - const double micro = delay / 1000.0f; - const double mili = micro / 1000.0f; - printf("HostTimer No Pausing Delay[%zu]: %.3f %.6f\n", i, micro, mili); - } - - const double micro = scheduling_time / 1000.0f; - const double mili = micro / 1000.0f; - printf("HostTimer No Pausing Scheduling Time: %.3f %.6f\n", micro, mili); - printf("HostTimer No Pausing Timer Time: %.3f %.6f\n", timer_time / 1000.f, - timer_time / 1000000.f); -} |