Best, most accurate clock?

Started by
30 comments, last by Ademan555 20 years ago
Ok, ive done a little bit of digging for timing in c++, and a report i read said that the multimedia clock (it must be in mmsystem.h ) is the most accurate, does anyone have any input? its not as if i need super accurate timing for my crappy 2d engine... but i was hoping to create a class and save it for later, once im better at d3d and c++ -Dan Yes I realize im a n00b... Don't yell. -fel [edited by - felisandria on December 12, 2003 2:22:23 PM]
When General Patton died after World War 2 he went to the gates of Heaven to talk to St. Peter. The first thing he asked is if there were any Marines in heaven. St. Peter told him no, Marines are too rowdy for heaven. He then asked why Patton wanted to know. Patton told him he was sick of the Marines overshadowing the Army because they did more with less and were all hard-core sons of bitches. St. Peter reassured him there were no Marines so Patton went into Heaven. As he was checking out his new home he rounded a corner and saw someone in Marine Dress Blues. He ran back to St. Peter and yelled "You lied to me! There are Marines in heaven!" St. Peter said "Who him? That's just God. He wishes he were a Marine."
Advertisement
they are probably refering to QueryPerformanceCounter, (although i dont think that needs winmm, maybe timeGetTime).

Regardless, using an intel system:
__asm {
cpuid ; force all previous instructions to complete
rdtsc ; read time stamp counter
mov time, eax ; move counter into variable
}
Should give you a reading as accurate as possible. It is sometimes advised to do this reading twice, and you will need to look up your processors manual to see how many clock ticks the rdtsc instruction takes (about 30 from memory)
quote:Original post by aboeing
they are probably refering to QueryPerformanceCounter, (although i dont think that needs winmm, maybe timeGetTime).

Regardless, using an intel system:
__asm {
cpuid ; force all previous instructions to complete
rdtsc ; read time stamp counter
mov time, eax ; move counter into variable
}
Should give you a reading as accurate as possible. It is sometimes advised to do this reading twice, and you will need to look up your processors manual to see how many clock ticks the rdtsc instruction takes (about 30 from memory)


Shouldn''t matter how many it takes.. because if it takes 30, it will ALWAYS be behind by 30, therefore your program will see the start time 30 ticks after it really is, etc... so it will always give the same time change value!

if it goes from 0 -> 600... or 30 -> 630 if you add the 30 in.. the time difference is still identical, so no need to compensate!
If the counter returns the timestamp BEFORE it was executed, you would have the overhead of this instruction before executing your code. If the counter returns the timestamp AFTER it's been executed (sounds strange), you would have overhead when reading the time after your code has executed..
Either way you have the overhead of 1 timestamp read...

-- EDIT --
This is if you're using it for performance measurement obviously (wouldn't reckon you'd use the timestamp counter for anything else..)

[edited by - BiTwhise on December 12, 2003 10:18:18 AM]
timeGetTime is probably fine for your needs, but it''s not the best. It has a resolution of 1 ms on 9x platforms, and also on NT if you call timeBeginPeriod; note that doing so increases system load. The problem is, it''s basically just a tick counter (incremented every timer interrupt, as reported by GetSystemTimeAdjustment), and drifts over time (the interrupt isn''t always delivered on time) - this is bad if you''re relying on this clock for multiplayer.

QueryPerformanceCounter has better resolution (depending on HAL, ~1 µs if using PIT, ~.3 µs for the PM timer, better than 100 ns if HPET is available, or CPU clock period if using TSC), but a raft of problems:
[comments from timer source]
// problems:
// - multiprocessor systems: may be inconsistent across CPUs;
// setting thread affinity is too much work.
// - if implemented with TSC: same problems as above.
// (we check if TSC/QPC freqs differ by more than 10% -
// can''t assume PIT / PMT freq values, because new the new HPET
// timer''s frequency is unspecified)
// - Q274323: jumps several seconds under heavy PCI bus load.
// readings are checked against system time and discarded if invalid.
// - "System clock problem can inflate benchmark scores":
// invalid value if not polled every 4.5 seconds? solved
// by calibration thread, which reads timer every second anyway.

While we''re at it, problems with rdtsc / the CPU timestamp counter:
// problems:
// - multiprocessor systems: may be inconsistent across CPUs;
// setting thread affinity is too much work.
// - deep sleep modes: TSC may not be advanced.
// - SpeedStep/''gearshift'' CPUs: frequency may change.
// this happens on notebooks now, but eventually desktop systems
// will do this as well (if not to save power, for heat reasons).
//
// detect''s tsc_is_safe check tries to ensure the above won''t happen,
// but I don''t think it''s possible to determine beforehand if the CPU
// does SpeedStep (currently, it assumes so iff running on a laptop).
// to be safe, wsdl disables the TSC when an APM message is received.

