High resolution timers are desirable in a wide variety of different applications. For example, the most common use of such timers in Windows is by multimedia applications that are producing sound or audio that require precise control. MIDI is a perfect example because MIDI sequencers must maintain the pace of MIDI events with 1 millisecond accuracy. This article describes how high resolution timers are implemented in NT and documents NtSetTimerResolution and NtQueryTimerResolution, the NT kernel functions that manipulate and return information about the system clock. Unfortunately, NtSetTimerResolution and NtQueryTimerResolution are not exported by the NT kernel, so they are not available to kernel-mode device drivers.
Windows NT bases all of its timer support off of one system clock interrupt, which by default runs at a 10 millisecond granularity. This is therefore the resolution of standard Windows timers. When a multimedia application uses the timeBeginPeriod mutlimedia API, which is exported by the Windows NT dynamic link library WINMM.DLL, the call is redirected into the Windows NT kernel-mode function NtSetTimerResolution, which is exported by the native Windows NT library NTDLL.DLL.
NtSetTimerResolution and NtQueryTimerResolution are defined as follows. All times are specifified in hundreds of nanoseconds.
NTSTATUS NtSetTimerResolution ( IN ULONG RequestedResolution, IN BOOLEAN Set, OUT PULONG ActualResolution );
The desired timer resolution. Must be within the legal range of system timer values supported by NT. On standard x86 systems this is 1-10 milliseconds. Values that are within the acceptable range are rounded to the next highest millisecond boundary by the standard x86 HAL. This parameter is ignored if the Set parameter is FALSE.
This is TRUE if a new timer resolution is being requested, and FALSE if the application is indicating it no longer needs a previously implemented resolution.
The timer resolution in effect after the call is returned in this parameter.
NtSetTimerResolution returns STATUS_SUCCESS if the resolution requested is within the valid range of timer values. If Set is FALSE, the caller must have made a previous call to NtSetTimerResolution or STATUS_TIMER_RESOLUTION_NOT_SET is returned.
NTSTATUS NtQueryTimerResolution ( OUT PULONG MinimumResolution, OUT PULONG Maximum Resolution, OUT PULONG ActualResolution );
The minimum timer resolution. On standard x86 systems this is 0x2625A, which is about 10 milliseconds
The maximum timer resolution. On standard x86 systems this is 0x2710, which is about 1 millisecond.
This is the current resolution of the system clock.
NtSetTimerResolution can be called to set timer resolutions by more than on application. To support a subsequent process setting a timer resolution without violating the resolution assumptions of a previous caller, NtSetTimerResolution never lowers the timer's resolution, only raises it. For example, if a process sets the resolution to 5 milliseconds, subequent calls to set the resolution to between 5 and 10 millseconds will return a status code indicating success, but the timer will be left at 5 milliseconds.
NtSetTimerResolution also keeps track of whether a process has set the timer resolution in its process control block, so that when a call is made with Set equal to FALSE it can verify that the caller has previously requested a new resolution. Every time a new resolution is set a global counter is incremented, and every time it is reset the counter is decremented. When the counter becomes 0 on a reset call the timer is changed back to its default rate, otherwise no action is taken. Again, this preserves the timer resolution assumptions of all the applications that have requested high resolution timers by guaranteeing that the resolution will be at least as good as what they specified.
You can use the ClockRes applet from Sysinternals to view the current clock resolution on your system.