diff options
Diffstat (limited to 'src/contrib/SDL-3.2.20/test/testtimer.c')
-rw-r--r-- | src/contrib/SDL-3.2.20/test/testtimer.c | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/src/contrib/SDL-3.2.20/test/testtimer.c b/src/contrib/SDL-3.2.20/test/testtimer.c new file mode 100644 index 0000000..0f12dce --- /dev/null +++ b/src/contrib/SDL-3.2.20/test/testtimer.c | |||
@@ -0,0 +1,287 @@ | |||
1 | /* | ||
2 | Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org> | ||
3 | |||
4 | This software is provided 'as-is', without any express or implied | ||
5 | warranty. In no event will the authors be held liable for any damages | ||
6 | arising from the use of this software. | ||
7 | |||
8 | Permission is granted to anyone to use this software for any purpose, | ||
9 | including commercial applications, and to alter it and redistribute it | ||
10 | freely. | ||
11 | */ | ||
12 | |||
13 | /* Test program to check the resolution of the SDL timer on the current | ||
14 | platform | ||
15 | */ | ||
16 | #include <SDL3/SDL.h> | ||
17 | #include <SDL3/SDL_main.h> | ||
18 | #include <SDL3/SDL_test.h> | ||
19 | |||
20 | #define DEFAULT_RESOLUTION 1 | ||
21 | |||
22 | static int test_sdl_delay_within_bounds(void) { | ||
23 | const int testDelay = 100; | ||
24 | const int marginOfError = 25; | ||
25 | Uint64 result; | ||
26 | Uint64 result2; | ||
27 | Sint64 difference; | ||
28 | |||
29 | SDLTest_ResetAssertSummary(); | ||
30 | |||
31 | /* Get ticks count - should be non-zero by now */ | ||
32 | result = SDL_GetTicks(); | ||
33 | SDLTest_AssertPass("Call to SDL_GetTicks()"); | ||
34 | SDLTest_AssertCheck(result > 0, "Check result value, expected: >0, got: %" SDL_PRIu64, result); | ||
35 | |||
36 | /* Delay a bit longer and measure ticks and verify difference */ | ||
37 | SDL_Delay(testDelay); | ||
38 | SDLTest_AssertPass("Call to SDL_Delay(%d)", testDelay); | ||
39 | result2 = SDL_GetTicks(); | ||
40 | SDLTest_AssertPass("Call to SDL_GetTicks()"); | ||
41 | SDLTest_AssertCheck(result2 > 0, "Check result value, expected: >0, got: %" SDL_PRIu64, result2); | ||
42 | difference = result2 - result; | ||
43 | SDLTest_AssertCheck(difference > (testDelay - marginOfError), "Check difference, expected: >%d, got: %" SDL_PRIu64, testDelay - marginOfError, difference); | ||
44 | /* Disabled because this might fail on non-interactive systems. */ | ||
45 | SDLTest_AssertCheck(difference < (testDelay + marginOfError), "Check difference, expected: <%d, got: %" SDL_PRIu64, testDelay + marginOfError, difference); | ||
46 | |||
47 | return SDLTest_AssertSummaryToTestResult() == TEST_RESULT_PASSED ? 0 : 1; | ||
48 | } | ||
49 | |||
50 | static int ticks = 0; | ||
51 | |||
52 | static Uint32 SDLCALL | ||
53 | ticktock(void *param, SDL_TimerID timerID, Uint32 interval) | ||
54 | { | ||
55 | ++ticks; | ||
56 | return interval; | ||
57 | } | ||
58 | |||
59 | static Uint64 SDLCALL | ||
60 | ticktockNS(void *param, SDL_TimerID timerID, Uint64 interval) | ||
61 | { | ||
62 | ++ticks; | ||
63 | return interval; | ||
64 | } | ||
65 | |||
66 | static Uint32 SDLCALL | ||
67 | callback(void *param, SDL_TimerID timerID, Uint32 interval) | ||
68 | { | ||
69 | int value = (int)(uintptr_t)param; | ||
70 | SDL_assert( value == 1 || value == 2 || value == 3 ); | ||
71 | SDL_Log("Timer %" SDL_PRIu32 " : param = %d", interval, value); | ||
72 | return interval; | ||
73 | } | ||
74 | |||
75 | int main(int argc, char *argv[]) | ||
76 | { | ||
77 | int i; | ||
78 | int desired = -1; | ||
79 | SDL_TimerID t1, t2, t3; | ||
80 | Uint64 start, now; | ||
81 | Uint64 start_perf, now_perf; | ||
82 | SDLTest_CommonState *state; | ||
83 | bool run_interactive_tests = true; | ||
84 | int return_code = 0; | ||
85 | |||
86 | /* Initialize test framework */ | ||
87 | state = SDLTest_CommonCreateState(argv, 0); | ||
88 | if (!state) { | ||
89 | return 1; | ||
90 | } | ||
91 | |||
92 | /* Parse commandline */ | ||
93 | for (i = 1; i < argc;) { | ||
94 | int consumed; | ||
95 | |||
96 | consumed = SDLTest_CommonArg(state, i); | ||
97 | if (!consumed) { | ||
98 | if (SDL_strcmp(argv[i], "--no-interactive") == 0) { | ||
99 | run_interactive_tests = false; | ||
100 | consumed = 1; | ||
101 | } else if (desired < 0) { | ||
102 | char *endptr; | ||
103 | |||
104 | desired = SDL_strtoul(argv[i], &endptr, 0); | ||
105 | if (desired != 0 && endptr != argv[i] && *endptr == '\0') { | ||
106 | consumed = 1; | ||
107 | } | ||
108 | } | ||
109 | } | ||
110 | if (consumed <= 0) { | ||
111 | static const char *options[] = { "[--no-interactive]", "[interval]", NULL }; | ||
112 | SDLTest_CommonLogUsage(state, argv[0], options); | ||
113 | return 1; | ||
114 | } | ||
115 | |||
116 | i += consumed; | ||
117 | } | ||
118 | |||
119 | if (SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SDL_TESTS_QUICK") != NULL) { | ||
120 | SDL_Log("Not running slower tests"); | ||
121 | SDL_Quit(); | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | /* Verify SDL_GetTicks* acts monotonically increasing, and not erratic. */ | ||
126 | SDL_Log("Sanity-checking GetTicks"); | ||
127 | for (i = 0; i < 1000; ++i) { | ||
128 | start = SDL_GetTicks(); | ||
129 | SDL_Delay(1); | ||
130 | now = SDL_GetTicks() - start; | ||
131 | if (now > 100) { | ||
132 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "testtimer.c: Delta time erratic at iter %d. Delay 1ms = %d ms in ticks", i, (int)now); | ||
133 | SDL_Quit(); | ||
134 | return 1; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | /* Start the millisecond timer */ | ||
139 | if (desired < 0) { | ||
140 | desired = DEFAULT_RESOLUTION; | ||
141 | } | ||
142 | ticks = 0; | ||
143 | t1 = SDL_AddTimer(desired, ticktock, NULL); | ||
144 | |||
145 | /* Wait 1 seconds */ | ||
146 | SDL_Log("Waiting 1 seconds for millisecond timer"); | ||
147 | SDL_Delay(1 * 1000); | ||
148 | |||
149 | /* Stop the timer */ | ||
150 | SDL_RemoveTimer(t1); | ||
151 | |||
152 | /* Print the results */ | ||
153 | if (ticks) { | ||
154 | SDL_Log("Millisecond timer resolution: desired = %d ms, actual = %f ms", | ||
155 | desired, (double)(10 * 1000) / ticks); | ||
156 | } | ||
157 | |||
158 | /* Wait for the results to be seen */ | ||
159 | SDL_Delay(1 * 1000); | ||
160 | |||
161 | /* Start the nanosecond timer */ | ||
162 | ticks = 0; | ||
163 | t1 = SDL_AddTimerNS(desired, ticktockNS, NULL); | ||
164 | |||
165 | /* Wait 1 seconds */ | ||
166 | SDL_Log("Waiting 1 seconds for nanosecond timer"); | ||
167 | SDL_Delay(1 * 1000); | ||
168 | |||
169 | /* Stop the timer */ | ||
170 | SDL_RemoveTimer(t1); | ||
171 | |||
172 | /* Print the results */ | ||
173 | if (ticks) { | ||
174 | SDL_Log("Nanosecond timer resolution: desired = %d ns, actual = %f ns", | ||
175 | desired, (double)(10 * 1000000) / ticks); | ||
176 | } | ||
177 | |||
178 | /* Wait for the results to be seen */ | ||
179 | SDL_Delay(1 * 1000); | ||
180 | |||
181 | /* Check accuracy of nanosecond delay */ | ||
182 | { | ||
183 | Uint64 desired_delay = SDL_NS_PER_SECOND / 60; | ||
184 | Uint64 actual_delay; | ||
185 | Uint64 total_overslept = 0; | ||
186 | |||
187 | start = SDL_GetTicksNS(); | ||
188 | SDL_DelayNS(1); | ||
189 | now = SDL_GetTicksNS(); | ||
190 | actual_delay = (now - start); | ||
191 | SDL_Log("Minimum nanosecond delay: %" SDL_PRIu64 " ns", actual_delay); | ||
192 | |||
193 | SDL_Log("Timing 100 frames at 60 FPS"); | ||
194 | for (i = 0; i < 100; ++i) { | ||
195 | start = SDL_GetTicksNS(); | ||
196 | SDL_DelayNS(desired_delay); | ||
197 | now = SDL_GetTicksNS(); | ||
198 | actual_delay = (now - start); | ||
199 | if (actual_delay > desired_delay) { | ||
200 | total_overslept += (actual_delay - desired_delay); | ||
201 | } | ||
202 | } | ||
203 | SDL_Log("Overslept %.2f ms", (double)total_overslept / SDL_NS_PER_MS); | ||
204 | } | ||
205 | |||
206 | /* Wait for the results to be seen */ | ||
207 | SDL_Delay(1 * 1000); | ||
208 | |||
209 | /* Check accuracy of precise delay */ | ||
210 | { | ||
211 | Uint64 desired_delay = SDL_NS_PER_SECOND / 60; | ||
212 | Uint64 actual_delay; | ||
213 | Uint64 total_overslept = 0; | ||
214 | |||
215 | start = SDL_GetTicksNS(); | ||
216 | SDL_DelayPrecise(1); | ||
217 | now = SDL_GetTicksNS(); | ||
218 | actual_delay = (now - start); | ||
219 | SDL_Log("Minimum precise delay: %" SDL_PRIu64 " ns", actual_delay); | ||
220 | |||
221 | SDL_Log("Timing 100 frames at 60 FPS"); | ||
222 | for (i = 0; i < 100; ++i) { | ||
223 | start = SDL_GetTicksNS(); | ||
224 | SDL_DelayPrecise(desired_delay); | ||
225 | now = SDL_GetTicksNS(); | ||
226 | actual_delay = (now - start); | ||
227 | if (actual_delay > desired_delay) { | ||
228 | total_overslept += (actual_delay - desired_delay); | ||
229 | } | ||
230 | } | ||
231 | SDL_Log("Overslept %.2f ms", (double)total_overslept / SDL_NS_PER_MS); | ||
232 | } | ||
233 | |||
234 | /* Wait for the results to be seen */ | ||
235 | SDL_Delay(1 * 1000); | ||
236 | |||
237 | /* Test multiple timers */ | ||
238 | SDL_Log("Testing multiple timers..."); | ||
239 | t1 = SDL_AddTimer(100, callback, (void *)1); | ||
240 | if (!t1) { | ||
241 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create timer 1: %s", SDL_GetError()); | ||
242 | } | ||
243 | t2 = SDL_AddTimer(50, callback, (void *)2); | ||
244 | if (!t2) { | ||
245 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create timer 2: %s", SDL_GetError()); | ||
246 | } | ||
247 | t3 = SDL_AddTimer(233, callback, (void *)3); | ||
248 | if (!t3) { | ||
249 | SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Could not create timer 3: %s", SDL_GetError()); | ||
250 | } | ||
251 | |||
252 | /* Wait 3 seconds */ | ||
253 | SDL_Log("Waiting 3 seconds"); | ||
254 | SDL_Delay(3 * 1000); | ||
255 | |||
256 | SDL_Log("Removing timer 1 and waiting 3 more seconds"); | ||
257 | SDL_RemoveTimer(t1); | ||
258 | |||
259 | SDL_Delay(3 * 1000); | ||
260 | |||
261 | SDL_RemoveTimer(t2); | ||
262 | SDL_RemoveTimer(t3); | ||
263 | |||
264 | ticks = 0; | ||
265 | start_perf = SDL_GetPerformanceCounter(); | ||
266 | for (i = 0; i < 1000000; ++i) { | ||
267 | ticktock(NULL, 0, 0); | ||
268 | } | ||
269 | now_perf = SDL_GetPerformanceCounter(); | ||
270 | SDL_Log("1 million iterations of ticktock took %f ms", (double)((now_perf - start_perf) * 1000) / SDL_GetPerformanceFrequency()); | ||
271 | |||
272 | SDL_Log("Performance counter frequency: %" SDL_PRIu64, SDL_GetPerformanceFrequency()); | ||
273 | start = SDL_GetTicks(); | ||
274 | start_perf = SDL_GetPerformanceCounter(); | ||
275 | SDL_Delay(1000); | ||
276 | now_perf = SDL_GetPerformanceCounter(); | ||
277 | now = SDL_GetTicks(); | ||
278 | SDL_Log("Delay 1 second = %d ms in ticks, %f ms according to performance counter", (int)(now - start), (double)((now_perf - start_perf) * 1000) / SDL_GetPerformanceFrequency()); | ||
279 | |||
280 | if (run_interactive_tests) { | ||
281 | return_code = test_sdl_delay_within_bounds(); | ||
282 | } | ||
283 | |||
284 | SDL_Quit(); | ||
285 | SDLTest_CommonDestroyState(state); | ||
286 | return return_code; | ||
287 | } | ||