1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */ 2 3 #ifndef SPRINGTIME_H 4 #define SPRINGTIME_H 5 6 #include "System/creg/creg_cond.h" 7 8 #include <boost/cstdint.hpp> 9 #include <cassert> 10 11 // glibc's chrono is non monotonic/not steady atm (it depends on set timezone and can change at runtime!) 12 // we don't want to specially handle all the problems caused by this, so just use boost version instead 13 // not possible either: boost::chrono uses extremely broken HPE timers on Windows 7 (but so does std::) 14 // 15 // #define FORCE_CHRONO_TIMERS 16 // #define FORCE_BOOST_CHRONO 17 18 #if (__cplusplus > 199711L) && !defined(FORCE_BOOST_CHRONO) 19 #define SPRINGTIME_USING_STDCHRONO 20 #undef gt 21 #include <chrono> 22 namespace chrono { using namespace std::chrono; } 23 #else 24 #define SPRINGTIME_USING_BOOST 25 #undef gt 26 #include <boost/chrono/include.hpp> 27 namespace chrono { using namespace boost::chrono; }; 28 #endif 29 30 31 32 33 34 namespace spring_clock { 35 // NOTE: 36 // 1e-x are double-precision literals but T can be float 37 // floats only provide ~6 decimal digits of precision so 38 // ToSecs is inaccurate in that case 39 // these cannot be written as integer divisions or tests 40 // will fail because of intermediate conversions to FP32 ToSecs(const boost::int64_t ns)41 template<typename T> static T ToSecs (const boost::int64_t ns) { return (ns * 1e-9); } ToMilliSecs(const boost::int64_t ns)42 template<typename T> static T ToMilliSecs(const boost::int64_t ns) { return (ns * 1e-6); } ToMicroSecs(const boost::int64_t ns)43 template<typename T> static T ToMicroSecs(const boost::int64_t ns) { return (ns * 1e-3); } ToNanoSecs(const boost::int64_t ns)44 template<typename T> static T ToNanoSecs (const boost::int64_t ns) { return (ns ); } 45 46 // specializations 47 template<> boost::int64_t ToSecs <boost::int64_t>(const boost::int64_t ns) { return (ns / boost::int64_t(1e9)); } 48 template<> boost::int64_t ToMilliSecs<boost::int64_t>(const boost::int64_t ns) { return (ns / boost::int64_t(1e6)); } 49 template<> boost::int64_t ToMicroSecs<boost::int64_t>(const boost::int64_t ns) { return (ns / boost::int64_t(1e3)); } 50 FromSecs(const T s)51 template<typename T> static boost::int64_t FromSecs (const T s) { return ( s * boost::int64_t(1e9)); } FromMilliSecs(const T ms)52 template<typename T> static boost::int64_t FromMilliSecs(const T ms) { return (ms * boost::int64_t(1e6)); } FromMicroSecs(const T us)53 template<typename T> static boost::int64_t FromMicroSecs(const T us) { return (us * boost::int64_t(1e3)); } FromNanoSecs(const T ns)54 template<typename T> static boost::int64_t FromNanoSecs (const T ns) { return (ns ); } 55 56 void PushTickRate(bool hres = false); 57 void PopTickRate(); 58 59 // number of ticks since clock epoch 60 boost::int64_t GetTicks(); 61 const char* GetName(); 62 } 63 64 65 66 // class Timer 67 struct spring_time { 68 private: 69 CR_DECLARE_STRUCT(spring_time) 70 71 typedef boost::int64_t int64; 72 73 public: spring_timespring_time74 spring_time(): x(0) {} spring_timespring_time75 template<typename T> explicit spring_time(const T millis): x(spring_clock::FromMilliSecs(millis)) {} 76 77 spring_time& operator+=(const spring_time st) { x += st.x; return *this; } 78 spring_time& operator-=(const spring_time st) { x -= st.x; return *this; } 79 spring_time& operator%=(const spring_time mt) { x %= mt.x; return *this; } 80 spring_time operator-(const spring_time st) const { return spring_time_native(x - st.x); } 81 spring_time operator+(const spring_time st) const { return spring_time_native(x + st.x); } 82 spring_time operator%(const spring_time mt) const { return spring_time_native(x % mt.x); } 83 bool operator<(const spring_time st) const { return (x < st.x); } 84 bool operator>(const spring_time st) const { return (x > st.x); } 85 bool operator<=(const spring_time st) const { return (x <= st.x); } 86 bool operator>=(const spring_time st) const { return (x >= st.x); } 87 88 // short-hands toSecsispring_time89 int64 toSecsi() const { return (toSecs <int64>()); } toMilliSecsispring_time90 int64 toMilliSecsi() const { return (toMilliSecs<int64>()); } toMicroSecsispring_time91 int64 toMicroSecsi() const { return (toMicroSecs<int64>()); } toNanoSecsispring_time92 int64 toNanoSecsi() const { return (toNanoSecs <int64>()); } 93 toSecsfspring_time94 float toSecsf() const { return (toSecs <float>()); } toMilliSecsfspring_time95 float toMilliSecsf() const { return (toMilliSecs<float>()); } toMicroSecsfspring_time96 float toMicroSecsf() const { return (toMicroSecs<float>()); } toNanoSecsfspring_time97 float toNanoSecsf() const { return (toNanoSecs <float>()); } 98 99 // wrappers toSecsspring_time100 template<typename T> T toSecs() const { return spring_clock::ToSecs <T>(x); } toMilliSecsspring_time101 template<typename T> T toMilliSecs() const { return spring_clock::ToMilliSecs<T>(x); } toMicroSecsspring_time102 template<typename T> T toMicroSecs() const { return spring_clock::ToMicroSecs<T>(x); } toNanoSecsspring_time103 template<typename T> T toNanoSecs() const { return spring_clock::ToNanoSecs <T>(x); } 104 105 isDurationspring_time106 bool isDuration() const { return (x != 0); } isTimespring_time107 bool isTime() const { return (x > 0); } 108 109 void sleep(); 110 void sleep_until(); 111 112 113 static spring_time gettime(bool init = false) { assert(xs != 0 || init); return spring_time_native(spring_clock::GetTicks()); } getstarttimespring_time114 static spring_time getstarttime() { assert(xs != 0); return spring_time_native(xs); } getelapsedtimespring_time115 static spring_time getelapsedtime() { return (gettime() - getstarttime()); } 116 setstarttimespring_time117 static void setstarttime(const spring_time t) { assert(xs == 0); xs = t.x; assert(xs != 0); } 118 fromNanoSecsspring_time119 static spring_time fromNanoSecs (const int64 ns) { return spring_time_native(spring_clock::FromNanoSecs( ns)); } fromMicroSecsspring_time120 static spring_time fromMicroSecs(const int64 us) { return spring_time_native(spring_clock::FromMicroSecs(us)); } fromMilliSecsspring_time121 static spring_time fromMilliSecs(const int64 ms) { return spring_time_native(spring_clock::FromMilliSecs(ms)); } fromSecsspring_time122 static spring_time fromSecs (const int64 s) { return spring_time_native(spring_clock::FromSecs ( s)); } 123 124 private: 125 // convert integer to spring_time (n is interpreted as number of nanoseconds) spring_time_nativespring_time126 static spring_time spring_time_native(const int64 n) { spring_time s; s.x = n; return s; } 127 128 void Serialize(creg::ISerializer& s); 129 130 private: 131 int64 x; 132 133 // initial time (the "Spring epoch", program start) 134 // all other time-points *must* be larger than this 135 // if the clock is monotonically increasing 136 static int64 xs; 137 }; 138 139 140 141 static const spring_time spring_notime(0); 142 static const spring_time spring_nulltime(0); 143 144 //#define spring_gettime() spring_time::gettime() 145 #define spring_gettime() spring_time::getelapsedtime() 146 #define spring_getstarttime() spring_time::getstarttime() 147 #define spring_now() spring_time::getelapsedtime() 148 149 #define spring_tomsecs(t) ((t).toMilliSecsi()) 150 #define spring_istime(t) ((t).isTime()) 151 #define spring_sleep(t) ((t).sleep()) 152 153 #define spring_msecs(msecs) spring_time(msecs) 154 #define spring_secs(secs) spring_time((secs) * 1000) 155 156 157 158 159 160 #define spring_difftime(now, before) (now - before) 161 #define spring_diffsecs(now, before) ((now - before).toSecsi()) 162 #define spring_diffmsecs(now, before) ((now - before).toMilliSecsi()) 163 164 #endif // SPRINGTIME_H 165