#include "dynlib.h" #include "fasttime.h" #include <util/generic/singleton.h> #include <util/generic/yexception.h> #include <utility> #include <util/thread/singleton.h> #if defined(_win_) || defined(_arm32_) || defined(_cygwin_) ui64 InterpolatedMicroSeconds() { return MicroSeconds(); } #else #include <dlfcn.h> #include <sys/time.h> #if defined(_musl_) #include <util/generic/hash.h> #include <util/generic/vector.h> #include <util/generic/string.h> #include <contrib/libs/linuxvdso/interface.h> #endif namespace { using TTime = ui64; struct TSymbols { using TFunc = int (*)(struct timeval*, struct timezone*); inline TSymbols() : Func(nullptr) { // not DEFAULT, cause library/cpp/gettimeofday Func = reinterpret_cast<TFunc>(dlsym(RTLD_NEXT, "gettimeofday")); #if defined(_musl_) if (!Func) { Func = reinterpret_cast<TFunc>(NVdso::Function("__vdso_gettimeofday", "LINUX_2.6")); } #endif if (!Func) { Func = reinterpret_cast<TFunc>(Libc()->Sym("gettimeofday")); } } inline TTime SystemTime() { timeval tv; Zero(tv); Func(&tv, nullptr); return (((TTime)1000000) * (TTime)tv.tv_sec) + (TTime)tv.tv_usec; } static inline THolder<TDynamicLibrary> OpenLibc() { const char* libs[] = { "/lib/libc.so.8", "/lib/libc.so.7", "/lib/libc.so.6", }; for (auto& lib : libs) { try { return MakeHolder<TDynamicLibrary>(lib); } catch (...) { // ¯\_(ツ)_/¯ } } ythrow yexception() << "can not load libc"; } inline TDynamicLibrary* Libc() { if (!Lib) { Lib = OpenLibc(); } return Lib.Get(); } THolder<TDynamicLibrary> Lib; TFunc Func; }; static inline TTime SystemTime() { return Singleton<TSymbols>()->SystemTime(); } struct TInitialTimes { inline TInitialTimes() : ITime(TimeBase()) , IProc(RdtscBase()) { } static TTime RdtscBase() { return GetCycleCount() / (TTime)1000; } static TTime TimeBase() { return SystemTime(); } inline TTime Rdtsc() { return RdtscBase() - IProc; } inline TTime Time() { return TimeBase() - ITime; } const TTime ITime; const TTime IProc; }; template <size_t N, class A, class B> class TLinePredictor { public: using TSample = std::pair<A, B>; inline TLinePredictor() : C_(0) , A_(0) , B_(0) { } inline void Add(const A& a, const B& b) noexcept { Add(TSample(a, b)); } inline void Add(const TSample& s) noexcept { S_[(C_++) % N] = s; if (C_ > 1) { ReCalc(); } } inline B Predict(A a) const noexcept { return A_ + a * B_; } inline size_t Size() const noexcept { return C_; } inline bool Enough() const noexcept { return Size() >= N; } inline A LastX() const noexcept { return S_[(C_ - 1) % N].first; } private: inline void ReCalc() noexcept { const size_t n = Min(N, C_); double sx = 0; double sy = 0; double sxx = 0; double syy = 0; double sxy = 0; for (size_t i = 0; i < n; ++i) { const double x = S_[i].first; const double y = S_[i].second; sx += x; sy += y; sxx += x * x; syy += y * y; sxy += x * y; } B_ = (n * sxy - sx * sy) / (n * sxx - sx * sx); A_ = (sy - B_ * sx) / n; } private: size_t C_; TSample S_[N]; double A_; double B_; }; class TTimePredictor: public TInitialTimes { public: inline TTimePredictor() : Next_(1) { } inline TTime Get() { return GetBase() + ITime; } private: inline TTime GetBase() { const TTime x = Rdtsc(); if (TimeToSync(x)) { const TTime y = Time(); P_.Add(x, y); return y; } if (P_.Enough()) { return P_.Predict(x); } return Time(); } inline bool TimeToSync(TTime x) { if (x > Next_) { Next_ = Min(x + x / 10, x + 1000000); return true; } return false; } private: TLinePredictor<16, TTime, TTime> P_; TTime Next_; }; } ui64 InterpolatedMicroSeconds() { return FastTlsSingleton<TTimePredictor>()->Get(); } #endif