/** File "HiResTimer2.h", by KWR for CSE250, Fall 2009. Still "mutable"?!? Wraps a class around basic timing functions, clarifying which times are clock-reads and which are *durations*, i.e. differences between reads. Assumes 64-bit longs (or higher), may break on (old) Windows setups that provide only 32-bit longs. IMPT: Any client that #includes this must use a trailing -lrt in g++ Not a "struct" because its fields are private; not quite "POD" either. */ #ifndef HI_RES_TIMER_H_ #define HI_RES_TIMER_H_ #include #include //#include //might be needed on some systems #include #include //needed in 2014 using std::string; class HiResTimer { clockid_t clockID; double nanoDivider; struct timespec timestamp; //standard calls require & in front struct timespec prevStamp; //INV: == *timestamp upon update struct timespec newInterval; //time *difference* not stamp struct timespec intervalSinceReset; void updateDurations() { clock_gettime(clockID,×tamp);//deliberately first line of code const long nanoDiff = timestamp.tv_nsec - prevStamp.tv_nsec; const time_t secondsDiff = timestamp.tv_sec - prevStamp.tv_sec; prevStamp = timestamp; //restore INV as soon as possible if (nanoDiff < 0) { //nano-reader wrapped around signed long boundary newInterval.tv_nsec = 1000000000 + nanoDiff; newInterval.tv_sec = secondsDiff - 1; } else { newInterval.tv_nsec = nanoDiff; newInterval.tv_sec = secondsDiff; } intervalSinceReset.tv_nsec += newInterval.tv_nsec; intervalSinceReset.tv_sec += newInterval.tv_sec; // FYI: // The "Stopwatch" class maintained a timestamp of last reset // because these repeated adds can increase roundoff errors, // but with nanosecond precision now those matter much less. } long newIntervalInNanoseconds() const { return newInterval.tv_nsec + 1000000000*newInterval.tv_sec; } long sinceResetInNanoseconds() const { return intervalSinceReset.tv_nsec + 1000000000*intervalSinceReset.tv_sec; } public: enum Units { SECONDS, MILLISECONDS, MICROSECONDS, NANOSECONDS }; /** Default units are microseconds */ HiResTimer() : clockID(CLOCK_PROCESS_CPUTIME_ID) , nanoDivider(1000.0) , timestamp(timespec()) //remember to eradicate "new" for value type! , prevStamp(timespec()) //overwritten , newInterval(timespec()) //meaningful , intervalSinceReset(timespec()) //meaningful { clock_gettime(clockID, ×tamp); prevStamp = timestamp; //so INV holds } HiResTimer(clockid_t clockID, Units units) : clockID(clockID) , nanoDivider(units == SECONDS ? 1000000000.0 : (units == MILLISECONDS ? 1000000.0 : (units == NANOSECONDS ? 1.0 : 1000.0) ) ) , timestamp(timespec()) //default constructor puts 0s , prevStamp(timestamp) //order matters! Legal and convenient , newInterval(timespec()) //meaningful , intervalSinceReset(timespec()) //meaningful { clock_gettime(clockID, ×tamp); prevStamp = timestamp; //so INV holds } void reset() { newInterval = intervalSinceReset = timespec(); clock_gettime(clockID, ×tamp); prevStamp = timestamp; } double elapsedTime() { //NOT CONST! Returns time since last call or reset updateDurations(); return newIntervalInNanoseconds() / nanoDivider; } double timeSinceReset() { updateDurations(); return sinceResetInNanoseconds() / nanoDivider; } string getUnits() const { if (nanoDivider > 999999999.9) { return "seconds"; } else if (nanoDivider > 999999.9) { return "milliseconds"; } else if (nanoDivider > 999.9) { return "microseconds"; } else { return "nanoseconds!"; } } }; #endif