| /* |
| * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #ifndef VIDEO_STATS_COUNTER_H_ |
| #define VIDEO_STATS_COUNTER_H_ |
| |
| #include <memory> |
| #include <string> |
| |
| namespace webrtc { |
| |
| class AggregatedCounter; |
| class Clock; |
| class Samples; |
| |
| // `StatsCounterObserver` is called periodically when a metric is updated. |
| class StatsCounterObserver { |
| public: |
| virtual void OnMetricUpdated(int sample) = 0; |
| |
| virtual ~StatsCounterObserver() {} |
| }; |
| |
| struct AggregatedStats { |
| std::string ToString() const; |
| std::string ToStringWithMultiplier(int multiplier) const; |
| |
| int64_t num_samples = 0; |
| int min = -1; |
| int max = -1; |
| int average = -1; |
| // TODO(asapersson): Consider adding median/percentiles. |
| }; |
| |
| // Classes which periodically computes a metric. |
| // |
| // During a period, `kProcessIntervalMs`, different metrics can be computed e.g: |
| // - `AvgCounter`: average of samples |
| // - `PercentCounter`: percentage of samples |
| // - `PermilleCounter`: permille of samples |
| // |
| // Each periodic metric can be either: |
| // - reported to an `observer` each period |
| // - aggregated during the call (e.g. min, max, average) |
| // |
| // periodically computed |
| // GetMetric() GetMetric() => AggregatedStats |
| // ^ ^ (e.g. min/max/avg) |
| // | | |
| // | * * * * | ** * * * * | ... |
| // |<- process interval ->| |
| // |
| // (*) - samples |
| // |
| // |
| // Example usage: |
| // |
| // AvgCounter counter(&clock, nullptr); |
| // counter.Add(5); |
| // counter.Add(1); |
| // counter.Add(6); // process interval passed -> GetMetric() avg:4 |
| // counter.Add(7); |
| // counter.Add(3); // process interval passed -> GetMetric() avg:5 |
| // counter.Add(10); |
| // counter.Add(20); // process interval passed -> GetMetric() avg:15 |
| // AggregatedStats stats = counter.GetStats(); |
| // stats: {min:4, max:15, avg:8} |
| // |
| |
| // Note: StatsCounter takes ownership of `observer`. |
| |
| class StatsCounter { |
| public: |
| virtual ~StatsCounter(); |
| |
| // Gets metric within an interval. Returns true on success false otherwise. |
| virtual bool GetMetric(int* metric) const = 0; |
| |
| // Gets the value to use for an interval without samples. |
| virtual int GetValueForEmptyInterval() const = 0; |
| |
| // Gets aggregated stats (i.e. aggregate of periodically computed metrics). |
| AggregatedStats GetStats(); |
| |
| // Reports metrics for elapsed intervals to AggregatedCounter and GetStats. |
| AggregatedStats ProcessAndGetStats(); |
| |
| // Reports metrics for elapsed intervals to AggregatedCounter and pauses stats |
| // (i.e. empty intervals will be discarded until next sample is added). |
| void ProcessAndPause(); |
| |
| // As above with a minimum pause time. Added samples within this interval will |
| // not resume the stats (i.e. stop the pause). |
| void ProcessAndPauseForDuration(int64_t min_pause_time_ms); |
| |
| // Reports metrics for elapsed intervals to AggregatedCounter and stops pause. |
| void ProcessAndStopPause(); |
| |
| // Checks if a sample has been added (i.e. Add or Set called). |
| bool HasSample() const; |
| |
| protected: |
| StatsCounter(Clock* clock, |
| int64_t process_intervals_ms, |
| bool include_empty_intervals, |
| StatsCounterObserver* observer); |
| |
| void Add(int sample); |
| void Set(int64_t sample, uint32_t stream_id); |
| void SetLast(int64_t sample, uint32_t stream_id); |
| |
| const bool include_empty_intervals_; |
| const int64_t process_intervals_ms_; |
| const std::unique_ptr<AggregatedCounter> aggregated_counter_; |
| const std::unique_ptr<Samples> samples_; |
| |
| private: |
| bool TimeToProcess(int* num_elapsed_intervals); |
| void TryProcess(); |
| void ReportMetricToAggregatedCounter(int value, int num_values_to_add) const; |
| bool IncludeEmptyIntervals() const; |
| void Resume(); |
| void ResumeIfMinTimePassed(); |
| |
| Clock* const clock_; |
| const std::unique_ptr<StatsCounterObserver> observer_; |
| int64_t last_process_time_ms_; |
| bool paused_; |
| int64_t pause_time_ms_; |
| int64_t min_pause_time_ms_; |
| }; |
| |
| // AvgCounter: average of samples |
| // |
| // | * * * | * * | ... |
| // | Add(5) Add(1) Add(6) | Add(5) Add(5) | |
| // GetMetric | (5 + 1 + 6) / 3 | (5 + 5) / 2 | |
| // |
| // `include_empty_intervals`: If set, intervals without samples will be included |
| // in the stats. The value for an interval is |
| // determined by GetValueForEmptyInterval(). |
| // |
| class AvgCounter : public StatsCounter { |
| public: |
| AvgCounter(Clock* clock, |
| StatsCounterObserver* observer, |
| bool include_empty_intervals); |
| ~AvgCounter() override {} |
| |
| AvgCounter(const AvgCounter&) = delete; |
| AvgCounter& operator=(const AvgCounter&) = delete; |
| |
| void Add(int sample); |
| |
| private: |
| bool GetMetric(int* metric) const override; |
| |
| // Returns the last computed metric (i.e. from GetMetric). |
| int GetValueForEmptyInterval() const override; |
| }; |
| |
| // MaxCounter: maximum of samples |
| // |
| // | * * * | * * | ... |
| // | Add(5) Add(1) Add(6) | Add(5) Add(5) | |
| // GetMetric | max: (5, 1, 6) | max: (5, 5) | |
| // |
| class MaxCounter : public StatsCounter { |
| public: |
| MaxCounter(Clock* clock, |
| StatsCounterObserver* observer, |
| int64_t process_intervals_ms); |
| ~MaxCounter() override {} |
| |
| MaxCounter(const MaxCounter&) = delete; |
| MaxCounter& operator=(const MaxCounter&) = delete; |
| |
| void Add(int sample); |
| |
| private: |
| bool GetMetric(int* metric) const override; |
| int GetValueForEmptyInterval() const override; |
| }; |
| |
| // PercentCounter: percentage of samples |
| // |
| // | * * * | * * | ... |
| // | Add(T) Add(F) Add(T) | Add(F) Add(T) | |
| // GetMetric | 100 * 2 / 3 | 100 * 1 / 2 | |
| // |
| class PercentCounter : public StatsCounter { |
| public: |
| PercentCounter(Clock* clock, StatsCounterObserver* observer); |
| ~PercentCounter() override {} |
| |
| PercentCounter(const PercentCounter&) = delete; |
| PercentCounter& operator=(const PercentCounter&) = delete; |
| |
| void Add(bool sample); |
| |
| private: |
| bool GetMetric(int* metric) const override; |
| int GetValueForEmptyInterval() const override; |
| }; |
| |
| // PermilleCounter: permille of samples |
| // |
| // | * * * | * * | ... |
| // | Add(T) Add(F) Add(T) | Add(F) Add(T) | |
| // GetMetric | 1000 * 2 / 3 | 1000 * 1 / 2 | |
| // |
| class PermilleCounter : public StatsCounter { |
| public: |
| PermilleCounter(Clock* clock, StatsCounterObserver* observer); |
| ~PermilleCounter() override {} |
| |
| PermilleCounter(const PermilleCounter&) = delete; |
| PermilleCounter& operator=(const PermilleCounter&) = delete; |
| |
| void Add(bool sample); |
| |
| private: |
| bool GetMetric(int* metric) const override; |
| int GetValueForEmptyInterval() const override; |
| }; |
| |
| // RateCounter: units per second |
| // |
| // | * * * | * * | ... |
| // | Add(5) Add(1) Add(6) | Add(5) Add(5) | |
| // |<------ 2 sec ------->| | |
| // GetMetric | (5 + 1 + 6) / 2 | (5 + 5) / 2 | |
| // |
| // `include_empty_intervals`: If set, intervals without samples will be included |
| // in the stats. The value for an interval is |
| // determined by GetValueForEmptyInterval(). |
| // |
| class RateCounter : public StatsCounter { |
| public: |
| RateCounter(Clock* clock, |
| StatsCounterObserver* observer, |
| bool include_empty_intervals); |
| ~RateCounter() override {} |
| |
| RateCounter(const RateCounter&) = delete; |
| RateCounter& operator=(const RateCounter&) = delete; |
| |
| void Add(int sample); |
| |
| private: |
| bool GetMetric(int* metric) const override; |
| int GetValueForEmptyInterval() const override; // Returns zero. |
| }; |
| |
| // RateAccCounter: units per second (used for counters) |
| // |
| // | * * * | * * | ... |
| // | Set(5) Set(6) Set(8) | Set(11) Set(13) | |
| // |<------ 2 sec ------->| | |
| // GetMetric | (8 - 0) / 2 | (13 - 8) / 2 | |
| // |
| // `include_empty_intervals`: If set, intervals without samples will be included |
| // in the stats. The value for an interval is |
| // determined by GetValueForEmptyInterval(). |
| // |
| class RateAccCounter : public StatsCounter { |
| public: |
| RateAccCounter(Clock* clock, |
| StatsCounterObserver* observer, |
| bool include_empty_intervals); |
| ~RateAccCounter() override {} |
| |
| RateAccCounter(const RateAccCounter&) = delete; |
| RateAccCounter& operator=(const RateAccCounter&) = delete; |
| |
| void Set(int64_t sample, uint32_t stream_id); |
| |
| // Sets the value for previous interval. |
| // To be used if a value other than zero is initially required. |
| void SetLast(int64_t sample, uint32_t stream_id); |
| |
| private: |
| bool GetMetric(int* metric) const override; |
| int GetValueForEmptyInterval() const override; // Returns zero. |
| }; |
| |
| } // namespace webrtc |
| |
| #endif // VIDEO_STATS_COUNTER_H_ |