diff --git a/MUNGA/TIME.h b/MUNGA/TIME.h index e81d5f6..0375a5b 100644 --- a/MUNGA/TIME.h +++ b/MUNGA/TIME.h @@ -32,6 +32,12 @@ protected: static long ticksPerSecond; static __int64 perfCounterFreq; + // + // The counter reading this process started at, so the clock counts from + // launch rather than from the machine's boot. See GetRTC. + // + static __int64 perfCounterOrigin; + static long GetRTC(); static double GetHiRes(); static __int64 GetHiResTicks(); diff --git a/MUNGA_L4/L4TIME.cpp b/MUNGA_L4/L4TIME.cpp index 75a2d0d..5323823 100644 --- a/MUNGA_L4/L4TIME.cpp +++ b/MUNGA_L4/L4TIME.cpp @@ -14,6 +14,7 @@ SystemClock SystemClock::timer; long SystemClock::ticksPerSecond; __int64 SystemClock::perfCounterFreq; +__int64 SystemClock::perfCounterOrigin; //RB 1/20/07 //volatile long fast_time = 0L; @@ -53,11 +54,42 @@ void Timer_Handler() //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // +// +// Milliseconds since this process started. +// +// It used to be milliseconds since the machine BOOTED, which is what +// QueryPerformanceCounter counts from, and that had two consequences. +// +// The quiet one: Scalar is a 32-bit float, so an absolute time held in one +// loses resolution as the number grows. Consecutive representable values +// are 3.9ms apart after nine hours of uptime, 15.6ms after a day and a +// half, and 31.25ms after three days - by which point the clock can no +// longer resolve a single 20ms physics step. Anything computed by +// subtracting two absolute times IN FLOAT inherits that, and the joystick +// poll interval in L4CTRL is exactly such a subtraction: its 50ms test +// quietly becomes 62.5ms after three days of uptime and 125ms after +// twelve, so a player's controls grow less responsive the longer the +// machine has been switched on. The smoke emitter in L4VIDRND has the same +// defect, where adding a small interval to a large timestamp can round to +// no change at all. +// +// The loud one: this returns a long, and milliseconds since boot overflows +// one after 24.8 days. +// +// Counting from launch fixes both at the source and leaves every Time +// arithmetic path untouched - those subtract ticks as integers and were +// always exact. Peer machines already disagreed about this origin, having +// booted at different moments, so the network is no worse off; reconciling +// that is what RP412NETCLOCK does. +// long SystemClock::GetRTC() { LARGE_INTEGER count; QueryPerformanceCounter(&count); - return (long)((count.QuadPart * (__int64)1000) / SystemClock::perfCounterFreq); + return (long)( + ((count.QuadPart - SystemClock::perfCounterOrigin) * (__int64)1000) + / SystemClock::perfCounterFreq + ); } double SystemClock::GetHiRes() @@ -97,6 +129,15 @@ SystemClock::SystemClock() //SystemClock::ticksPerSecond = freq.QuadPart; SystemClock::perfCounterFreq = freq.QuadPart; SystemClock::ticksPerSecond = 1000L; + + // + // Time zero. Set here rather than on the first GetRTC call so that the + // origin is fixed before anything can read the clock, and so no two + // threads can race to establish it. + // + LARGE_INTEGER origin; + QueryPerformanceCounter(&origin); + SystemClock::perfCounterOrigin = origin.QuadPart; } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~