Oberon Community Platform Forum

Development => Merge Requests => Topic started by: sage on June 27, 2011, 09:17:36 PM



Title: Kernel32.GetTickCount() has very poor precision
Post by: sage on June 27, 2011, 09:17:36 PM
Hi guys,
Kernel32.GetTickCount() has very poor precision and as result Win32.Kernel.GetTicks() has poor precision too.
Typical measurements (time of some frames rendering) using Kernel32.GetTickCount() compared to values obtained using precise timer:
Quote
Win32.Kernel.GetTicks(): 31  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 26
Win32.Kernel.GetTicks(): 31  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 29
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 20
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 20
Win32.Kernel.GetTicks(): 31  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 20
Win32.Kernel.GetTicks(): 31  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 19
Win32.Kernel.GetTicks(): 15  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 19
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 16
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 16
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 16
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 16
Win32.Kernel.GetTicks(): 15  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 16
Win32.Kernel.GetTicks(): 15  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 16
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 15
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 15
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 14
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 14
Win32.Kernel.GetTicks(): 15  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 12
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 12
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 12
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 14
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 13
Win32.Kernel.GetTicks(): 15  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 6
Win32.Kernel.GetTicks(): 15  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 6
Win32.Kernel.GetTicks(): 0  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 7
Win32.Kernel.GetTicks(): 0  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 7
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 5
Win32.Kernel.GetTicks(): 0  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 7
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 7
Win32.Kernel.GetTicks(): 16  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 6
Win32.Kernel.GetTicks(): 15  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 6
Win32.Kernel.GetTicks(): 0  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 13
Win32.Kernel.GetTicks(): 15  ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5): 14
It's evident that values obtained using Win32.Kernel.GetTicks() every time is multiple of 15(16)!
Following replacement of Win32.Kernel.GetTicks() makes ticks counter more precise:
Code:
PROCEDURE GetTicks*() : LONGINT;
BEGIN
RETURN ENTIER((1000 * QueryPerformanceCounter() / QueryPerformanceFrequency()) + 0.5)
END GetTicks;
It requires two functions:
Code:
PROCEDURE QueryPerformanceCounter(): HUGEINT;
VAR
t: HUGEINT;
res: Kernel32.BOOL;
BEGIN
res := Kernel32.QueryPerformanceCounter(SYSTEM.VAL(Kernel32.LargeInteger, t));
RETURN t
END QueryPerformanceCounter;

PROCEDURE QueryPerformanceFrequency(): HUGEINT;
VAR
t: HUGEINT;
res: Kernel32.BOOL;
BEGIN
res := Kernel32.QueryPerformanceFrequency(SYSTEM.VAL(Kernel32.LargeInteger, t));
RETURN t
END QueryPerformanceFrequency;


Title: Re: Kernel32.GetTickCount() has very poor precision
Post by: sage on June 28, 2011, 07:56:04 AM
Or, as possible better solution to provide additional module for precision timer or new functions to existing Kernel module with preserving cross-platform capability.


Title: Re: Kernel32.GetTickCount() has very poor precision
Post by: sage on June 30, 2011, 10:42:27 PM
I want to contribute a small demo to A2 system ;)
It's ray-casting Wolfenstein like engine, and also cross-platform PreciseTimer module.
Engine still lacks of game logic, but anyway may be useful.


Title: Re: Kernel32.GetTickCount() has very poor precision
Post by: sage on July 07, 2011, 09:44:35 AM
WMRaycaster.Mod now able to use multiple threads for rendering.