aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/yt/cpu_clock/clock.cpp
blob: 22f665e1d35b0bb045717c6700901100b44f50a7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#include "clock.h"

#include <util/system/hp_timer.h>

#include <library/cpp/yt/assert/assert.h>

#include <library/cpp/yt/misc/tls.h>

namespace NYT {

////////////////////////////////////////////////////////////////////////////////

// Re-calibrate every 1B CPU ticks.
constexpr auto CalibrationCpuPeriod = 1'000'000'000;

struct TCalibrationState
{
    TCpuInstant CpuInstant;
    TInstant Instant;
};

double GetMicrosecondsToTicks()
{
    static const auto MicrosecondsToTicks = static_cast<double>(NHPTimer::GetCyclesPerSecond()) / 1'000'000;
    return MicrosecondsToTicks;
}

double GetTicksToMicroseconds()
{
    static const auto TicksToMicroseconds = 1.0 / GetMicrosecondsToTicks();
    return TicksToMicroseconds;
}

YT_PREVENT_TLS_CACHING TCalibrationState GetCalibrationState(TCpuInstant cpuInstant)
{
    thread_local TCalibrationState State;

    if (State.CpuInstant + CalibrationCpuPeriod < cpuInstant) {
        State.CpuInstant = cpuInstant;
        State.Instant = TInstant::Now();
    }

    return State;
}

TCalibrationState GetCalibrationState()
{
    return GetCalibrationState(GetCpuInstant());
}

TDuration CpuDurationToDuration(TCpuDuration cpuDuration, double ticksToMicroseconds)
{
    // TDuration is unsigned and thus does not support negative values.
    if (cpuDuration < 0) {
        return TDuration::Zero();
    }
    return TDuration::MicroSeconds(static_cast<ui64>(cpuDuration * ticksToMicroseconds));
}

TCpuDuration DurationToCpuDuration(TDuration duration, double microsecondsToTicks)
{
    return static_cast<TCpuDuration>(duration.MicroSeconds() * microsecondsToTicks);
}

TInstant GetInstant()
{
    auto cpuInstant = GetCpuInstant();
    auto state = GetCalibrationState(cpuInstant);
    YT_ASSERT(cpuInstant >= state.CpuInstant);
    return state.Instant + CpuDurationToDuration(cpuInstant - state.CpuInstant, GetTicksToMicroseconds());
}

TDuration CpuDurationToDuration(TCpuDuration cpuDuration)
{
    return CpuDurationToDuration(cpuDuration, GetTicksToMicroseconds());
}

TCpuDuration DurationToCpuDuration(TDuration duration)
{
    return DurationToCpuDuration(duration, GetMicrosecondsToTicks());
}

TInstant CpuInstantToInstant(TCpuInstant cpuInstant)
{
    // TDuration is unsigned and does not support negative values,
    // thus we consider two cases separately.
    auto state = GetCalibrationState();
    return cpuInstant >= state.CpuInstant
        ? state.Instant + CpuDurationToDuration(cpuInstant - state.CpuInstant, GetTicksToMicroseconds())
        : state.Instant - CpuDurationToDuration(state.CpuInstant - cpuInstant, GetTicksToMicroseconds());
}

TCpuInstant InstantToCpuInstant(TInstant instant)
{
    // See above.
    auto state = GetCalibrationState();
    return instant >= state.Instant
        ? state.CpuInstant + DurationToCpuDuration(instant - state.Instant, GetMicrosecondsToTicks())
        : state.CpuInstant - DurationToCpuDuration(state.Instant - instant, GetMicrosecondsToTicks());
}

////////////////////////////////////////////////////////////////////////////////

} // namespace NYT