Know Thy Tick
When I read something like “the clock interval… for most x86 multiprocessors is about 15 milliseconds” I’m compelled to determine the value of my clock, or “tick”, interval. Fortunately, the book I read this quote in, Windows Internals Fourth Edition provides a reference for helping me with my affliction.
The author, Mark Russinovich, of the aforementioned book has graciously made the utility ClockRes available on his web site. Running this utility, I was able to determine that the clock interval on my x86 multiprocessor PC is 15.625000 ms. Interesting, but my curious mind wants to know more.
Even more graciously, Mark has made the source code for ClockRes available. The function used in ClockRes to determine the tick interval is GetSystemTimeAdjustment . This function serves two purposes:
1) provide information about how and if the system periodically adjusts the time-of-day clock and
2) provide the interval between two successive system clock interrupts (i.e. the tick interval). Actually, the second purpose is really part of the first, but from my driven perspective, it’s the primary purpose of this function.
Armed with this information, I can start to connect a few dots without inflicting too much cerebral pain. Specifically, it explains why the return value from API function GetSystemTimeAsFileTime doesn’t update as frequently as one might expect. Given that the return value has a resolution of 100-nanoseconds, one might think that this function would provide a nifty high resolution timer. But, no, its system time and system time is only updated at the rate of the tick interval. And, to connect the dots, the tick interval is the value returned by function GetSystemTimeAdjustment.
Of course the real reason why the tick interval is important is that it affects thread scheduling. The Windows scheduler gives each thread a “quantum” of time to execute before allowing another task, at the same priority level, to run. The quantum that the scheduler assigns to a thread is a multiple of the tick interval. The specific quantum value chosen for a specific thread is bit beyond where I want to go with this article.
For now, let’s just examine the default quantum value for a foreground thread in XPe. In this case the Windows scheduler assigns a quantum of 18 or 6 tick intervals (Yes, to convert quantum to tick intervals, one must divide by 3. I could throw in a gratuitous comment about obfuscation here, but the reason for the multiple is to allow the scheduler the ability to “charge” a thread for doing an operation which causes it to suspend.) This means that on my PC, a foreground thread is allowed to hog the processor for about 94 milliseconds before another task of the same priority level is given a chance.
For some applications, one might want to be able to change the quantum setting. Fortunately, within limitations, one can. However, I’ll need to take this subject on in my next blog as this is a lengthy subject all on its own.
- Jim
Comments
- Anonymous
March 01, 2006
Hi Jim,
Thanks for the blog.
>For some applications, one might want to be able to change
>the quantum setting.
>Fortunately, within limitations, one can.
I was trying to make system clock interval smaller and SetSystemTimeAdjustment() obviously (dah!) did not help much.
Any hints on how to change it?
>However, I’ll need to take this subject on in my next blog
>as this is a lengthy subject all on its own.
Looking forward.
Alexei - Anonymous
March 01, 2006
Just for notification - Anonymous
March 01, 2006
Hi Alexei,
Unfortunately, the system clock interval, or tick, is set by the HAL and can't be changed. Most single processor boards have a clock interval of about 10 milliseconds.
You can, however, change the thread quantum; I've submitted a blog article on this subject which should be posted shortly. If you don't want to wait, I suggest you checkout the Quantum section of Chapter 6 of Mark Russinovich's Windows Internals Fourth Edition.
I hope this helps.
Jim - Anonymous
March 01, 2006
Thanks Jim,
I am reading it right now :-(
Alexei - Anonymous
March 08, 2006
The comment has been removed - Anonymous
March 09, 2006
Hi Lucas,
Thanks for the post and app.
I did run your application on Win2K.
Numbers were:
Minimum Resolution 15.625
Maximum Resolution 1.000 (?)
Current Resolution 15.625
I have looked at your article again and decided to start Multimedia Player.
Run you app again.
Minimum Resolution 15.625
Maximum Resolution 1.000 (?)
Current Resolution 0.977
So, the question still remains:
What is Minimum Resolution and how to change it.
Thanks,
Alexei - Anonymous
March 09, 2006
Ok,
My laizy. Spent more time writing the post than a test.
BTW: Lucas thanks for the hint.
This does it:
#include "mmsystem.h"
BOOL SetRes()
{
#define TARGET_RESOLUTION 1 // 1-millisecond target resolution
TIMECAPS tc;
UINT wTimerRes;
if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR)
{
// Error
return FALSE;
}
wTimerRes = min(max(tc.wPeriodMin, TARGET_RESOLUTION), tc.wPeriodMax);
MMRESULT res = timeBeginPeriod(wTimerRes);
return (TIMERR_NOERROR == res);
}
Hope this helps someone!
Alexei - Anonymous
March 09, 2006
Sorry about the Min and Max names... I guess it should be maximum precision :)
If you don't want to have to use the winmm.lib and you have access to the DDK you can use ntdll.lib and call the undocumented functions:
NtSetTimerResolution(
IN ULONG DesiredResolution,
IN BOOLEAN SetResolution,
OUT PULONG CurrentResolution );
NtQueryTimerResolution(
OUT PULONG MinimumResolution,
OUT PULONG MaximumResolution,
OUT PULONG CurrentResolution );
Lucas - Anonymous
March 09, 2006
Thanks much for pointing me at original nt calls, that's much better.
I usually use LoadLibrary to load ntdll.
Regards,
Alexei