Discussion:
Using QueryPerformanceCounter for precision timing delay
(too old to reply)
Ed
2006-12-24 18:03:58 UTC
Permalink
The following code does work in my app and gives a 2ms delay:

LARGE_INTEGER startc;
LARGE_INTEGER endc;
LONGLONG diff;

QueryPerformanceCounter(&startc);
loop:
QueryPerformanceCounter(&endc);
diff = endc.QuadPart - startc.QuadPart;
if (diff < 5000)
goto loop;

I know that this will not be the case on all PC's and OS's.
How can I calibrate it to allways give the same time delay (about 2ms)?
Thanks
Geoff
2006-12-24 18:25:12 UTC
Permalink
Post by Ed
LARGE_INTEGER startc;
LARGE_INTEGER endc;
LONGLONG diff;
QueryPerformanceCounter(&startc);
QueryPerformanceCounter(&endc);
diff = endc.QuadPart - startc.QuadPart;
if (diff < 5000)
goto loop;
I know that this will not be the case on all PC's and OS's.
How can I calibrate it to allways give the same time delay (about 2ms)?
Thanks
Take the performance frequency into account:

LARGE_INTEGER startc;
LARGE_INTEGER endc, freqc;
LONGLONG diff;
double res;

QueryPerformanceCounter(&startc);
loop:
QueryPerformanceCounter (&endc);
QueryPerformanceFrequency (&freqc);
diff = endc.QuadPart - startc.QuadPart;
res = ((double)((double)diff / (double)freqc.QuadPart));
if (res < 0.002)
goto loop;
Geoff
2006-12-24 18:37:07 UTC
Permalink
Post by Ed
LARGE_INTEGER startc;
LARGE_INTEGER endc;
LONGLONG diff;
QueryPerformanceCounter(&startc);
QueryPerformanceCounter(&endc);
diff = endc.QuadPart - startc.QuadPart;
if (diff < 5000)
goto loop;
I know that this will not be the case on all PC's and OS's.
How can I calibrate it to allways give the same time delay (about 2ms)?
Thanks
Keep in mind, if you do this you are causing your application to
consume CPU time. Run two instances of your program in that loop and
100% CPU use results. Not a very friendly application. This is not the
right way to get precise time delays.
Scott McPhillips [MVP]
2006-12-25 01:36:54 UTC
Permalink
Post by Ed
LARGE_INTEGER startc;
LARGE_INTEGER endc;
LONGLONG diff;
QueryPerformanceCounter(&startc);
QueryPerformanceCounter(&endc);
diff = endc.QuadPart - startc.QuadPart;
if (diff < 5000)
goto loop;
I know that this will not be the case on all PC's and OS's.
How can I calibrate it to allways give the same time delay (about 2ms)?
Thanks
Depends on what "does work" means to you. In fact, there will be times
when the delay is hundreds of milliseconds due to Windows task switching.
--
Scott McPhillips [VC++ MVP]
Joseph M. Newcomer
2006-12-25 03:05:36 UTC
Permalink
Note that if you haven't done QueryPerformanceFrequency, you have no idea what those
numbers mean, and the 5000 only works on your CPU.

Note that the use of the goto is silly; you could easily do it with a while-loop. But
note that it is mostly 2ms. There is no guarantee that, during that time, you will not
get an end-of-timeslice, or be preempted by a higher-priority thread, so it will give you
some kind of delay some of the time, but it will never be reliable.
joe
Post by Ed
LARGE_INTEGER startc;
LARGE_INTEGER endc;
LONGLONG diff;
QueryPerformanceCounter(&startc);
QueryPerformanceCounter(&endc);
diff = endc.QuadPart - startc.QuadPart;
if (diff < 5000)
goto loop;
I know that this will not be the case on all PC's and OS's.
How can I calibrate it to allways give the same time delay (about 2ms)?
Thanks
Joseph M. Newcomer [MVP]
email: ***@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Robert Bogard
2006-12-26 06:12:19 UTC
Permalink
Post by Ed
LARGE_INTEGER startc;
LARGE_INTEGER endc;
LONGLONG diff;
QueryPerformanceCounter(&startc);
QueryPerformanceCounter(&endc);
diff = endc.QuadPart - startc.QuadPart;
if (diff < 5000)
goto loop;
I know that this will not be the case on all PC's and OS's.
How can I calibrate it to allways give the same time delay (about 2ms)?
Thanks
Since Windows is a pre-emptive multi-threading OS (i.e., not a RTOS) and
since other threads can easily pre-empt yours depending on the
number/priority of other concurrently running processes, the basic answer is
"You can't".

Plus, given that your code wastes 100% of CPU power for at least 2 ms,
checking a performance counter, I would hate to be an end-user of your code.
You should learn how to use the capabilities of the OS (e.g., multimedia
timers) within the constraints inherent to its design.
Joseph M. Newcomer
2006-12-27 00:11:03 UTC
Permalink
YOu can assume that you will never get code that works with delays this short to ever work
reliably on any operating system other than a real-time operating system. The chances you
will ever get user-level code like this to work on WIndows, Unix, Linux, Mac OS X, or
Solaris is so vanishingly small as to not even be worthy of discussion.

I was trying to use a system, laughably called "Real-time Unix", some years ago. It had a
10ms timer. The only problem with this was that it was two orders of magnitude slower
than our application required.

The key here is "reliably". If your app fails if the delay is longer than 2ms, give up.
You have an unsolvable problem in general-purpose operating systems. If you can
occasionally stand a delay, the multimedia timers will work sort-of-pretty-reliably.

Note that if you need resolution to 1ms, you have to have a system capable of giving you
events at no less than 1/2ms, and preferrably at 1/4ms. Your error rate will be one or
two intervals, so a 1ms timer will not really give you maximum reliability for a 2ms
interval because you might get 2ms, or you might get 3ms. The phenomenon, well known to
people who deal with physical systems, is called "gating error" and was understood back in
the 1940s, at least (I have not researched it earlier than that, because that was the
first time digital circuits could actually be used in measurement equipment). So the
induced error is one or two ticks depending on gating error on front and back sampling, so
to get reliably 2ms, you should have a system that can resolve events to 500us. Not going
to happen on Windows as it is currently set up.

Please explain why you need such tiny intervals.
joe
Post by Ed
LARGE_INTEGER startc;
LARGE_INTEGER endc;
LONGLONG diff;
QueryPerformanceCounter(&startc);
QueryPerformanceCounter(&endc);
diff = endc.QuadPart - startc.QuadPart;
if (diff < 5000)
goto loop;
I know that this will not be the case on all PC's and OS's.
How can I calibrate it to allways give the same time delay (about 2ms)?
Thanks
Joseph M. Newcomer [MVP]
email: ***@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm

Loading...