#include "cputimer.h"
#include <util/system/defaults.h>
#include <util/system/hp_timer.h>
#include <util/string/printf.h>
#include <util/stream/output.h>
#include <util/generic/singleton.h>
#if defined(_unix_)
#include <unistd.h>
#include <sched.h>
#elif defined(_win_)
#include <util/system/winint.h>
#endif
TTimer::TTimer(const TStringBuf message) {
static const int SMALL_DURATION_CHAR_LENGTH = 9; // strlen("0.123456s")
Message_.Reserve(message.length() + SMALL_DURATION_CHAR_LENGTH + 1); // +"\n"
Message_ << message;
// Do not measure the allocations above.
Start_ = TInstant::Now();
}
TTimer::~TTimer() {
const TDuration duration = TInstant::Now() - Start_;
Message_ << duration << "\n";
Cerr << Message_.Str();
}
static ui64 ManuallySetCyclesPerSecond = 0;
static ui64 GetCyclesPerSecond() {
if (ManuallySetCyclesPerSecond != 0) {
return ManuallySetCyclesPerSecond;
} else {
return NHPTimer::GetCyclesPerSecond();
}
}
void SetCyclesPerSecond(ui64 cycles) {
ManuallySetCyclesPerSecond = cycles;
}
ui64 GetCyclesPerMillisecond() {
return GetCyclesPerSecond() / 1000;
}
TDuration CyclesToDuration(ui64 cycles) {
return TDuration::MicroSeconds(cycles * 1000000 / GetCyclesPerSecond());
}
TDuration CyclesToDurationSafe(ui64 cycles)
{
constexpr ui64 cyclesLimit = std::numeric_limits<ui64>::max() / 1000000;
if (cycles <= cyclesLimit) {
return CyclesToDuration(cycles);
}
return TDuration::MicroSeconds(cycles / GetCyclesPerSecond() * 1000000);
}
ui64 DurationToCycles(TDuration duration) {
return duration.MicroSeconds() * GetCyclesPerSecond() / 1000000;
}
ui64 DurationToCyclesSafe(TDuration duration)
{
if (duration.MicroSeconds() <= std::numeric_limits<ui64>::max() / GetCyclesPerSecond()) {
return DurationToCycles(duration);
}
return duration.MicroSeconds() / 1000000 * GetCyclesPerSecond();
}
TPrecisionTimer::TPrecisionTimer()
: Start(::GetCycleCount())
{
}
ui64 TPrecisionTimer::GetCycleCount() const {
return ::GetCycleCount() - Start;
}
TString FormatCycles(ui64 cycles) {
ui64 milliseconds = cycles / GetCyclesPerMillisecond();
ui32 ms = ui32(milliseconds % 1000);
milliseconds /= 1000;
ui32 secs = ui32(milliseconds % 60);
milliseconds /= 60;
ui32 mins = ui32(milliseconds);
TString result;
sprintf(result, "%" PRIu32 " m %.2" PRIu32 " s %.3" PRIu32 " ms", mins, secs, ms);
return result;
}
TFormattedPrecisionTimer::TFormattedPrecisionTimer(const char* message, IOutputStream* out)
: Message(message)
, Out(out)
{
Start = GetCycleCount();
}
TFormattedPrecisionTimer::~TFormattedPrecisionTimer() {
const ui64 end = GetCycleCount();
const ui64 diff = end - Start;
*Out << Message << ": " << diff << " ticks " << FormatCycles(diff) << Endl;
}
TFuncTimer::TFuncTimer(const char* func)
: Start_(TInstant::Now())
, Func_(func)
{
Cerr << "enter " << Func_ << Endl;
}
TFuncTimer::~TFuncTimer() {
Cerr << "leave " << Func_ << " -> " << (TInstant::Now() - Start_) << Endl;
}
TTimeLogger::TTimeLogger(const TString& message, bool verbose)
: Message(message)
, Verbose(verbose)
, OK(false)
, Begin(time(nullptr))
, BeginCycles(GetCycleCount())
{
if (Verbose) {
fprintf(stderr, "=========================================================\n");
fprintf(stderr, "%s started: %.24s (%lu) (%d)\n", Message.data(), ctime(&Begin), (unsigned long)Begin, (int)getpid());
}
}
double TTimeLogger::ElapsedTime() const {
return time(nullptr) - Begin;
}
void TTimeLogger::SetOK() {
OK = true;
}
TTimeLogger::~TTimeLogger() {
time_t tim = time(nullptr);
ui64 endCycles = GetCycleCount();
if (Verbose) {
const char* prefix = (OK) ? "" : "!";
fprintf(stderr, "%s%s ended: %.24s (%lu) (%d) (took %lus = %s)\n",
prefix, Message.data(), ctime(&tim), (unsigned long)tim, (int)getpid(),
(unsigned long)tim - (unsigned long)Begin, FormatCycles(endCycles - BeginCycles).data());
fprintf(stderr, "%s=========================================================\n", prefix);
}
}