summaryrefslogtreecommitdiff
path: root/src/tests/core
diff options
context:
space:
mode:
authorGravatar B3n302017-11-25 14:56:57 +0100
committerGravatar bunnei2018-01-08 19:10:25 -0500
commit82151d407d8021fa8865cf8dd51c4d5cf0a4b702 (patch)
tree739df280fddbecb50e1a2fa690abe8749486ea2d /src/tests/core
parentIPC: Make DuplicateSession return the Domain instead of the Session if the re... (diff)
downloadyuzu-82151d407d8021fa8865cf8dd51c4d5cf0a4b702.tar.gz
yuzu-82151d407d8021fa8865cf8dd51c4d5cf0a4b702.tar.xz
yuzu-82151d407d8021fa8865cf8dd51c4d5cf0a4b702.zip
CoreTiming: Reworked CoreTiming (cherry-picked from Citra #3119)
* CoreTiming: New CoreTiming; Add Test for CoreTiming
Diffstat (limited to 'src/tests/core')
-rw-r--r--src/tests/core/core_timing.cpp237
1 files changed, 237 insertions, 0 deletions
diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp
new file mode 100644
index 000000000..fcaa30990
--- /dev/null
+++ b/src/tests/core/core_timing.cpp
@@ -0,0 +1,237 @@
1// Copyright 2016 Dolphin Emulator Project / 2017 Dolphin Emulator Project
2// Licensed under GPLv2+
3// Refer to the license.txt file included.
4
5#include <catch.hpp>
6
7#include <array>
8#include <bitset>
9#include <string>
10#include "common/file_util.h"
11#include "core/core.h"
12#include "core/core_timing.h"
13
14// Numbers are chosen randomly to make sure the correct one is given.
15static constexpr std::array<u64, 5> CB_IDS{{42, 144, 93, 1026, UINT64_C(0xFFFF7FFFF7FFFF)}};
16static constexpr int MAX_SLICE_LENGTH = 20000; // Copied from CoreTiming internals
17
18static std::bitset<CB_IDS.size()> callbacks_ran_flags;
19static u64 expected_callback = 0;
20static s64 lateness = 0;
21
22template <unsigned int IDX>
23void CallbackTemplate(u64 userdata, s64 cycles_late) {
24 static_assert(IDX < CB_IDS.size(), "IDX out of range");
25 callbacks_ran_flags.set(IDX);
26 REQUIRE(CB_IDS[IDX] == userdata);
27 REQUIRE(CB_IDS[IDX] == expected_callback);
28 REQUIRE(lateness == cycles_late);
29}
30
31class ScopeInit final {
32public:
33 ScopeInit() {
34 CoreTiming::Init();
35 }
36 ~ScopeInit() {
37 CoreTiming::Shutdown();
38 }
39};
40
41static void AdvanceAndCheck(u32 idx, int downcount, int expected_lateness = 0,
42 int cpu_downcount = 0) {
43 callbacks_ran_flags = 0;
44 expected_callback = CB_IDS[idx];
45 lateness = expected_lateness;
46
47 CoreTiming::AddTicks(CoreTiming::GetDowncount() -
48 cpu_downcount); // Pretend we executed X cycles of instructions.
49 CoreTiming::Advance();
50
51 REQUIRE(decltype(callbacks_ran_flags)().set(idx) == callbacks_ran_flags);
52 REQUIRE(downcount == CoreTiming::GetDowncount());
53}
54
55TEST_CASE("CoreTiming[BasicOrder]", "[core]") {
56 ScopeInit guard;
57
58 CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
59 CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
60 CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>);
61 CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", CallbackTemplate<3>);
62 CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", CallbackTemplate<4>);
63
64 // Enter slice 0
65 CoreTiming::Advance();
66
67 // D -> B -> C -> A -> E
68 CoreTiming::ScheduleEvent(1000, cb_a, CB_IDS[0]);
69 REQUIRE(1000 == CoreTiming::GetDowncount());
70 CoreTiming::ScheduleEvent(500, cb_b, CB_IDS[1]);
71 REQUIRE(500 == CoreTiming::GetDowncount());
72 CoreTiming::ScheduleEvent(800, cb_c, CB_IDS[2]);
73 REQUIRE(500 == CoreTiming::GetDowncount());
74 CoreTiming::ScheduleEvent(100, cb_d, CB_IDS[3]);
75 REQUIRE(100 == CoreTiming::GetDowncount());
76 CoreTiming::ScheduleEvent(1200, cb_e, CB_IDS[4]);
77 REQUIRE(100 == CoreTiming::GetDowncount());
78
79 AdvanceAndCheck(3, 400);
80 AdvanceAndCheck(1, 300);
81 AdvanceAndCheck(2, 200);
82 AdvanceAndCheck(0, 200);
83 AdvanceAndCheck(4, MAX_SLICE_LENGTH);
84}
85
86TEST_CASE("CoreTiming[Threadsave]", "[core]") {
87 ScopeInit guard;
88
89 CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
90 CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
91 CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>);
92 CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", CallbackTemplate<3>);
93 CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", CallbackTemplate<4>);
94
95 // Enter slice 0
96 CoreTiming::Advance();
97
98 // D -> B -> C -> A -> E
99 CoreTiming::ScheduleEventThreadsafe(1000, cb_a, CB_IDS[0]);
100 // Manually force since ScheduleEventThreadsafe doesn't call it
101 CoreTiming::ForceExceptionCheck(1000);
102 REQUIRE(1000 == CoreTiming::GetDowncount());
103 CoreTiming::ScheduleEventThreadsafe(500, cb_b, CB_IDS[1]);
104 // Manually force since ScheduleEventThreadsafe doesn't call it
105 CoreTiming::ForceExceptionCheck(500);
106 REQUIRE(500 == CoreTiming::GetDowncount());
107 CoreTiming::ScheduleEventThreadsafe(800, cb_c, CB_IDS[2]);
108 // Manually force since ScheduleEventThreadsafe doesn't call it
109 CoreTiming::ForceExceptionCheck(800);
110 REQUIRE(500 == CoreTiming::GetDowncount());
111 CoreTiming::ScheduleEventThreadsafe(100, cb_d, CB_IDS[3]);
112 // Manually force since ScheduleEventThreadsafe doesn't call it
113 CoreTiming::ForceExceptionCheck(100);
114 REQUIRE(100 == CoreTiming::GetDowncount());
115 CoreTiming::ScheduleEventThreadsafe(1200, cb_e, CB_IDS[4]);
116 // Manually force since ScheduleEventThreadsafe doesn't call it
117 CoreTiming::ForceExceptionCheck(1200);
118 REQUIRE(100 == CoreTiming::GetDowncount());
119
120 AdvanceAndCheck(3, 400);
121 AdvanceAndCheck(1, 300);
122 AdvanceAndCheck(2, 200);
123 AdvanceAndCheck(0, 200);
124 AdvanceAndCheck(4, MAX_SLICE_LENGTH);
125}
126
127namespace SharedSlotTest {
128static unsigned int counter = 0;
129
130template <unsigned int ID>
131void FifoCallback(u64 userdata, s64 cycles_late) {
132 static_assert(ID < CB_IDS.size(), "ID out of range");
133 callbacks_ran_flags.set(ID);
134 REQUIRE(CB_IDS[ID] == userdata);
135 REQUIRE(ID == counter);
136 REQUIRE(lateness == cycles_late);
137 ++counter;
138}
139} // namespace SharedSlotTest
140
141TEST_CASE("CoreTiming[SharedSlot]", "[core]") {
142 using namespace SharedSlotTest;
143
144 ScopeInit guard;
145
146 CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", FifoCallback<0>);
147 CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", FifoCallback<1>);
148 CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", FifoCallback<2>);
149 CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", FifoCallback<3>);
150 CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", FifoCallback<4>);
151
152 CoreTiming::ScheduleEvent(1000, cb_a, CB_IDS[0]);
153 CoreTiming::ScheduleEvent(1000, cb_b, CB_IDS[1]);
154 CoreTiming::ScheduleEvent(1000, cb_c, CB_IDS[2]);
155 CoreTiming::ScheduleEvent(1000, cb_d, CB_IDS[3]);
156 CoreTiming::ScheduleEvent(1000, cb_e, CB_IDS[4]);
157
158 // Enter slice 0
159 CoreTiming::Advance();
160 REQUIRE(1000 == CoreTiming::GetDowncount());
161
162 callbacks_ran_flags = 0;
163 counter = 0;
164 lateness = 0;
165 CoreTiming::AddTicks(CoreTiming::GetDowncount());
166 CoreTiming::Advance();
167 REQUIRE(MAX_SLICE_LENGTH == CoreTiming::GetDowncount());
168 REQUIRE(0x1FULL == callbacks_ran_flags.to_ullong());
169}
170
171TEST_CASE("CoreTiming[PredictableLateness]", "[core]") {
172 ScopeInit guard;
173
174 CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
175 CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
176
177 // Enter slice 0
178 CoreTiming::Advance();
179
180 CoreTiming::ScheduleEvent(100, cb_a, CB_IDS[0]);
181 CoreTiming::ScheduleEvent(200, cb_b, CB_IDS[1]);
182
183 AdvanceAndCheck(0, 90, 10, -10); // (100 - 10)
184 AdvanceAndCheck(1, MAX_SLICE_LENGTH, 50, -50);
185}
186
187namespace ChainSchedulingTest {
188static int reschedules = 0;
189
190static void RescheduleCallback(u64 userdata, s64 cycles_late) {
191 --reschedules;
192 REQUIRE(reschedules >= 0);
193 REQUIRE(lateness == cycles_late);
194
195 if (reschedules > 0)
196 CoreTiming::ScheduleEvent(1000, reinterpret_cast<CoreTiming::EventType*>(userdata),
197 userdata);
198}
199} // namespace ChainSchedulingTest
200
201TEST_CASE("CoreTiming[ChainScheduling]", "[core]") {
202 using namespace ChainSchedulingTest;
203
204 ScopeInit guard;
205
206 CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>);
207 CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>);
208 CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>);
209 CoreTiming::EventType* cb_rs =
210 CoreTiming::RegisterEvent("callbackReschedule", RescheduleCallback);
211
212 // Enter slice 0
213 CoreTiming::Advance();
214
215 CoreTiming::ScheduleEvent(800, cb_a, CB_IDS[0]);
216 CoreTiming::ScheduleEvent(1000, cb_b, CB_IDS[1]);
217 CoreTiming::ScheduleEvent(2200, cb_c, CB_IDS[2]);
218 CoreTiming::ScheduleEvent(1000, cb_rs, reinterpret_cast<u64>(cb_rs));
219 REQUIRE(800 == CoreTiming::GetDowncount());
220
221 reschedules = 3;
222 AdvanceAndCheck(0, 200); // cb_a
223 AdvanceAndCheck(1, 1000); // cb_b, cb_rs
224 REQUIRE(2 == reschedules);
225
226 CoreTiming::AddTicks(CoreTiming::GetDowncount());
227 CoreTiming::Advance(); // cb_rs
228 REQUIRE(1 == reschedules);
229 REQUIRE(200 == CoreTiming::GetDowncount());
230
231 AdvanceAndCheck(2, 800); // cb_c
232
233 CoreTiming::AddTicks(CoreTiming::GetDowncount());
234 CoreTiming::Advance(); // cb_rs
235 REQUIRE(0 == reschedules);
236 REQUIRE(MAX_SLICE_LENGTH == CoreTiming::GetDowncount());
237}