RE: [GD-Windows] More timer fun! (sorry for revisit!)
Brought to you by:
vexxed72
From: Jon W. <hp...@mi...> - 2002-12-24 05:48:44
|
First, a suggestion for your suggested inline assembly: If you let the compiler generate the prolog and epilog, it can inline the function. Thus, the best implementation of reading the time stamp counter is this: inline uint64 read_tsc() { __asm { rdtsc } } The RDTSC instruction luckily uses the defined calling convention for returning 64-bit integers (in EDX:EAX). Second, the archives contains my long rant on the subject of timers on PC hardware. To re-cap: On PC hardware, there's basically three timers that are generally available. 1) the "tick" counter. This is a millisecond-type timer, and is read by calls such as timeGetTime() or GetTickCount(). It is driven by the age-old ISA interrupt controller (which by now is probably virtualized into some do-everything-legacy chip three bridges away from the CPU on the motherboard). This is sort-of millisecond precise. Reading it requires a bus transaction all the way out to the LPC ISA interface, so it's fairly slow as such things go (say, 1-2 microseconds). (boo!) If there's heavy bus traffic, such as running a game which makes good use of AGP and DMA for graphics and audio, this timer will glitch and lose a tick or two every so often; slowly falling behind. (boo!) 2) the "performance" counter. This is a microsecond-type timer, and is read by the QueryPerformanceCounter() call. It typically advances by little over 1 million ticks per second, or little over 3 million ticks per second, depending on bus. It is derived from, I think, some PCI controller counter. Reading it requires, at least, a CPU->northbridge bus transaction, and as such is not super snappy. Call it 1 microsecond. (boo!) If there's heavy bus traffic, on many, common chip sets, even very new ones, this timer may suddenly jump between one and four seconds forward in time (boo!). I believe there is some internal race WRT this counter being 64 bits, but kept in two separate 32-bit registers, but don't hold me to that. 3) the "time stamp" counter. This is a register internal to the CPU, which counts, using a 64 bit timer, the number of CPU clocks executed since system power-on (more or less). On a four GHz machine, it will take over a hundred and thirty years for this counter to wrap (yay!). Reading this counter stays within the CPU, and as such is really fast (call it 40 cycles) (yay!). Because it really measures CPU clock ticks on all but the most exotic architectures (read: Transmeta :-), this counter is extremely useful for determining exactly how long a piece of code takes to execute, on a micro-benchmarking scale. You still have to compensate for the fact that you may take an interrupt in the middle of measurement, so run the same piece of code 100 times and pick the BEST value -- that's how well your code can perform, which is what you want to measure unless you're trying to model starting with cold caches. (yay!) Unfortunately, this third model, if you want to turn it into real time, needs the relation between CPU ticks and seconds. This can be had by profiling the CPU on start-up, using some of the other timers available. Such profiling always has a little bit of imprecision (boo!). What's worse, on laptops, the rate of advance on this register will fluctuate wildly, because, you guessed it, the CPU speed fluctuates wildly. (boo!) Thus, there is no fool-proof way of measuring elapsed time on a PC in a really accurate manner. If you're trying to keep a simulation in sync over a network, say, this may be of high importance to you so you'll probably, in the end, come up with some system which uses a combination of all three. I use the cycle counter for most measurements, because it's fast and cheap, and then I continually re-calibrate by using the other two counters and having them vote. If they vote differently, I discard that sample and wait until later. This seems to work reasonably well. On the CPU-speed-switching machines, you are mostly toast. The best you can do is selectively instantiate another class for your clock, and hope that the effect of jumping timer inaccuracy won't totally kill your application. Cheers, / h+ > -----Original Message----- > From: gam...@li... > [mailto:gam...@li...]On Behalf Of > Josiah Manson > Sent: Monday, December 23, 2002 9:27 PM > To: gam...@li... > Subject: Re: [GD-Windows] More timer fun! (sorry for revisit!) > > > I don't know if you are going to think this is a good idea or not, but if > you want a really high accuracy timer, it may be possible to get > the number > of actual CPU clock cycles elapsed and use that as your measurement. Of > course this means that you have to use 64 bit integers, pay > attention to the > clock wrapping over, and limiting yourself to pentiums and > higher, but that > is a small price to pay. I think that it also won't work with laptops. > > The idea is pretty simple though. First get a reading of clock cycles, use > the good old C time() function in a buisy loop for a second, then get > another reading of clock cycles at your programs startup. The > difference in > clock cycles is the frequency of the cpu. > > Now, if you find any number of elapsed cycles, and divide by the > frequency, > you know how much time has passed to a high degree of accuracy. > Lets see if > I can dig out some code here. The following 2 code snippets > should work, but > the first is probably better. I got it out of a simple profiler I made > recently. > > // 64 bit... yum > _declspec(naked) __int64 _fastcall _profileTick() > { > _asm rdtsc > _asm ret > } > > // clock is 32 bit integer > // this is a pentium specific macro that will count cpu cycles > #define clocktick(clock) _asm push eax\ > _asm push edx\ > _asm rdtsc\ > _asm mov clock, eax\ > _asm pop edx\ > _asm pop eax > > > > ------------------------------------------------------- > This sf.net email is sponsored by:ThinkGeek > Welcome to geek heaven. > http://thinkgeek.com/sf > _______________________________________________ > Gamedevlists-windows mailing list > Gam...@li... > https://lists.sourceforge.net/lists/listinfo/gamedevlists-windows > Archives: > http://sourceforge.net/mailarchive/forum.php?forum_id=555 > |