Windows 7 Timing Functions - How to Use Getsystemtimeadjustment Correctly

Windows 7 timing functions - How to use GetSystemTimeAdjustment correctly?

The GetSystemTimeAsFileTimeAPI provides access to the system's wall clock in file time format.

A 64-bit FILETIME structure receives the system time as FILETIME in 100ns units, which have been expired since Jan 1, 1601. The call to GetSystemTimeAsFileTime typically requires 10 ns to 15 ns.

In order to investigate the real accuracy of the system time provided by this API, the granularity that comes along with the time values needs to be discussed. In other words: How often is the system time updated? A first estimate is provided by the hidden API call:

NTSTATUS NtQueryTimerResolution(OUT PULONG MinimumResolution, 
OUT PULONG MaximumResolution,
OUT PULONG ActualResolution);

NtQueryTimerResolution is exported by the native Windows NT library NTDLL.DLL. The ActualResolution reported by this call represents the update period of the system time in 100 ns units, which does not necessarily match the interrupt period. The value depends on the hardware platform. Common hardware platforms report 156,250 or 100,144 for ActualResolution; older platforms may report even larger numbers; newer systems, particulary when HPET (High Precision Event Timer) or constant/invariant TSC are supported, may return 156,001 for ActualResolution.

This is one of the heartbeats controlling the system. The MinimumResolution and the ActualResolution are relevant for the multimedia timer configuration.

The ActualResolution can be set by using the API call

NTSTATUS NtSetTimerResolution(IN ULONG RequestedResolution,
IN BOOLEAN Set,
OUT PULONG ActualResolution);

or via the multimedia timer interface

MMRESULT timeBeginPeriod(UINT uPeriod);

with the value of uPeriod derived from the range allowed by

MMRESULT timeGetDevCaps(LPTIMECAPS ptc, UINT cbtc );

which fills the structure

typedef struct {
UINT wPeriodMin;
UINT wPeriodMax;
} TIMECAPS;

Typical values are 1 ms for wPeriodMin and 1,000,000 ms for wPeriodMax.

There is an unfortunate misinterpretation when looking an the min/max values here:

  • wPeriodMin defines the minimum period, which is clear in this context.
  • MinimumResolution returned by NtQueryTimerResolution on the other hand specifies a resolution. The lowest obtainable resolution (MinimumResolution) is in the range of up to about 20 ms, while the highest obtainable resolution (MaximumResolution) can be 0.5 ms. However, the 0.5 ms resulution is not accessable through a of timeBeginPeriod.

The multimedia timer interface handles periods and NtQueryTimerResolution() handles resolutions (reciprocal value of period).

Summary: GetSystemTimeAdjustment is not the function to look at. This function only tells how and if time-changes are done. Depending on the setting of the multimedia timer interface timeBeginPeriod, the progress of time may be done more often and in smaller portions. Use NtQueryTimerResolution to receive the actual time increment. And be aware that the setting of the multimedia timer API does influence the values. (Example: When the media player is showing a video, the times are getting short.)

I diagnosed windows time matters to a large extent. Some of the results can be found here.

Note: Time Adjustment: 0.0156001 clearly identifies windows VISTA or higher with HPET and/or constant/invariant TSC on your system.

Implementation: If you want to catch the time transition:

FILETIME FileTime,LastFileTime;
long long DueTime,LastTime;
long FileTimeTransitionPeriod;

GetSystemTimeAsFileTime(&FileTime);
for (int i = 0; i < 20; i++) {
LastFileTime.dwLowDateTime = FileTime.dwLowDateTime;
while (FileTime.dwLowDateTime == LastFileTime.dwLowDateTime) GetSystemTimeAsFileTime(&FileTime);
// enough to just look at the low part to catch the transition
CopyMemory(&DueTime,&FileTime,sizeof(FILETIME));
CopyMemory(&LastTime,&LastFileTime,sizeof(FILETIME));
FileTimeTransitionPeriod = (long)(DueTime-LastTime);
fprintf(stdout,"transition period: % 7.4lf ms)\n",(double)(FileTimeTransitionPeriod)/10000);
}

// WARNING: This code consumes 100% of the cpu for 20 file time increments.
// At the standard file time increment of 15.625 ms this corresponds to 312.5ms!

But: When the filetime transition is very short (e.g. set by timeBeginPeriod(wPeriodMin)) any output like fprintf or std::cout might destroy the result because it delays the loop. In such cases I'd recommend to store the 20 results in a data structure and do the output afterwards.

And: The filetime transition may not always be the same. It may well be that the file time increment does not match the update period. See the link above to get more details and examples for this bahavior.

Edit: Use caution when calling timeBeginPeriod, as frequent calls can significantly affect the system clock MSDN. This behavior applies up to Windows version 7.

Calls to timeBeginPeriod/timeEndPeriod or NtSetTimerResolution may change the system time by as much as ActualResolution. Doing it very often results in considerable changes of the system time. However, when the calls are made at or near the transition of the system time, deviations are much less. Polling for a system time transition/increment ahead of calls to the above function is advised for demanding applications like NTP clients. Synchronizing to an NTP server is difficult when unwanted jumps in the systemtime progess occurs.

How to find out timeGetTime precision?

I'd suggest to use the GetSystemTimeAsFileTime function. This function has low overhead and displays ths system clock. See this answer to get some more details about the granularity of time and APIs to query timer resolutions (e.g. NtQueryTimerResolution). Code to find out how the system file time increments can be found there too.
Windows 8 and Server 2012 provide the new GetSystemTimePreciseAsFileTime function which is supposed to be more accurate. MSDN states with the highest possible level of precision (<1us). However, this only works on W8 and Server 2012 and there is very little documentation about how this additional accuracy is obtained. Seems like MS is going a Linux alike (gettimeofday) way to combine the performace counter frequency with the system clock.
This post may of interest for you too.

Edit: As of February 2014 there is some more detailed information about time matters on MSDN: Acquiring high-resolution time stamps.

How to get the current Windows system-wide timer resolution

Windows timer resolution is provided by the hidden API call:

NTSTATUS NtQueryTimerResolution(OUT PULONG MinimumResolution, 
OUT PULONG MaximumResolution,
OUT PULONG ActualResolution);

NtQueryTimerResolution is exported by the native Windows NT library NTDLL.DLL.

Common hardware platforms report 156,250 or 100,144 for ActualResolution; older platforms may report even larger numbers; newer systems, particulary when HPET (High Precision Event Timer) or constant/invariant TSC are supported, may return 156,001 for ActualResolution.

Calls to timeBeginPeriod(n) are reflected in ActualResolution.

More details in this answer.

strange waitable timer aligning issue


dueTime.QuadPart = 0;

what do you intend with this statement?

The documentation says: "Positive values indicate absolute time." and "Negative values indicate relative time.". Zero never specifies a possible value for dueTime.

Instead you shoud find a reasonable start time by specifying

  1. a relative time for the first event to happen.

    dueTime.QuadPart = -1000000; 
    // 100 ns units, first event at 100 ms from now
  2. an absolute time

    FILETIME FileTime;
    LARGE_INTEGER dueTime;

    GetSystemTimeAsFileTime(&FileTime);
    CopyMemory(&dueTime,&FileTime,sizeof(FILETIME));
    dueTime.QuadPart += 1000000;
    // 100 ns units, first event at 100 ms from FileTime

Note: waitable timers allow to specify the due time in 100 ns units. This does not mean that they can trigger at that accuracy. The accuracy is determined by the system time granularity. More details about the system time granularity can be found in this answer.



Related Topics



Leave a reply



Submit