From aa19b4eb0b064bc8e83b47337916d5caedd0bcac Mon Sep 17 00:00:00 2001 From: Jim Melton Date: Wed, 1 Aug 2018 21:17:50 -0600 Subject: [PATCH] refactor TimeKeeper to use std::chrono --- include/TimeKeeper.h | 109 ++++++----------- src/bzfs/bzfs.cxx | 8 +- src/common/TimeKeeper.cxx | 247 ++++++++++---------------------------- 3 files changed, 106 insertions(+), 258 deletions(-) diff --git a/include/TimeKeeper.h b/include/TimeKeeper.h index d826085926..df3d207639 100644 --- a/include/TimeKeeper.h +++ b/include/TimeKeeper.h @@ -20,12 +20,14 @@ * operator+=() allows a time in seconds to be added to a TimeKeeper. */ -#ifndef BZF_TIME_KEEPER_H -#define BZF_TIME_KEEPER_H +#pragma once +#ifndef BZF_TIME_KEEPER_H +#define BZF_TIME_KEEPER_H #include "common.h" /* system interface headers */ +#include #include @@ -38,54 +40,45 @@ class TimeKeeper { public: - TimeKeeper(); - TimeKeeper(const TimeKeeper&); - ~TimeKeeper(); - TimeKeeper& operator=(const TimeKeeper&); - - double operator-(const TimeKeeper&) const; - bool operator<=(const TimeKeeper&) const; - TimeKeeper& operator+=(double); - TimeKeeper& operator+=(const TimeKeeper&); - - // make a TimeKeeper with seconds = NULL act like unset - // Fixme: must this be defined here? didn't work for me outside the class - inline operator void*() - { - if (seconds > 0.0) - return this; - else - return NULL; - } + TimeKeeper() = default; + using Seconds_t = std::chrono::duration; + + explicit TimeKeeper(Seconds_t secs); + + operator bool() const; + + double operator-(const TimeKeeper&) const; + bool operator<=(const TimeKeeper&) const; + TimeKeeper& operator+=(double); + TimeKeeper& operator+=(const TimeKeeper&); /** returns how many seconds have elapsed since epoch, Jan 1, 1970 */ - double getSeconds(void) const; + double getSeconds() const; /** returns a timekeeper representing the current time */ - static const TimeKeeper& getCurrent(void); + static const TimeKeeper& getCurrent(); /** returns a timekeeper representing the time of program execution */ - static const TimeKeeper& getStartTime(void); + static const TimeKeeper& getStartTime(); /** sets the time to the current time (recalculates) */ - static void setTick(void); + static void setTick(); /** returns a timekeeper that is updated periodically via setTick */ - static const TimeKeeper& getTick(void); // const + static const TimeKeeper& getTick(); /** returns a timekeeper representing +Inf */ - static const TimeKeeper& getSunExplodeTime(void); + static const TimeKeeper& getSunExplodeTime(); /** returns a timekeeper representing -Inf */ - static const TimeKeeper& getSunGenesisTime(void); + static const TimeKeeper& getSunGenesisTime(); /** returns a timekeeper representing an unset timekeeper */ - static const TimeKeeper& getNullTime(void); - + static const TimeKeeper& getNullTime(); /** returns the local time */ static void localTime(int *year = NULL, int *month = NULL, int* day = NULL, int* hour = NULL, int* min = NULL, int* sec = NULL, bool* dst = NULL); /** returns a string of the local time */ - static const char *timestamp(void); + static const char *timestamp(); static void localTime( int &day); @@ -96,75 +89,51 @@ class TimeKeeper /** converts a time difference into an array of integers representing days, hours, minutes, seconds */ - static void convertTime(double raw, long int convertedTimes[]); + static void convertTime(Seconds_t raw, long int convertedTimes[]); /** prints an integer-array time difference in human-readable form */ - static const std::string printTime(long int timeValue[]); + static const std::string printTime(long int timeValue[]); /** prints an float time difference in human-readable form */ - static const std::string printTime(double diff); + static const std::string printTime(double diff); /** sleep for a given number of floating point seconds */ static void sleep(double secs); //const +protected: + // not that we expect to subclass, but prefer separating methods from members + void now(); + private: - double seconds; - static TimeKeeper currentTime; - static TimeKeeper tickTime; - static TimeKeeper sunExplodeTime; - static TimeKeeper sunGenesisTime; - static TimeKeeper nullTime; - static TimeKeeper startTime; + std::chrono::time_point lastTime; // floating seconds }; // // TimeKeeper // -inline TimeKeeper::TimeKeeper() : seconds(0.0) -{ - // do nothing -} - -inline TimeKeeper::TimeKeeper(const TimeKeeper& t) : - seconds(t.seconds) -{ - // do nothing -} - -inline TimeKeeper::~TimeKeeper() -{ - // do nothing -} - -inline TimeKeeper& TimeKeeper::operator=(const TimeKeeper& t) -{ - seconds = t.seconds; - return *this; -} - -inline double TimeKeeper::operator-(const TimeKeeper& t) const +inline double TimeKeeper::operator-(const TimeKeeper& t) const { - return seconds - t.seconds; + return (lastTime - t.lastTime).count(); } inline TimeKeeper& TimeKeeper::operator+=(double dt) { - seconds += dt; + lastTime += Seconds_t(dt); return *this; } inline TimeKeeper& TimeKeeper::operator+=(const TimeKeeper& t) { - seconds += t.seconds; + lastTime += t.lastTime.time_since_epoch(); return *this; } inline bool TimeKeeper::operator<=(const TimeKeeper& t) const { - return seconds <= t.seconds; + return lastTime <= t.lastTime; } -inline double TimeKeeper::getSeconds(void) const +inline double TimeKeeper::getSeconds() const { - return seconds; + return lastTime.time_since_epoch().count(); } diff --git a/src/bzfs/bzfs.cxx b/src/bzfs/bzfs.cxx index 1bd43d6460..6548ccf070 100644 --- a/src/bzfs/bzfs.cxx +++ b/src/bzfs/bzfs.cxx @@ -794,13 +794,13 @@ void startCountdown ( int delay, float limit, int playerID ) matchBegins = "Match begins now!"; else { - TimeKeeper::convertTime(countdownDelay, timeArray); + TimeKeeper::convertTime(TimeKeeper::Seconds_t(countdownDelay), timeArray); std::string countdowntime = TimeKeeper::printTime(timeArray); matchBegins = TextUtils::format("Match begins in about %s", countdowntime.c_str()); } sendMessage(ServerPlayer, AllPlayers, matchBegins.c_str()); - TimeKeeper::convertTime(clOptions->timeLimit, timeArray); + TimeKeeper::convertTime(TimeKeeper::Seconds_t(clOptions->timeLimit), timeArray); std::string timelimit = TimeKeeper::printTime(timeArray); matchBegins = TextUtils::format("Match duration is %s", timelimit.c_str()); sendMessage(ServerPlayer, AllPlayers, matchBegins.c_str()); @@ -2230,7 +2230,7 @@ void AddPlayer(int playerIndex, GameKeeper::Player *playerData) if (duration < 365.0f * 24 * 3600) { long int timeArray[4]; - TimeKeeper::convertTime(duration, timeArray); + TimeKeeper::convertTime(TimeKeeper::Seconds_t(duration), timeArray); std::string bantime = TimeKeeper::printTime(timeArray); rejectionMessage += bantime; rejectionMessage += " remaining"; @@ -5925,7 +5925,7 @@ static void doStuffOnPlayer(GameKeeper::Player &playerData) if (duration < 365.0f * 24 * 3600) { long int timeArray[4]; - TimeKeeper::convertTime(duration, timeArray); + TimeKeeper::convertTime(TimeKeeper::Seconds_t(duration), timeArray); std::string bantime = TimeKeeper::printTime(timeArray); reason += bantime; reason += " remaining"; diff --git a/src/common/TimeKeeper.cxx b/src/common/TimeKeeper.cxx index 57b48f70cf..be5091560e 100644 --- a/src/common/TimeKeeper.cxx +++ b/src/common/TimeKeeper.cxx @@ -14,165 +14,78 @@ #include "TimeKeeper.h" /* system implementation headers */ -#include -#include -#include -#ifdef HAVE_UNISTD_H -# include -#endif -#ifdef __BEOS__ -# include -#endif -#if !defined(_WIN32) -# include -# include -static struct timeval lastTime = { 0, 0 }; -#else /* !defined(_WIN32) */ -# include -static Uint64 lastTime = 0; -static Uint64 qpcLastTime; -static Uint64 qpcFrequency = 0; -static Uint64 qpcLastCalibration; -static DWORD timeLastCalibration; -#endif /* !defined(_WIN32) */ +#include /* common implementation headers */ #include "TextUtils.h" #include "bzfio.h" -TimeKeeper TimeKeeper::currentTime; -TimeKeeper TimeKeeper::tickTime; -TimeKeeper TimeKeeper::sunExplodeTime; -TimeKeeper TimeKeeper::sunGenesisTime; -TimeKeeper TimeKeeper::nullTime; -TimeKeeper TimeKeeper::startTime = TimeKeeper::getCurrent(); +namespace { + TimeKeeper currentTime; + TimeKeeper startTime = TimeKeeper::getCurrent(); // initialize when we started + TimeKeeper tickTime; -const TimeKeeper& TimeKeeper::getCurrent(void) + TimeKeeper sunExplodeTime{TimeKeeper::Seconds_t::max()}; + TimeKeeper sunGenesisTime{TimeKeeper::Seconds_t::min()}; + TimeKeeper nullTime{TimeKeeper::Seconds_t::zero()}; +} + +TimeKeeper::TimeKeeper(Seconds_t secs) + : lastTime(secs) { - // if not first call then update current time, else use default initial time -#if !defined(_WIN32) - if (lastTime.tv_sec != 0) - { - struct timeval now; - gettimeofday(&now, NULL); - currentTime += double(now.tv_sec - lastTime.tv_sec) + - 1.0e-6 * double(now.tv_usec - lastTime.tv_usec); - lastTime = now; - } - else - gettimeofday(&lastTime, NULL); -#else /* !defined(_WIN32) */ - if (qpcFrequency != 0) - { - - // main timer is qpc - Uint64 now = SDL_GetPerformanceCounter(); - - Uint64 diff = now - qpcLastTime; - Uint64 clkSpent = now - qpcLastCalibration; - Uint64 thisFeq = SDL_GetPerformanceFrequency(); - - if (thisFeq != qpcFrequency) - { - // Recalibrate Frequency - DWORD tgt = timeGetTime(); - DWORD deltaTgt = tgt - timeLastCalibration; - timeLastCalibration = tgt; - qpcLastCalibration = now; - if (deltaTgt > 0) - { - LONGLONG oldqpcfreq = qpcFrequency; - qpcFrequency = thisFeq; - if (qpcFrequency != oldqpcfreq) - logDebugMessage(4,"Recalibrated QPC frequency. Old: %f ; New: %f\n", (double)oldqpcfreq, (double)qpcFrequency); - } - } - - currentTime += (double) diff / (double) qpcFrequency; - qpcLastTime = now; - } - else if (lastTime != 0) - { - Uint64 now = (Uint64)timeGetTime(); - Uint64 diff; - if (now <= lastTime) - { - // eh, how'd we go back in time? - diff = 0; - } - else - diff = now - lastTime; - currentTime += 1.0e-3 * (double)diff; - lastTime = now; - } - else - { - static bool sane = true; - - // should only get into here once on app start - if (!sane) - logDebugMessage(1,"Sanity check failure in TimeKeeper::getCurrent()\n"); - sane = false; - - Uint64 freq = SDL_GetPerformanceFrequency(); - - if (true) - { - qpcLastTime = SDL_GetPerformanceCounter(); - qpcFrequency = freq; - logDebugMessage(4,"Actual reported QPC Frequency: %f\n", (double)qpcFrequency); - qpcLastCalibration = qpcLastTime; - timeLastCalibration = timeGetTime(); - } - else - { - logDebugMessage(1,"QueryPerformanceFrequency failed with error %d\n", GetLastError()); - - // make sure we're at our best timer resolution possible - timeBeginPeriod(1); - - lastTime = (Uint64)timeGetTime(); - } - } -#endif /* !defined(_WIN32) */ +} + +TimeKeeper::operator bool() const +{ + return lastTime != nullTime.lastTime; +} + +void TimeKeeper::now() +{ + lastTime = std::chrono::steady_clock::now(); +} + +const TimeKeeper& TimeKeeper::getCurrent() +{ + currentTime.now(); return currentTime; } -const TimeKeeper& TimeKeeper::getStartTime(void) // const +const TimeKeeper& TimeKeeper::getStartTime() { return startTime; } -const TimeKeeper& TimeKeeper::getTick(void) // const +const TimeKeeper& TimeKeeper::getTick() { return tickTime; } -void TimeKeeper::setTick(void) +void TimeKeeper::setTick() { tickTime = getCurrent(); } -const TimeKeeper& TimeKeeper::getSunExplodeTime(void) +//static +const TimeKeeper& TimeKeeper::getSunExplodeTime() { - sunExplodeTime.seconds = 10000.0 * 365 * 24 * 60 * 60; return sunExplodeTime; } -const TimeKeeper& TimeKeeper::getSunGenesisTime(void) +//static +const TimeKeeper& TimeKeeper::getSunGenesisTime() { - sunGenesisTime.seconds = -10000.0 * 365 * 24 * 60 * 60; return sunGenesisTime; } -const TimeKeeper& TimeKeeper::getNullTime(void) +//static +const TimeKeeper& TimeKeeper::getNullTime() { - nullTime.seconds = 0; return nullTime; } -const char *TimeKeeper::timestamp(void) // const +const char *TimeKeeper::timestamp() // const { static char buffer[256]; // static, so that it doesn't vanish time_t tnow = time(0); @@ -240,24 +153,25 @@ void TimeKeeper::UTCTime(int *year, int *month, int* day, int* wday, // function for converting a float time (e.g. difference of two TimeKeepers) // into an array of ints -void TimeKeeper::convertTime(double raw, long int convertedTimes[]) +void TimeKeeper::convertTime(Seconds_t raw, long int convertedTimes[]) { - long int day, hour, min, sec, remainder; - static const int secondsInDay = 86400; - - sec = (long int)raw; - day = sec / secondsInDay; - remainder = sec - (day * secondsInDay); - hour = remainder / 3600; - remainder = sec - ((hour * 3600) + (day * secondsInDay)); - min = remainder / 60; - remainder = sec - ((hour * 3600) + (day * secondsInDay) + (min * 60)); - sec = remainder; - - convertedTimes[0] = day; - convertedTimes[1] = hour; - convertedTimes[2] = min; - convertedTimes[3] = sec; + // std::chrono::days is C++-20 + auto days = std::chrono::duration_cast>>(raw); + raw -= days; + + auto hours = std::chrono::duration_cast(raw); + raw -= hours; + + auto mins = std::chrono::duration_cast(raw); + raw -= mins; + + auto secs = std::chrono::duration_cast(raw); + raw -= secs; + + convertedTimes[0] = days.count(); + convertedTimes[1] = hours.count(); + convertedTimes[2] = mins.count(); + convertedTimes[3] = secs.count(); return; } @@ -269,27 +183,23 @@ const std::string TimeKeeper::printTime(long int timeValue[]) std::string valueNames; char temp[25]; - if (timeValue[0] > 0) - { + if (timeValue[0] > 0) { snprintf(temp, 25, "%ld day%s", timeValue[0], timeValue[0] == 1 ? "" : "s"); valueNames.append(temp); } - if (timeValue[1] > 0) - { + if (timeValue[1] > 0) { if (timeValue[0] > 0) valueNames.append(", "); snprintf(temp, 20, "%ld hour%s", timeValue[1], timeValue[1] == 1 ? "" : "s"); valueNames.append(temp); } - if (timeValue[2] > 0) - { + if (timeValue[2] > 0) { if ((timeValue[1] > 0) || (timeValue[0] > 0)) valueNames.append(", "); snprintf(temp, 20, "%ld min%s", timeValue[2], timeValue[2] == 1 ? "" : "s"); valueNames.append(temp); } - if (timeValue[3] > 0) - { + if (timeValue[3] > 0) { if ((timeValue[2] > 0) || (timeValue[1] > 0) || (timeValue[0] > 0)) valueNames.append(", "); snprintf(temp, 20, "%ld sec%s", timeValue[3], timeValue[3] == 1 ? "" : "s"); @@ -303,47 +213,16 @@ const std::string TimeKeeper::printTime(long int timeValue[]) const std::string TimeKeeper::printTime(double diff) { long int temp[4]; - convertTime(diff, temp); + convertTime(Seconds_t(diff), temp); return printTime(temp); } void TimeKeeper::sleep(double seconds) { - if (seconds <= 0.0) - return; - -#ifdef HAVE_USLEEP - usleep((unsigned int)(1.0e6 * seconds)); - return; -#endif -#if defined(HAVE_SLEEP) && !defined(__APPLE__) - // equivalent to _sleep() on win32 (not sleep(3)) - Sleep((DWORD)(seconds * 1000.0)); - return; -#endif -#ifdef HAVE_SNOOZE - snooze((bigtime_t)(1.0e6 * seconds)); - return; -#endif -#ifdef HAVE_SELECT - struct timeval tv; - tv.tv_sec = (long)seconds; - tv.tv_usec = (long)(1.0e6 * (seconds - tv.tv_sec)); - select(0, NULL, NULL, NULL, &tv); - return; -#endif -#ifdef HAVE_WAITFORSINGLEOBJECT - HANDLE dummyEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - WaitForSingleObject(dummyEvent, (DWORD)(1000.0 * seconds)); - CloseHandle(dummyEvent); - return; -#endif - - // fall-back case is fugly manual timekeeping - TimeKeeper now = TimeKeeper::getCurrent(); - while ((TimeKeeper::getCurrent() - now) < seconds) - continue; + if (seconds > 0.0) { + std::this_thread::sleep_for(Seconds_t(seconds)); + } return; }