Click here to Skip to main content
15,886,545 members
Please Sign up or sign in to vote.
4.50/5 (2 votes)
See more:
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)

C++
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
Comments
JackDingler 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 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.
Orjan Westin 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 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.

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:

C++
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);
    }
}
 
Share this answer
 
v2
Comments
windyl3ig 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 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 23-Jan-12 7:42am    
ok, very thank you for youf help and code.:P
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.
 
Share this answer
 

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



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900