1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
| /* File :
This file implements a microsecond precision clock.
We can start it (reset to zero), watch it (getting the elapsed time from start in many units)
We wan also ask it to wait until a specified time.
Remark:
In Windows, the millisecond is the atomic time unit for the followings operations:
* waiting without CPU usage (with Sleep)
* getting software interuptions. In this latter case, only a precision of 10 ms is garanted in practice.
It is always possible to get an accurate time (in microseconds) by requesting a hardware clock on the mother board (if any)
However, it it not possible to use this clock to get sub-microseconds interrupts neither to sleep peacefully.
The solution I implemented is to sleep peacefully the desired numbers of microseconds then to actively wath the precision clock.
----------------------------------------------------------------------------------*/
#pragma once
#pragma message( "Including " __FILE__ )
#define MICROCLOCK_H
// #include "Globals.h"
// #include "utils.h"
class CMicroClock {
protected:
__int64 n_Start ; // time when start was called
__int64 n_Watch ; // time when couter was last watched
__int64 n_CountsPerSec ; // counter frequeny (machine dependent)
__int64 n_llCorrection ; // elapsed time of a start-watch sequence
public:
CMicroClock(void); // calculates frequency and calibrate correction factor
__int64 Start(void); // get current time in start
void Start(__int64 newStartValue); // Change the value of the start member
__int64 GetCurrentCount(void); // get current time in GetCurrentCount
// Results in seconds in double
double GetDurationSec(void) ; // calculates time between start and GetCurrentCount members
double WatchSec(void) ; // call GetCurrentCount, then calculate duration
// Results in microseconds in 64 bits integer
__int64 GetDurationMicro(void) ; // calculates time between start and GetCurrentCount members
__int64 Watch(void) ; // call GetCurrentCount, then calculate duration
__int64 WatchAndRestart(void) ; // call Watch,then use the watch date as new zero
// Results in milli seconds in long with loss of precision (unsigned long is good because it can be mapped on a dialog)
unsigned WatchMilliSec(void) ;
// Offsets the start
void Offset(__int64 offset) ; // add offset to Start as many times as possible but maintains (start <= watch)
// Provide conversions between time units and counter
double Count2sec (__int64 count) ;
__int64 Count2microsec (__int64 count) ;
__int64 Microsec2count (__int64 microsec) ;
__int64 Sec2count (double sec) ;
// wait quietly as many ms as possible with sleep,
// then wait actively the rest of the time
// a tolerance si set to allow sleeping a full millisecond even if some microseconds are missing
__int64 WaitUntil(__int64 awakeTime, __int64 round = 100) ;
};
inline CMicroClock::CMicroClock(void) {
// get frequency
LARGE_INTEGER countsPerSec; // LargeIntegers are 64 bits native integers embeded in a Union designed for compatibility with systems/compilers which does not support native 64 bits integers. The QuadPart member is the native 64 bits integer.
QueryPerformanceFrequency(&countsPerSec) ; // the current performance-counter frequency, in counts per second.
n_CountsPerSec = countsPerSec.QuadPart;
if (n_CountsPerSec == 0) throw "This computer does not support high-frequency counters. Application cannot run" ;
// Calibration
Start();
GetCurrentCount();
n_llCorrection = n_Watch - n_Start ;
// Restart in case of any use
Start() ;
}
inline __int64 CMicroClock::Start(void) {
// Sleep(10); // Ensure we will not be interrupted by any other thread for a while
QueryPerformanceCounter((LARGE_INTEGER*)&n_Start) ;
return n_Start ;
}
inline void CMicroClock::Start(__int64 newStartValue) {
n_Start = newStartValue ;
}
inline __int64 CMicroClock::GetCurrentCount(void) {
QueryPerformanceCounter((LARGE_INTEGER*)&n_Watch) ;
return n_Watch ;
}
// duration in seconds in double
inline double CMicroClock::GetDurationSec(void) {
return Count2sec(n_Watch - n_Start - n_llCorrection) ;
}
// duration in microseconds in 64 bits integer
inline __int64 CMicroClock::GetDurationMicro(void) {
return Count2microsec(n_Watch - n_Start - n_llCorrection) ;
}
inline double CMicroClock::WatchSec(void) {
GetCurrentCount() ;
return GetDurationSec() ;
}
// Convert to milli second with precision loss
inline unsigned CMicroClock::WatchMilliSec(void) {
GetCurrentCount() ;
return (unsigned)(GetDurationMicro() / 1000) ;
}
inline __int64 CMicroClock::Watch(void) {
GetCurrentCount() ;
return GetDurationMicro() ;
}
inline __int64 CMicroClock::WatchAndRestart(void) {
__int64 r = Watch() ;
n_Start = n_Watch ;
return r ;
}
inline void CMicroClock::Offset(__int64 offset) {
GetCurrentCount() ;
n_Start += offset * ((n_Watch - n_Start) / offset) ;
}
inline double CMicroClock::Count2sec (__int64 count) {
static double k = 1.0 / (double)n_CountsPerSec ;
return (double)count * k ;
}
inline __int64 CMicroClock::Count2microsec (__int64 count) {
static __int64 million = 1000000 ;
return (__int64)(count * million / n_CountsPerSec) ;
}
inline __int64 CMicroClock::Microsec2count (__int64 microsec) {
static __int64 million = 1000000 ;
return (__int64)(microsec * n_CountsPerSec / million) ;
}
inline __int64 CMicroClock::Sec2count (double sec) {
return (__int64)(sec * n_CountsPerSec) ;
}
inline __int64 CMicroClock::WaitUntil(__int64 awakeTime, __int64 round /* = 100 */ ) {
__int64 enter = Watch(), quit ;
__int64 sleep_micro = awakeTime - enter ;
unsigned sleep_ms ;
if (sleep_micro > 1000 - round) {
sleep_ms = max(1U, (unsigned)(sleep_micro/1000)) ;
Sleep(sleep_ms) ; // quiet wait, in ms
}
while ((quit = Watch()) < awakeTime) ;
return quit - enter ;
} |
Partager