2015-06-21 17:33:46 +02:00
/*
2024-01-01 13:15:26 -08:00
Copyright ( C ) 1997 - 2024 Sam Lantinga < slouken @ libsdl . org >
2015-06-21 17:33:46 +02:00
This software is provided ' as - is ' , without any express or implied
warranty . In no event will the authors be held liable for any damages
arising from the use of this software .
Permission is granted to anyone to use this software for any purpose ,
including commercial applications , and to alter it and redistribute it
freely .
*/
/* Test program to check the resolution of the SDL timer on the current
platform
*/
2022-11-26 20:43:38 -08:00
# include <SDL3/SDL.h>
2022-12-15 05:58:20 +01:00
# include <SDL3/SDL_main.h>
2023-03-17 00:25:39 +01:00
# include <SDL3/SDL_test.h>
2015-06-21 17:33:46 +02:00
2022-11-30 12:51:59 -08:00
# define DEFAULT_RESOLUTION 1
2015-06-21 17:33:46 +02:00
2023-08-29 00:03:05 +02:00
static int test_sdl_delay_within_bounds ( void ) {
const int testDelay = 100 ;
const int marginOfError = 25 ;
Uint64 result ;
Uint64 result2 ;
Sint64 difference ;
SDLTest_ResetAssertSummary ( ) ;
/* Get ticks count - should be non-zero by now */
result = SDL_GetTicks ( ) ;
SDLTest_AssertPass ( " Call to SDL_GetTicks() " ) ;
SDLTest_AssertCheck ( result > 0 , " Check result value, expected: >0, got: % " SDL_PRIu64 , result ) ;
/* Delay a bit longer and measure ticks and verify difference */
SDL_Delay ( testDelay ) ;
SDLTest_AssertPass ( " Call to SDL_Delay(%d) " , testDelay ) ;
result2 = SDL_GetTicks ( ) ;
SDLTest_AssertPass ( " Call to SDL_GetTicks() " ) ;
SDLTest_AssertCheck ( result2 > 0 , " Check result value, expected: >0, got: % " SDL_PRIu64 , result2 ) ;
difference = result2 - result ;
SDLTest_AssertCheck ( difference > ( testDelay - marginOfError ) , " Check difference, expected: >%d, got: % " SDL_PRIu64 , testDelay - marginOfError , difference ) ;
/* Disabled because this might fail on non-interactive systems. */
SDLTest_AssertCheck ( difference < ( testDelay + marginOfError ) , " Check difference, expected: <%d, got: % " SDL_PRIu64 , testDelay + marginOfError , difference ) ;
return SDLTest_AssertSummaryToTestResult ( ) = = TEST_RESULT_PASSED ? 0 : 1 ;
}
2015-06-21 17:33:46 +02:00
static int ticks = 0 ;
static Uint32 SDLCALL
2024-05-26 17:56:29 -07:00
ticktock ( void * param , SDL_TimerID timerID , Uint32 interval )
2015-06-21 17:33:46 +02:00
{
+ + ticks ;
2022-11-27 17:38:43 +01:00
return interval ;
2015-06-21 17:33:46 +02:00
}
2024-05-27 06:30:37 -07:00
static Uint64 SDLCALL
ticktockNS ( void * param , SDL_TimerID timerID , Uint64 interval )
{
+ + ticks ;
return interval ;
}
2015-06-21 17:33:46 +02:00
static Uint32 SDLCALL
2024-05-26 17:56:29 -07:00
callback ( void * param , SDL_TimerID timerID , Uint32 interval )
2015-06-21 17:33:46 +02:00
{
2024-05-26 17:56:29 -07:00
int value = ( int ) ( uintptr_t ) param ;
SDL_assert ( value = = 1 | | value = = 2 | | value = = 3 ) ;
SDL_Log ( " Timer % " SDL_PRIu32 " : param = %d \n " , interval , value ) ;
2015-06-21 17:33:46 +02:00
return interval ;
}
2022-11-30 12:51:59 -08:00
int main ( int argc , char * argv [ ] )
2015-06-21 17:33:46 +02:00
{
2023-03-17 00:25:39 +01:00
int i ;
int desired = - 1 ;
2015-06-21 17:33:46 +02:00
SDL_TimerID t1 , t2 , t3 ;
Uint64 start , now ;
2022-12-02 01:17:17 -08:00
Uint64 start_perf , now_perf ;
2023-03-17 00:25:39 +01:00
SDLTest_CommonState * state ;
2023-08-29 00:03:05 +02:00
SDL_bool run_interactive_tests = SDL_TRUE ;
int return_code = 0 ;
2023-03-17 00:25:39 +01:00
/* Initialize test framework */
state = SDLTest_CommonCreateState ( argv , 0 ) ;
2023-11-09 22:29:15 +01:00
if ( ! state ) {
2023-03-17 00:25:39 +01:00
return 1 ;
}
2015-06-21 17:33:46 +02:00
2015-11-25 21:39:28 +01:00
/* Enable standard application logging */
2024-05-16 10:00:50 -07:00
SDL_SetLogPriority ( SDL_LOG_CATEGORY_APPLICATION , SDL_LOG_PRIORITY_INFO ) ;
2015-06-21 17:33:46 +02:00
2023-03-17 00:25:39 +01:00
/* Parse commandline */
for ( i = 1 ; i < argc ; ) {
int consumed ;
consumed = SDLTest_CommonArg ( state , i ) ;
if ( ! consumed ) {
2023-08-29 00:03:05 +02:00
if ( SDL_strcmp ( argv [ i ] , " --no-interactive " ) = = 0 ) {
run_interactive_tests = SDL_FALSE ;
consumed = 1 ;
} else if ( desired < 0 ) {
2023-03-17 00:25:39 +01:00
char * endptr ;
desired = SDL_strtoul ( argv [ i ] , & endptr , 0 ) ;
if ( desired ! = 0 & & endptr ! = argv [ i ] & & * endptr = = ' \0 ' ) {
consumed = 1 ;
}
}
}
if ( consumed < = 0 ) {
2023-08-29 00:03:05 +02:00
static const char * options [ ] = { " [--no-interactive] " , " [interval] " , NULL } ;
2023-03-17 00:25:39 +01:00
SDLTest_CommonLogUsage ( state , argv [ 0 ] , options ) ;
return 1 ;
}
i + = consumed ;
}
2015-06-21 17:33:46 +02:00
if ( SDL_Init ( SDL_INIT_TIMER ) < 0 ) {
SDL_LogError ( SDL_LOG_CATEGORY_APPLICATION , " Couldn't initialize SDL: %s \n " , SDL_GetError ( ) ) ;
2022-11-27 17:38:43 +01:00
return 1 ;
2015-06-21 17:33:46 +02:00
}
2022-05-04 19:16:01 +01:00
if ( SDL_getenv ( " SDL_TESTS_QUICK " ) ! = NULL ) {
SDL_Log ( " Not running slower tests " ) ;
SDL_Quit ( ) ;
return 0 ;
}
2021-11-02 18:58:06 +01:00
/* Verify SDL_GetTicks* acts monotonically increasing, and not erratic. */
SDL_Log ( " Sanity-checking GetTicks \n " ) ;
for ( i = 0 ; i < 1000 ; + + i ) {
2022-12-02 01:17:17 -08:00
start = SDL_GetTicks ( ) ;
2021-11-02 18:58:06 +01:00
SDL_Delay ( 1 ) ;
2022-12-02 01:17:17 -08:00
now = SDL_GetTicks ( ) - start ;
if ( now > 100 ) {
SDL_LogError ( SDL_LOG_CATEGORY_APPLICATION , " testtimer.c: Delta time erratic at iter %d. Delay 1ms = %d ms in ticks \n " , i , ( int ) now ) ;
2021-11-02 18:58:06 +01:00
SDL_Quit ( ) ;
return 1 ;
}
}
2024-05-27 06:30:37 -07:00
/* Start the millisecond timer */
2023-03-17 00:25:39 +01:00
if ( desired < 0 ) {
2015-06-21 17:33:46 +02:00
desired = DEFAULT_RESOLUTION ;
}
2024-05-27 06:30:37 -07:00
ticks = 0 ;
2015-06-21 17:33:46 +02:00
t1 = SDL_AddTimer ( desired , ticktock , NULL ) ;
2024-05-27 06:30:37 -07:00
/* Wait 1 seconds */
SDL_Log ( " Waiting 1 seconds for millisecond timer \n " ) ;
SDL_Delay ( 1 * 1000 ) ;
2015-06-21 17:33:46 +02:00
/* Stop the timer */
SDL_RemoveTimer ( t1 ) ;
/* Print the results */
if ( ticks ) {
2024-05-27 06:30:37 -07:00
SDL_Log ( " Millisecond timer resolution: desired = %d ms, actual = %f ms \n " ,
2022-11-30 12:51:59 -08:00
desired , ( double ) ( 10 * 1000 ) / ticks ) ;
2015-06-21 17:33:46 +02:00
}
2024-05-27 06:30:37 -07:00
/* Wait for the results to be seen */
SDL_Delay ( 1 * 1000 ) ;
/* Start the nanosecond timer */
ticks = 0 ;
t1 = SDL_AddTimerNS ( desired , ticktockNS , NULL ) ;
/* Wait 1 seconds */
SDL_Log ( " Waiting 1 seconds for nanosecond timer \n " ) ;
SDL_Delay ( 1 * 1000 ) ;
/* Stop the timer */
SDL_RemoveTimer ( t1 ) ;
/* Print the results */
if ( ticks ) {
SDL_Log ( " Nanosecond timer resolution: desired = %d ns, actual = %f ns \n " ,
desired , ( double ) ( 10 * 1000000 ) / ticks ) ;
}
/* Wait for the results to be seen */
SDL_Delay ( 1 * 1000 ) ;
2024-07-15 18:05:31 -07:00
/* Check accuracy of precise delay */
{
Uint64 desired_delay = SDL_NS_PER_SECOND / 60 ;
Uint64 actual_delay ;
Uint64 total_overslept = 0 ;
start = SDL_GetTicksNS ( ) ;
SDL_DelayNS ( 1 ) ;
now = SDL_GetTicksNS ( ) ;
actual_delay = ( now - start ) ;
SDL_Log ( " Minimum precise delay: % " SDL_PRIu64 " ns \n " , actual_delay ) ;
SDL_Log ( " Timing 100 frames at 60 FPS \n " ) ;
for ( i = 0 ; i < 100 ; + + i ) {
start = SDL_GetTicksNS ( ) ;
SDL_DelayNS ( desired_delay ) ;
now = SDL_GetTicksNS ( ) ;
actual_delay = ( now - start ) ;
if ( actual_delay > desired_delay ) {
total_overslept + = ( actual_delay - desired_delay ) ;
}
}
SDL_Log ( " Overslept %.2f ms \n " , ( double ) total_overslept / SDL_NS_PER_MS ) ;
}
/* Wait for the results to be seen */
SDL_Delay ( 1 * 1000 ) ;
2015-06-21 17:33:46 +02:00
/* Test multiple timers */
SDL_Log ( " Testing multiple timers... \n " ) ;
2022-11-30 12:51:59 -08:00
t1 = SDL_AddTimer ( 100 , callback , ( void * ) 1 ) ;
2022-11-27 17:38:43 +01:00
if ( ! t1 ) {
SDL_LogError ( SDL_LOG_CATEGORY_APPLICATION , " Could not create timer 1: %s \n " , SDL_GetError ( ) ) ;
}
2022-11-30 12:51:59 -08:00
t2 = SDL_AddTimer ( 50 , callback , ( void * ) 2 ) ;
2022-11-27 17:38:43 +01:00
if ( ! t2 ) {
SDL_LogError ( SDL_LOG_CATEGORY_APPLICATION , " Could not create timer 2: %s \n " , SDL_GetError ( ) ) ;
}
2022-11-30 12:51:59 -08:00
t3 = SDL_AddTimer ( 233 , callback , ( void * ) 3 ) ;
2022-11-27 17:38:43 +01:00
if ( ! t3 ) {
SDL_LogError ( SDL_LOG_CATEGORY_APPLICATION , " Could not create timer 3: %s \n " , SDL_GetError ( ) ) ;
}
2015-06-21 17:33:46 +02:00
2024-05-27 06:30:37 -07:00
/* Wait 3 seconds */
SDL_Log ( " Waiting 3 seconds \n " ) ;
SDL_Delay ( 3 * 1000 ) ;
2015-06-21 17:33:46 +02:00
2024-05-27 06:30:37 -07:00
SDL_Log ( " Removing timer 1 and waiting 3 more seconds \n " ) ;
2015-06-21 17:33:46 +02:00
SDL_RemoveTimer ( t1 ) ;
2024-05-27 06:30:37 -07:00
SDL_Delay ( 3 * 1000 ) ;
2015-06-21 17:33:46 +02:00
SDL_RemoveTimer ( t2 ) ;
SDL_RemoveTimer ( t3 ) ;
2024-05-27 06:30:37 -07:00
ticks = 0 ;
2022-12-02 01:17:17 -08:00
start_perf = SDL_GetPerformanceCounter ( ) ;
2015-06-21 17:33:46 +02:00
for ( i = 0 ; i < 1000000 ; + + i ) {
2024-05-26 17:56:29 -07:00
ticktock ( NULL , 0 , 0 ) ;
2015-06-21 17:33:46 +02:00
}
2022-12-02 01:17:17 -08:00
now_perf = SDL_GetPerformanceCounter ( ) ;
SDL_Log ( " 1 million iterations of ticktock took %f ms \n " , ( double ) ( ( now_perf - start_perf ) * 1000 ) / SDL_GetPerformanceFrequency ( ) ) ;
2015-06-21 17:33:46 +02:00
2022-11-30 12:51:59 -08:00
SDL_Log ( " Performance counter frequency: % " SDL_PRIu64 " \n " , SDL_GetPerformanceFrequency ( ) ) ;
2022-12-02 01:17:17 -08:00
start = SDL_GetTicks ( ) ;
start_perf = SDL_GetPerformanceCounter ( ) ;
2015-06-21 17:33:46 +02:00
SDL_Delay ( 1000 ) ;
2022-12-02 01:17:17 -08:00
now_perf = SDL_GetPerformanceCounter ( ) ;
now = SDL_GetTicks ( ) ;
SDL_Log ( " Delay 1 second = %d ms in ticks, %f ms according to performance counter \n " , ( int ) ( now - start ) , ( double ) ( ( now_perf - start_perf ) * 1000 ) / SDL_GetPerformanceFrequency ( ) ) ;
2015-06-21 17:33:46 +02:00
2023-08-29 00:03:05 +02:00
if ( run_interactive_tests ) {
return_code = test_sdl_delay_within_bounds ( ) ;
}
2023-03-17 00:25:39 +01:00
SDLTest_CommonDestroyState ( state ) ;
2015-06-21 17:33:46 +02:00
SDL_Quit ( ) ;
2023-08-29 00:03:05 +02:00
return return_code ;
2015-06-21 17:33:46 +02:00
}