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