W2k SDL_GetTicks(): further investigations

Hi,

here I have another patch against SDL_systimer.c regarding
SDL_GetTicks() – to be applied to SDL_systimer.c after having
applied the first patch from my mail from yesterday. :slight_smile:

It is only one additional line in SDL_StartTicks() that does the
following:

If QueryPerformanceFrequency() results in not having a high-resolution
counter available (which would lead to a counter precision of
SDL_GetTicks() of only 10-15 ms under Windows NT/2000), it calls
"timeBeginPeriod(1)", which sets the counter precision of "timeGetTime()"
used by SDL_GetTicks() to 1 ms, which indeed works that way under
Windows NT/2000 (all tests done on Windows 2000, BTW).

This function is therefore only used if QueryPerformanceCounter() states
that there is no high-precision counter available on that system.

Here are my investigations and conclusions that let me think that this
is the right precedence. (Again, all tests done with Windows 2000.)

When using standard SDL_GetTicks(), you get a precision of 10-15 ms.

When using QueryPerformanceCounter(), you get a precision of 1 ms.

When using timeBeginPeriod(1) once at startup, you get a precision of 1 ms.

When using timeGetTime() (like in plain SDL 1.2.1), but directly surrounded
by timeBeginPeriod(1) and timeEndPeriod(1) like this…
timeBeginPeriod(1);
now = timeGetTime();
timeEndPeriod(1);
…you get a totally messed up “precision” of randomly 1-15 ms – unusable.

When starting an SDL program with the “use timeBeginPeriod(1) once at
startup” patch, all other SDL programs running at the same time (that use
standard SDL with normally 10-15 ms precision) suddenly also get an
SDL_GetTicks() precision of 1 ms. Conclusion: timeBeginPeriod(1) has a
system-wide effect. But also: timeEndPeriod(1) has this effekt, too,
lowering the precision of all SDL programs (with precision raised once at
startup) back to 10-15 ms. :frowning:

Interesting performance observations:

The tests were done on a PentiumIII/800MHz/nvidiaTNT2 system and the game
Rocks’n’Diamonds, doing some soft-scrolling at fixed 50 FPS.

Additionally, the Windows 2000 task manager was used to monitor CPU usage.

When using QueryPerformanceCounter() for 1 ms accurate timing,
the CPU usage when scrolling was around 10%.

When using timeBeginPeriod(1) (once at startup) for 1 ms timing,
the CPU usage when scrolling was around 66%!

Conclusions for the best approach:

  • Use 1 ms precision counter by QueryPerformanceCounter(), where the
    high-precision counter is availabe.
  • Use 1 ms precision counter by calling timeBeginPeriod(1) once at
    startup (with apparently higher CPU load and side-effects on other
    timeGetTime-using applications), where the high-precision counter
    is NOT available, which is far better than plain timeGetTime() on
    Windows NT/2000 systems.

Some (slightly confusing) remarks on timeBeginPeriod from the MSDN:
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/hh/multimed/mmfunc_1dwk.asp)

“Call this function immediately before using timer services, and call the timeEndPeriod function immediately after you are finished using the timer services.”

Unfortunately, they don’t specify what “using timer services” mean –
“immediately before” and “immediately after” like in “surrounding” (see
above) does obviously not work.

The only thing that would make sense this way is a special "busy-wait"
function like this (just a prototype):

SDL_BusyWait(int milliseconds)
{
int start;

timeBeginPeriod(1);
start = timeGetTime();
while (timeGetTime() < start + milliseconds)
    do_nothing();
timeEndPeriod(1);

}

But then, you might need a 1 ms precise counter not only for busy-waiting.

In my opinion, the combination of the two patches (from my last mail and
this mail) seem to offer the best (== practical) solution for all WIN32
platforms.

Any comments welcome!

Best regards,
Holger–
holger.schemel at mediaways.net
-------------- next part --------------
— SDL_systimer.c.patched Mon Jul 2 22:14:29 2001
+++ SDL_systimer.c Tue Jul 3 23:03:04 2001
@@ -65,6 +65,7 @@
else
{
hires_timer_available = FALSE;

  •   timeBeginPeriod(1);		/* use 1 ms timer precision */
      start = timeGetTime();
    
    }
    #endif

[…]

Conclusion: timeBeginPeriod(1) has a
system-wide effect. But also: timeEndPeriod(1) has this effekt, too,
lowering the precision of all SDL programs (with precision raised once at
startup) back to 10-15 ms. :frowning:

WHAT!? Well, there’s one rather serious bug n Win2k… Nothing should happen
until everyone has called timeEndPeriod(). One wouldn’t expect that kind of
resource “management” from a server OS.

Interesting performance observations:

The tests were done on a PentiumIII/800MHz/nvidiaTNT2 system and the game
Rocks’n’Diamonds, doing some soft-scrolling at fixed 50 FPS.

Additionally, the Windows 2000 task manager was used to monitor CPU usage.

When using QueryPerformanceCounter() for 1 ms accurate timing,
the CPU usage when scrolling was around 10%.

When using timeBeginPeriod(1) (once at startup) for 1 ms timing,
the CPU usage when scrolling was around 66%!

Well, Win2k is not an RTOS, and a “periodic task” running at 1 kHz means 2 k
context switches/second, but 66%!? What’s going on…? On Linux, we’re
running user space threads (blocking on audio card read or writte) at 1-2 kHz
on Linux/lowlatency with no significant overhead.

Then again, the NT scheduler isn’t exactly known for having much control over
CPU usage. The 66% could just be some side effect of the timeGetTime() calls
or something, rather than the actual CPU load.

//David Olofson — Programmer, Reologica Instruments AB

.- M A I A -------------------------------------------------.
| Multimedia Application Integration Architecture |
| A Free/Open Source Plugin API for Professional Multimedia |
----------------------> http://www.linuxaudiodev.com/maia -' .- David Olofson -------------------------------------------. | Audio Hacker - Open Source Advocate - Singer - Songwriter |--------------------------------------> david at linuxdj.com -'On Wednesday 04 July 2001 00:04, Holger Schemel wrote: