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 |