From 2f22a5638d3bde7450110bd088a8a9bb5ec857d6 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Fri, 15 May 2020 06:55:04 -0600 Subject: [PATCH] windows: finer granularity for sleep The Windows scheduler tends to work on 16ms bounaries, which is not good for sleeping (as part of an animation, say) for times near or less than 16ms. Change rktio to request more fine-grained scheduling temporarily when trying to sleep for a short time. --- racket/src/rktio/rktio_poll_set.c | 28 ++++++++++++++++++- racket/src/worksp/cs/Makefile | 2 +- racket/src/worksp/gc2/make.rkt | 2 +- racket/src/worksp/libracket/libracket.vcproj | 16 +++++------ racket/src/worksp/libracket/libracket.vcxproj | 2 +- 5 files changed, 38 insertions(+), 12 deletions(-) diff --git a/racket/src/rktio/rktio_poll_set.c b/racket/src/rktio/rktio_poll_set.c index 2c230bf5ee..adf68d3114 100644 --- a/racket/src/rktio/rktio_poll_set.c +++ b/racket/src/rktio/rktio_poll_set.c @@ -1228,6 +1228,23 @@ void rkio_reset_sleep_backoff(rktio_t *rktio) rktio->made_progress = 1; } +static void prepare_windows_sleep(DWORD msec) +{ + /* The default scheduling granilaity is usually 16ms, which + means that a request to sleep 16ms could easily end up being 31ms, + and a request to sleep 2ms is likely at least 16ms. We can + request a finer granularity of scheduling, but do that only + temporarily, because it may slow down the rest of the system. */ + if (msec < 32) + timeBeginPeriod((msec >> 2) | 1); +} + +static void finish_windows_sleep(DWORD msec) +{ + if (msec < 32) + timeEndPeriod((msec >> 1) | 1); +} + #endif /******************** Main sleep function *****************/ @@ -1304,7 +1321,14 @@ void rktio_sleep(rktio_t *rktio, float nsecs, rktio_poll_set_t *fds, rktio_ltps_ # endif #else # ifdef RKTIO_SYSTEM_WINDOWS - Sleep((DWORD)(nsecs * 1000)); + { + DWORD msecs = nsecs * 1000; + if (msecs > 0) { + prepare_windows_sleep(msecs); + Sleep(msecs); + finish_windows_sleep(msecs); + } + } # else # ifndef NO_SLEEP # ifndef NO_USLEEP @@ -1455,7 +1479,9 @@ void rktio_sleep(rktio_t *rktio, float nsecs, rktio_poll_set_t *fds, rktio_ltps_ msec = INFINITE; } + prepare_windows_sleep(msec); result = MsgWaitForMultipleObjects(count, array, FALSE, msec, fds->wait_event_mask); + finish_windows_sleep(msec); } clean_up_wait(rktio, result, array, rps, rcount); rktio_collapse_win_fd(fds); /* cleans up */ diff --git a/racket/src/worksp/cs/Makefile b/racket/src/worksp/cs/Makefile index d5176dc9d1..fb9321ae1b 100644 --- a/racket/src/worksp/cs/Makefile +++ b/racket/src/worksp/cs/Makefile @@ -2,7 +2,7 @@ INCS = /I.. /I..\..\rktio /I..\librktio /I..\..\worksp\cs /I$(SCHEME_DIR)\$(MACHINE)\boot\$(MACHINE) RKTIO_LIB = ..\..\build\librktio.lib -BASE_WIN32_LIBS = WS2_32.lib Shell32.lib User32.lib +BASE_WIN32_LIBS = WS2_32.lib Shell32.lib User32.lib Winmm.lib WIN32_LIBS = $(BASE_WIN32_LIBS) RpCrt4.lib Ole32.lib Advapi32.lib SCHEME_LIB_FULL = $(SCHEME_DIR)\$(MACHINE)\boot\$(MACHINE)\$(SCHEME_LIB) diff --git a/racket/src/worksp/gc2/make.rkt b/racket/src/worksp/gc2/make.rkt index 10164cdf74..5ec9d6bb1e 100644 --- a/racket/src/worksp/gc2/make.rkt +++ b/racket/src/worksp/gc2/make.rkt @@ -288,7 +288,7 @@ (define dll "../../../lib/libracket3mxxxxxxx.dll") (define exe (format "../../../Racket~a.exe" suffix)) -(define libs "kernel32.lib user32.lib ws2_32.lib shell32.lib advapi32.lib") +(define libs "kernel32.lib user32.lib ws2_32.lib shell32.lib advapi32.lib winmm.lib") (define (link-dll objs delayloads sys-libs dll link-options exe?) (let ([ms (if (file-exists? dll) diff --git a/racket/src/worksp/libracket/libracket.vcproj b/racket/src/worksp/libracket/libracket.vcproj index 311e464cae..926325b1b8 100644 --- a/racket/src/worksp/libracket/libracket.vcproj +++ b/racket/src/worksp/libracket/libracket.vcproj @@ -49,7 +49,7 @@ 0x0409 - WS2_32.lib;Shell32.lib;User32.lib;%(AdditionalDependencies) + WS2_32.lib;Shell32.lib;User32.lib;Winmm.lib;%(AdditionalDependencies) ..\..\..\lib\libracketxxxxxxx.dll true true