aboutsummaryrefslogblamecommitdiffstats
path: root/library/cpp/monlib/counters/timer.h
blob: 03dfb35337f72f1a61d677c87df0a7034fcdb8a1 (plain) (tree)
1
2
3
4
5
6


                      
                               









































































































                                                                                       
 
                                       
                                       









































                                                                                                                  
         













                                                                   
#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_;
    };
}