aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/monlib/counters/timer.h
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/monlib/counters/timer.h
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/monlib/counters/timer.h')
-rw-r--r--library/cpp/monlib/counters/timer.h176
1 files changed, 176 insertions, 0 deletions
diff --git a/library/cpp/monlib/counters/timer.h b/library/cpp/monlib/counters/timer.h
new file mode 100644
index 0000000000..03dfb35337
--- /dev/null
+++ b/library/cpp/monlib/counters/timer.h
@@ -0,0 +1,176 @@
+#pragma once
+
+#include "histogram.h"
+
+#include <util/generic/scope.h>
+
+#include <chrono>
+
+namespace NMonitoring {
+ /**
+ * A timer counter which aggregates timing durations and provides duration
+ * statistics in selected time resolution.
+ */
+ template <typename TResolution>
+ class TTimerImpl {
+ public:
+ /**
+ * Construct a timer given the Lowest and Highest values to be tracked
+ * and a number of significant decimal digits. Providing a
+ * lowestDiscernibleValue is useful in situations where the units used for
+ * the timer's values are much smaller that the minimal accuracy
+ * required. E.g. when tracking time values stated in nanosecond units,
+ * where the minimal accuracy required is a microsecond, the proper value
+ * for lowestDiscernibleValue would be 1000.
+ *
+ * @param min The lowest value that can be discerned (distinguished from
+ * 0) by the timer. Must be a positive integer that is >= 1.
+ * May be internally rounded down to nearest power of 2.
+ *
+ * @param max The highest value to be tracked by the timer. Must be a
+ * positive integer that is >= (2 * min).
+ *
+ * @param numberOfSignificantValueDigits Specifies the precision to use.
+ * This is the number of significant decimal digits to which the
+ * timer will maintain value resolution and separation. Must be
+ * a non-negative integer between 0 and 5.
+ */
+ TTimerImpl(ui64 min, ui64 max, i32 numberOfSignificantValueDigits = 3)
+ : TTimerImpl(TResolution(min), TResolution(max),
+ numberOfSignificantValueDigits) {
+ }
+
+ /**
+ * Construct a timer given the Lowest and Highest values to be tracked
+ * and a number of significant decimal digits.
+ *
+ * @param min The lowest value that can be discerned (distinguished from
+ * 0) by the timer.
+ *
+ * @param max The highest value to be tracked by the histogram. Must be a
+ * positive integer that is >= (2 * min).
+ *
+ * @param numberOfSignificantValueDigits Specifies the precision to use.
+ */
+ template <typename TDurationMin, typename TDurationMax>
+ TTimerImpl(TDurationMin min, TDurationMax max,
+ i32 numberOfSignificantValueDigits = 3)
+ : Histogram_(std::chrono::duration_cast<TResolution>(min).count(),
+ std::chrono::duration_cast<TResolution>(max).count(),
+ numberOfSignificantValueDigits) {
+ }
+
+ /**
+ * Records a value in the timer with timer resulution. Recorded value will
+ * be rounded to a precision at or better than the
+ * NumberOfSignificantValueDigits specified at construction time.
+ *
+ * @param duration duration to add to the timer
+ * @return false if the value is larger than the max and can't be recorded,
+ * true otherwise.
+ */
+ bool RecordValue(ui64 duration) {
+ return Histogram_.RecordValue(duration);
+ }
+
+ /**
+ * Records a duration in the timer. Recorded value will be converted to
+ * the timer resulution and rounded to a precision at or better than the
+ * NumberOfSignificantValueDigits specified at construction time.
+ *
+ * @param duration duration to add to the timer
+ * @return false if the value is larger than the max and can't be recorded,
+ * true otherwise.
+ */
+ template <typename TDuration>
+ bool RecordValue(TDuration duration) {
+ auto count = static_cast<ui64>(
+ std::chrono::duration_cast<TResolution>(duration).count());
+ return RecordValue(count);
+ }
+
+ /**
+ * Records count values in the timer with timer resulution. Recorded value will
+ * be rounded to a precision at or better than the
+ * NumberOfSignificantValueDigits specified at construction time.
+ *
+ * @param duration duration to add to the timer
+ * @param count number of values to add to the histogram
+ * @return false if the value is larger than the max and can't be recorded,
+ * true otherwise.
+ */
+ bool RecordValues(ui64 duration, ui64 count) {
+ return Histogram_.RecordValues(duration, count);
+ }
+
+ /**
+ * Measures a time of functor execution.
+ *
+ * @param fn functor whose duration should be timed
+ */
+ template <typename TFunc>
+ void Measure(TFunc&& fn) {
+ using TClock = std::chrono::high_resolution_clock;
+
+ auto start = TClock::now();
+
+ Y_SCOPE_EXIT(this, start) {
+ RecordValue(TClock::now() - start);
+ };
+
+ fn();
+ }
+
+ /**
+ * Place a copy of the value counts accumulated since the last snapshot
+ * was taken into {@code snapshot}. Calling this member-function will
+ * reset the value counts, and start accumulating value counts for the
+ * next interval.
+ *
+ * @param snapshot the structure into which the values should be copied.
+ */
+ void TakeSnapshot(THistogramSnapshot* snapshot) {
+ Histogram_.TakeSnaphot(snapshot);
+ }
+
+ private:
+ THdrHistogram Histogram_;
+ };
+
+ /**
+ * Timer template instantiations for certain time resolutions.
+ */
+ using TTimerNs = TTimerImpl<std::chrono::nanoseconds>;
+ using TTimerUs = TTimerImpl<std::chrono::microseconds>;
+ using TTimerMs = TTimerImpl<std::chrono::milliseconds>;
+ using TTimerS = TTimerImpl<std::chrono::seconds>;
+
+ /**
+ * A timing scope to record elapsed time since creation.
+ */
+ template <typename TTimer, typename TFunc = std::function<void(std::chrono::high_resolution_clock::duration)>>
+ class TTimerScope {
+ using TClock = std::chrono::high_resolution_clock;
+
+ public:
+ explicit TTimerScope(TTimer* timer, TFunc* callback = nullptr)
+ : Timer_(timer)
+ , StartTime_(TClock::now())
+ , Callback_(callback)
+ {
+ }
+
+ ~TTimerScope() {
+ TClock::duration duration = TClock::now() - StartTime_;
+ if (Callback_) {
+ (*Callback_)(duration);
+ }
+ Timer_->RecordValue(duration);
+ }
+
+ private:
+ TTimer* Timer_;
+ TClock::time_point StartTime_;
+ TFunc* Callback_;
+ };
+}