Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C++ time
I'm trying to create a timer that activate in a small time(less than 1ms).
 
I found a application from www.sysinternals.com called "ClockRes v2.0"
That application reported
 
Maximum timer Interval 15.6 ms
Minimum timer Interval 0.5 ms
Current timer Interval 15.6 ms.
 
That means, It's possible to change system clock resolution.but I'm fail.
 
Next, I try this code to create my timer.(read freq from registry,disabled CPU Boost Speed and multithread technology)
 
void MicroTmr(double ms)
{
	unsigned __int64 start_in = 0;
	unsigned __int64 stop_in= 0;
	if (!SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS))
		 cout << "Set Prioity Class Fail. " << endl;
		start_in = __rdtsc();
		while(true)
		{
			stop_in = __rdtsc();
			if (stop_in-start_in > freq/1000*ms)
				break;
		}
		start_in = 0;
		stop_in = 0;
}
 
but, If I set this function and my program in a same core this function will extremely disturb my program.(I set my program's priority at REALTIME_PRIORITY_CLASS too)
 
My question is :
1. How can I change system clock resolution?
2. How can I protect my program from the disturbance?
3. Are there any ways to use timer in a small interval(Less than 1ms)
 
Very thank you for your answer.
Posted 18-Jan-12 5:30am
Comments
JackDingler at 18-Jan-12 13:51pm
   
Windows is not a Real Time Operating System (RTOS), and so timing at those ranges is very difficult to do, and it will be error prone.
 
Because windows is executing many more tasks than just your application, at any time, another task can take up more processor time and skew your results.
 
Perhaps if you said what kind of problem you're trying to solve, we can suggest other ways of doing this?
Stefan_Lang at 20-Jan-12 7:01am
   
That is what I think as well: In my experience, Windows can't even guarantee measurements of 1ms accuracy even though that's the default grnularity of the system timer. Apparently some background services occasionally prevent the timer to actually 'tick' when it should, causing measurements of operations taking less than 1ms to occasionaly be measured as taking up to 4 or 5ms! Changing the granularity of measurement doesn't change that, although I guess you could probably take several measures and ignore the higher values.
Cool Cow Orjan at 20-Jan-12 8:29am
   
While ms is the unit of measurement, the default precision is 5ms (for NT family kernels, on Win 95 family it was 15ms). It is sometimes possible to improve this with calls to time[Begin/End]Period - it will tell you how precise it can be.
 
There is support for a high precision counter. It's just not guaranteed to be installed.
JackDingler at 20-Jan-12 10:26am
   
Solutions that require a high degree of precision in timing for windows, tend to have a hardware component.
 
Quite a few micro-controllers are on the market now that are within a price range that a hobbyist can afford. They come prebuilt with a facilities that allow them to do data collection from a variety of input sources.
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

1. The utility uses the function ::GetSystemTimeAdjustment to get the intervals. And, as expected, ::SetSystemTimeAdjustment can change the interval.
 
2. Using very high priorities is a very bad idea. You can lock your complete system. You may use ::QueryPerformanceCounter to measure time spans with higher resolutions. There are some articles here at CodeProject about the Performance Counter.
 
3. If you only want to measure times, using ::QueryPerformanceCounter may solve your problem. If you need some kind of action after a specific very short time, things are more complicated.
 
EDIT:
I must correct my answer to the first item. ::GetSystemTimeAdjustment can be only used to get the current timer interval and ::SetSystemTimeAdjustment can't be used to set it. To get also the min. and max. values and change the interval, the undocumented functions NtQueryTimerResolution() and NtSetTimerResolution() can be used. These functions have no associated import library. Use GetModuleHandle() and GetProcAddress() to dynamically link to Ntdll.dll. GetModuleHandle() can be used rather than LoadLibrary() because Ntdll.dll has been loaded by the app:
 
typedef NTSTATUS (CALLBACK* LPFN_NtQueryTimerResolution)(PULONG,PULONG,PULONG);
typedef NTSTATUS (CALLBACK* LPFN_NtSetTimerResolution)(ULONG,BOOLEAN,PULONG);
 
HMODULE hNtDll = ::GetModuleHandle(_T("Ntdll"));
if (hNtDll)
{
    ULONG nMinRes, nMaxRes, nCurRes;
    LPFN_NtQueryTimerResolution pQueryResolution = 
        (LPFN_NtQueryTimerResolution)::GetProcAddress(hNtDll, "NtQueryTimerResolution");
    if (pQueryResolution &&
        pQueryResolution(&nMinRes, &nMaxRes, &nCurRes) == STATUS_SUCCESS)
    {
        TRACE(_T("NT timer resolutions (min/max/cur): %u.%u / %u.%u / %u.%u ms"), 
            nMinRes / 10000, (nMinRes % 10000) / 10,
            nMaxRes / 10000, (nMaxRes % 10000) / 10,
            nCurRes / 10000, (nCurRes % 10000) / 10);
    }
    LPFN_NtSetTimerResolution pSetResolution = 
        (LPFN_NtSetTimerResolution)::GetProcAddress(hNtDll, "NtSetTimerResolution");
    if (pSetResolution && nSetRes)
    {
        NTSTATUS nStatus = pSetResolution(nSetRes, TRUE, &nCurRes);
    }
}
  Permalink  
v2
Comments
windyl3ig at 23-Jan-12 5:45am
   
your code is cool, but I think, you 'miss-place' with min and max,my result:
 
NT timer resolutions (min/max/cur):15.6/0.5/15.6or I missunderstand again? - -"
Jochen Arndt at 23-Jan-12 5:59am
   
The code is correct, but capable of being misunderstood. I have used 'timer resolution' as output (as named by the called function) while the Sysinternal utility uses 'timer interval' (which is more meaningful). The value of 15.6 ms is the max. interval time, but has the worst resolution.
windyl3ig at 23-Jan-12 7:42am
   
ok, very thank you for youf help and code.:P
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

Windows gives no built-in way of setting off events with a precision greter than (at best) 5 ms. (But see timeGetTime, timeBeginPeriod and timeEndPeriod for a possible way of measuring with ms precision.)
 
If you want to measure time with high precision, use the high-resolution performance counter. See QueryPerformanceCounter and QueryPerformanceFrequency. I guess you could make a polling function and put it in a worker thread where it could signal a semaphore or call a function pointer or something.
 
However, there's no guarantee that any given system has a high-resolution performance counter, and if yours don't, you're out of luck.
  Permalink  

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 OriginalGriff 587
1 Sergey Alexandrovich Kryukov 479
2 Maciej Los 305
3 Mathew Soji 195
4 BillWoodruff 170
0 OriginalGriff 7,356
1 Sergey Alexandrovich Kryukov 6,777
2 DamithSL 5,461
3 Manas Bhardwaj 4,916
4 Maciej Los 4,475


Advertise | Privacy | Mobile
Web04 | 2.8.1411023.1 | Last Updated 27 Jul 2012
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100