LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/video - stats_counter.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 230 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 60 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #include "webrtc/video/stats_counter.h"
      12             : 
      13             : #include <algorithm>
      14             : #include <limits>
      15             : #include <map>
      16             : 
      17             : #include "webrtc/base/checks.h"
      18             : #include "webrtc/system_wrappers/include/clock.h"
      19             : 
      20             : namespace webrtc {
      21             : 
      22             : namespace {
      23             : // Default periodic time interval for processing samples.
      24             : const int64_t kDefaultProcessIntervalMs = 2000;
      25             : const uint32_t kStreamId0 = 0;
      26             : }  // namespace
      27             : 
      28           0 : std::string AggregatedStats::ToString() const {
      29           0 :   return ToStringWithMultiplier(1);
      30             : }
      31             : 
      32           0 : std::string AggregatedStats::ToStringWithMultiplier(int multiplier) const {
      33           0 :   std::stringstream ss;
      34           0 :   ss << "periodic_samples:" << num_samples << ", {";
      35           0 :   ss << "min:" << (min * multiplier) << ", ";
      36           0 :   ss << "avg:" << (average * multiplier) << ", ";
      37           0 :   ss << "max:" << (max * multiplier) << "}";
      38           0 :   return ss.str();
      39             : }
      40             : 
      41             : // Class holding periodically computed metrics.
      42             : class AggregatedCounter {
      43             :  public:
      44           0 :   AggregatedCounter() : last_sample_(0), sum_samples_(0) {}
      45           0 :   ~AggregatedCounter() {}
      46             : 
      47           0 :   void Add(int sample) {
      48           0 :     last_sample_ = sample;
      49           0 :     sum_samples_ += sample;
      50           0 :     ++stats_.num_samples;
      51           0 :     if (stats_.num_samples == 1) {
      52           0 :       stats_.min = sample;
      53           0 :       stats_.max = sample;
      54             :     }
      55           0 :     stats_.min = std::min(sample, stats_.min);
      56           0 :     stats_.max = std::max(sample, stats_.max);
      57           0 :   }
      58             : 
      59           0 :   AggregatedStats ComputeStats() {
      60           0 :     Compute();
      61           0 :     return stats_;
      62             :   }
      63             : 
      64           0 :   bool Empty() const { return stats_.num_samples == 0; }
      65             : 
      66           0 :   int last_sample() const { return last_sample_; }
      67             : 
      68             :  private:
      69           0 :   void Compute() {
      70           0 :     if (stats_.num_samples == 0)
      71           0 :       return;
      72             : 
      73           0 :     stats_.average =
      74           0 :         (sum_samples_ + stats_.num_samples / 2) / stats_.num_samples;
      75             :   }
      76             :   int last_sample_;
      77             :   int64_t sum_samples_;
      78             :   AggregatedStats stats_;
      79             : };
      80             : 
      81             : // Class holding gathered samples within a process interval.
      82             : class Samples {
      83             :  public:
      84           0 :   Samples() : total_count_(0) {}
      85           0 :   ~Samples() {}
      86             : 
      87           0 :   void Add(int sample, uint32_t stream_id) {
      88           0 :     samples_[stream_id].Add(sample);
      89           0 :     ++total_count_;
      90           0 :   }
      91           0 :   void Set(int sample, uint32_t stream_id) {
      92           0 :     samples_[stream_id].Set(sample);
      93           0 :     ++total_count_;
      94           0 :   }
      95             : 
      96           0 :   int64_t Count() const { return total_count_; }
      97           0 :   bool Empty() const { return total_count_ == 0; }
      98             : 
      99           0 :   int64_t Sum() const {
     100           0 :     int64_t sum = 0;
     101           0 :     for (const auto& it : samples_)
     102           0 :       sum += it.second.sum_;
     103           0 :     return sum;
     104             :   }
     105             : 
     106           0 :   int Max() const {
     107           0 :     int max = std::numeric_limits<int>::min();
     108           0 :     for (const auto& it : samples_)
     109           0 :       max = std::max(it.second.max_, max);
     110           0 :     return max;
     111             :   }
     112             : 
     113           0 :   void Reset() {
     114           0 :     for (auto& it : samples_)
     115           0 :       it.second.Reset();
     116           0 :     total_count_ = 0;
     117           0 :   }
     118             : 
     119           0 :   int64_t Diff() const {
     120           0 :     int64_t sum_diff = 0;
     121           0 :     int count = 0;
     122           0 :     for (const auto& it : samples_) {
     123           0 :       if (it.second.count_ > 0) {
     124           0 :         int64_t diff = it.second.sum_ - it.second.last_sum_;
     125           0 :         if (diff >= 0) {
     126           0 :           sum_diff += diff;
     127           0 :           ++count;
     128             :         }
     129             :       }
     130             :     }
     131           0 :     return (count > 0) ? sum_diff : -1;
     132             :   }
     133             : 
     134             :  private:
     135           0 :   struct Stats {
     136           0 :     void Add(int sample) {
     137           0 :       sum_ += sample;
     138           0 :       ++count_;
     139           0 :       max_ = std::max(sample, max_);
     140           0 :     }
     141           0 :     void Set(int sample) {
     142           0 :       sum_ = sample;
     143           0 :       ++count_;
     144           0 :     }
     145           0 :     void Reset() {
     146           0 :       if (count_ > 0)
     147           0 :         last_sum_ = sum_;
     148           0 :       sum_ = 0;
     149           0 :       count_ = 0;
     150           0 :       max_ = std::numeric_limits<int>::min();
     151           0 :     }
     152             : 
     153           0 :     int max_ = std::numeric_limits<int>::min();
     154             :     int64_t count_ = 0;
     155             :     int64_t sum_ = 0;
     156             :     int64_t last_sum_ = 0;
     157             :   };
     158             : 
     159             :   int64_t total_count_;
     160             :   std::map<uint32_t, Stats> samples_;  // Gathered samples mapped by stream id.
     161             : };
     162             : 
     163             : // StatsCounter class.
     164           0 : StatsCounter::StatsCounter(Clock* clock,
     165             :                            int64_t process_intervals_ms,
     166             :                            bool include_empty_intervals,
     167           0 :                            StatsCounterObserver* observer)
     168             :     : include_empty_intervals_(include_empty_intervals),
     169             :       process_intervals_ms_(process_intervals_ms),
     170           0 :       aggregated_counter_(new AggregatedCounter()),
     171           0 :       samples_(new Samples()),
     172             :       clock_(clock),
     173             :       observer_(observer),
     174             :       last_process_time_ms_(-1),
     175           0 :       paused_(false) {
     176           0 :   RTC_DCHECK_GT(process_intervals_ms_, 0);
     177           0 : }
     178             : 
     179           0 : StatsCounter::~StatsCounter() {}
     180             : 
     181           0 : AggregatedStats StatsCounter::GetStats() {
     182           0 :   return aggregated_counter_->ComputeStats();
     183             : }
     184             : 
     185           0 : AggregatedStats StatsCounter::ProcessAndGetStats() {
     186           0 :   if (HasSample())
     187           0 :     TryProcess();
     188           0 :   return aggregated_counter_->ComputeStats();
     189             : }
     190             : 
     191           0 : void StatsCounter::ProcessAndPause() {
     192           0 :   if (HasSample())
     193           0 :     TryProcess();
     194           0 :   paused_ = true;
     195           0 : }
     196             : 
     197           0 : bool StatsCounter::HasSample() const {
     198           0 :   return last_process_time_ms_ != -1;
     199             : }
     200             : 
     201           0 : bool StatsCounter::TimeToProcess(int* elapsed_intervals) {
     202           0 :   int64_t now = clock_->TimeInMilliseconds();
     203           0 :   if (last_process_time_ms_ == -1)
     204           0 :     last_process_time_ms_ = now;
     205             : 
     206           0 :   int64_t diff_ms = now - last_process_time_ms_;
     207           0 :   if (diff_ms < process_intervals_ms_)
     208           0 :     return false;
     209             : 
     210             :   // Advance number of complete |process_intervals_ms_| that have passed.
     211           0 :   int64_t num_intervals = diff_ms / process_intervals_ms_;
     212           0 :   last_process_time_ms_ += num_intervals * process_intervals_ms_;
     213             : 
     214           0 :   *elapsed_intervals = num_intervals;
     215           0 :   return true;
     216             : }
     217             : 
     218           0 : void StatsCounter::Set(int sample, uint32_t stream_id) {
     219           0 :   TryProcess();
     220           0 :   samples_->Set(sample, stream_id);
     221           0 :   paused_ = false;
     222           0 : }
     223             : 
     224           0 : void StatsCounter::Add(int sample) {
     225           0 :   TryProcess();
     226           0 :   samples_->Add(sample, kStreamId0);
     227           0 :   paused_ = false;
     228           0 : }
     229             : 
     230             : // Reports periodically computed metric.
     231           0 : void StatsCounter::ReportMetricToAggregatedCounter(
     232             :     int value,
     233             :     int num_values_to_add) const {
     234           0 :   for (int i = 0; i < num_values_to_add; ++i) {
     235           0 :     aggregated_counter_->Add(value);
     236           0 :     if (observer_)
     237           0 :       observer_->OnMetricUpdated(value);
     238             :   }
     239           0 : }
     240             : 
     241           0 : void StatsCounter::TryProcess() {
     242             :   int elapsed_intervals;
     243           0 :   if (!TimeToProcess(&elapsed_intervals))
     244           0 :     return;
     245             : 
     246             :   // Get and report periodically computed metric.
     247             :   int metric;
     248           0 :   if (GetMetric(&metric))
     249           0 :     ReportMetricToAggregatedCounter(metric, 1);
     250             : 
     251             :   // Report value for elapsed intervals without samples.
     252           0 :   if (IncludeEmptyIntervals()) {
     253             :     // If there are no samples, all elapsed intervals are empty (otherwise one
     254             :     // interval contains sample(s), discard this interval).
     255             :     int empty_intervals =
     256           0 :         samples_->Empty() ? elapsed_intervals : (elapsed_intervals - 1);
     257           0 :     ReportMetricToAggregatedCounter(GetValueForEmptyInterval(),
     258           0 :                                     empty_intervals);
     259             :   }
     260             : 
     261             :   // Reset samples for elapsed interval.
     262           0 :   samples_->Reset();
     263             : }
     264             : 
     265           0 : bool StatsCounter::IncludeEmptyIntervals() const {
     266           0 :   return include_empty_intervals_ && !paused_ && !aggregated_counter_->Empty();
     267             : }
     268             : 
     269             : // StatsCounter sub-classes.
     270           0 : AvgCounter::AvgCounter(Clock* clock,
     271             :                        StatsCounterObserver* observer,
     272           0 :                        bool include_empty_intervals)
     273             :     : StatsCounter(clock,
     274             :                    kDefaultProcessIntervalMs,
     275             :                    include_empty_intervals,
     276           0 :                    observer) {}
     277             : 
     278           0 : void AvgCounter::Add(int sample) {
     279           0 :   StatsCounter::Add(sample);
     280           0 : }
     281             : 
     282           0 : bool AvgCounter::GetMetric(int* metric) const {
     283           0 :   int64_t count = samples_->Count();
     284           0 :   if (count == 0)
     285           0 :     return false;
     286             : 
     287           0 :   *metric = (samples_->Sum() + count / 2) / count;
     288           0 :   return true;
     289             : }
     290             : 
     291           0 : int AvgCounter::GetValueForEmptyInterval() const {
     292           0 :   return aggregated_counter_->last_sample();
     293             : }
     294             : 
     295           0 : MaxCounter::MaxCounter(Clock* clock,
     296             :                        StatsCounterObserver* observer,
     297           0 :                        int64_t process_intervals_ms)
     298             :     : StatsCounter(clock,
     299             :                    process_intervals_ms,
     300             :                    false,  // |include_empty_intervals|
     301           0 :                    observer) {}
     302             : 
     303           0 : void MaxCounter::Add(int sample) {
     304           0 :   StatsCounter::Add(sample);
     305           0 : }
     306             : 
     307           0 : bool MaxCounter::GetMetric(int* metric) const {
     308           0 :   if (samples_->Empty())
     309           0 :     return false;
     310             : 
     311           0 :   *metric = samples_->Max();
     312           0 :   return true;
     313             : }
     314             : 
     315           0 : int MaxCounter::GetValueForEmptyInterval() const {
     316           0 :   RTC_NOTREACHED();
     317           0 :   return 0;
     318             : }
     319             : 
     320           0 : PercentCounter::PercentCounter(Clock* clock, StatsCounterObserver* observer)
     321             :     : StatsCounter(clock,
     322             :                    kDefaultProcessIntervalMs,
     323             :                    false,  // |include_empty_intervals|
     324           0 :                    observer) {}
     325             : 
     326           0 : void PercentCounter::Add(bool sample) {
     327           0 :   StatsCounter::Add(sample ? 1 : 0);
     328           0 : }
     329             : 
     330           0 : bool PercentCounter::GetMetric(int* metric) const {
     331           0 :   int64_t count = samples_->Count();
     332           0 :   if (count == 0)
     333           0 :     return false;
     334             : 
     335           0 :   *metric = (samples_->Sum() * 100 + count / 2) / count;
     336           0 :   return true;
     337             : }
     338             : 
     339           0 : int PercentCounter::GetValueForEmptyInterval() const {
     340           0 :   RTC_NOTREACHED();
     341           0 :   return 0;
     342             : }
     343             : 
     344           0 : PermilleCounter::PermilleCounter(Clock* clock, StatsCounterObserver* observer)
     345             :     : StatsCounter(clock,
     346             :                    kDefaultProcessIntervalMs,
     347             :                    false,  // |include_empty_intervals|
     348           0 :                    observer) {}
     349             : 
     350           0 : void PermilleCounter::Add(bool sample) {
     351           0 :   StatsCounter::Add(sample ? 1 : 0);
     352           0 : }
     353             : 
     354           0 : bool PermilleCounter::GetMetric(int* metric) const {
     355           0 :   int64_t count = samples_->Count();
     356           0 :   if (count == 0)
     357           0 :     return false;
     358             : 
     359           0 :   *metric = (samples_->Sum() * 1000 + count / 2) / count;
     360           0 :   return true;
     361             : }
     362             : 
     363           0 : int PermilleCounter::GetValueForEmptyInterval() const {
     364           0 :   RTC_NOTREACHED();
     365           0 :   return 0;
     366             : }
     367             : 
     368           0 : RateCounter::RateCounter(Clock* clock,
     369             :                          StatsCounterObserver* observer,
     370           0 :                          bool include_empty_intervals)
     371             :     : StatsCounter(clock,
     372             :                    kDefaultProcessIntervalMs,
     373             :                    include_empty_intervals,
     374           0 :                    observer) {}
     375             : 
     376           0 : void RateCounter::Add(int sample) {
     377           0 :   StatsCounter::Add(sample);
     378           0 : }
     379             : 
     380           0 : bool RateCounter::GetMetric(int* metric) const {
     381           0 :   if (samples_->Empty())
     382           0 :     return false;
     383             : 
     384           0 :   *metric = (samples_->Sum() * 1000 + process_intervals_ms_ / 2) /
     385           0 :             process_intervals_ms_;
     386           0 :   return true;
     387             : }
     388             : 
     389           0 : int RateCounter::GetValueForEmptyInterval() const {
     390           0 :   return 0;
     391             : }
     392             : 
     393           0 : RateAccCounter::RateAccCounter(Clock* clock,
     394             :                                StatsCounterObserver* observer,
     395           0 :                                bool include_empty_intervals)
     396             :     : StatsCounter(clock,
     397             :                    kDefaultProcessIntervalMs,
     398             :                    include_empty_intervals,
     399           0 :                    observer) {}
     400             : 
     401           0 : void RateAccCounter::Set(int sample, uint32_t stream_id) {
     402           0 :   StatsCounter::Set(sample, stream_id);
     403           0 : }
     404             : 
     405           0 : bool RateAccCounter::GetMetric(int* metric) const {
     406           0 :   int64_t diff = samples_->Diff();
     407           0 :   if (diff < 0 || (!include_empty_intervals_ && diff == 0))
     408           0 :     return false;
     409             : 
     410           0 :   *metric = (diff * 1000 + process_intervals_ms_ / 2) / process_intervals_ms_;
     411           0 :   return true;
     412             : }
     413             : 
     414           0 : int RateAccCounter::GetValueForEmptyInterval() const {
     415           0 :   return 0;
     416             : }
     417             : 
     418             : }  // namespace webrtc

Generated by: LCOV version 1.13