What I do (to emulate gettimeofday on Windows; Linux does something similar already) is choose one of 3 high-resolution timers (QPC, TSC, timeGetTime), depending on which has the least problems, and lock it to the system time. Still working on it, but looks good already.

aboeing:
In addition to the above problems, be sure to issue several cpuid before first use of the timer - the first few times take longer to execute. BTW, the CPU clock isn''t terribly accurate.
E8 17 00 42 CE DC D2 DC E4 EA C4 40 CA DA C2 D8 CC 40 CA D0 E8 40E0 CA CA 96 5B B0 16 50 D7 D4 02 B2 02 86 E2 CD 21 58 48 79 F2 C3
I think the standard C function clock works well, to use it I include:
#include <ctime>
#include <cstdlib>

In school I program in Windows and submit my homework on NetBSD, and one of them doesn''t have CLOCKS_PER_SEC defined (not sure which constant is the standard), so I keep this up top:

#ifndef CLOCKS_PER_SEC
#define CLOCKS_PER_SEC CLK_TCK
#endif

to time something:

std::clock_t end_time, start_time;
start_time = std::clock();
//do something here
end_time = std::clock();
double elapsed_time_in_clock_ticks = (double)(end_time - start_time);
double elapsed_time_in_seconds = elapsed_time_in_clock_ticks / (double)CLOCKS_PER_SEC;


And unlike those windows functions, if you ever want to port your code, this code is platform independent :-)
Unfortunately, clock() only has a resolution of 10..15 ms on Windows (it''s implemented with GetSystemTimeAsFileTime).

> And unlike those windows functions, if you ever want to port your code, this code is platform independent
Yes - which is why I emulate gettimeofday and clock_gettime on Windows, and use those in real code
E8 17 00 42 CE DC D2 DC E4 EA C4 40 CA DA C2 D8 CC 40 CA D0 E8 40E0 CA CA 96 5B B0 16 50 D7 D4 02 B2 02 86 E2 CD 21 58 48 79 F2 C3
quote:Original post by Ready4Dis
if it goes from 0 -> 600... or 30 -> 630 if you add the 30 in.. the time difference is still identical, so no need to compensate!

Yes, but thats only because I''m an idiot.
I really should stop posting late at night.
quote:
be sure to issue several cpuid before first use of the timer - the first few times take longer to execute.
BTW, the CPU clock isn''t terribly accurate.

Yeah, this is basically what AMD suggested to do to count ticks. What other possible method will give you a better reading?
I thought rdtsc was the most accurate reading possible, the only reason you get inaccuracies is because of multitasking?

read the cedar.intel.com documentatino for rdstc.


Second poster was correct.

What they do is to time their own function after three warm up passes.


RDTSC WITH CPUID is about 20 something clock ticks.

Just subtract it from your time differences if that''s what you are after (as in a timer). Same as any other method for overhead.


As a note: QueryPerformanceCounter is about 674 clock ticks.

That''s for a straight
//start
QueryPerformanceCounter(&starttime);
QueryPerformanceCounter(&endtime);
totaltime=endtime-starttime;
//end


For overhead, use declspec(naked) if you know what you are doing. You won''t get any extra overhead that way.


Btw Dan, don''t geel like a "n00b" because you asked for help on a topic like this. You did your research, and it''s one of the most reasonably debated topics around here. Also a pretty important one for some applications.

It kind of comes down to preference. I still like using QueryPerformanceCounter for things like frame rate and testing large blocks of code as it saves the inline assembly. For smaller peices (testing which is faster etc for release modes) and optimisation I use the RDTSC code.

Oh, as a side note: CPUID isn''t really necessary for the newer processors, but use it anyway unless that extra 15 or so clock ticks is that important to you. Better safe than sorry.
Beer - the love catalystgood ol' homepage
> I thought rdtsc was the most accurate reading possible, the only reason you get inaccuracies is because of multitasking?
I''m saying it''s not as accurate as it would appear - the crystal that drives the CPU clock isn''t the best. The TSC is the best you''ve got for measuring short intervals, but you''re screwed if the processor decides to sleep, or change frequency. I think the OP wanted a wall clock reference - in that case, using the TSC is a lot of work

> As a note: QueryPerformanceCounter is about 674 clock ticks.
Wow, that''s fast - sounds like a switch to kernel mode, rdtsc, a little bit correction, and that''s it. The other QPC implementations (PIT, PMT, HPET) require port I/O, so it ends up taking several µs. What OS and HAL is this on?
E8 17 00 42 CE DC D2 DC E4 EA C4 40 CA DA C2 D8 CC 40 CA D0 E8 40E0 CA CA 96 5B B0 16 50 D7 D4 02 B2 02 86 E2 CD 21 58 48 79 F2 C3

This topic is closed to new replies.

Advertisement