blob: 71f8f5764df6e2fcc316fc4666490e3c1c378d80 [file] [log] [blame]
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +00001/*
2 * Copyright (c) 2013 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_engine/overuse_frame_detector.h"
12
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000013#include <assert.h>
pbos@webrtc.orga9575702013-08-30 17:16:32 +000014#include <math.h>
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000015
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +000016#include <algorithm>
17#include <list>
asapersson@webrtc.org734a5322014-06-10 06:35:22 +000018#include <map>
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +000019
tommi@webrtc.org7a57f8f2015-02-08 18:27:46 +000020#include "webrtc/base/checks.h"
minyue@webrtc.org74aaf292014-07-16 21:28:26 +000021#include "webrtc/base/exp_filter.h"
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000022#include "webrtc/system_wrappers/interface/clock.h"
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +000023#include "webrtc/system_wrappers/interface/logging.h"
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000024
25namespace webrtc {
26
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000027// TODO(mflodman) Test different values for all of these to trigger correctly,
28// avoid fluctuations etc.
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000029namespace {
pbos@webrtc.orga9575702013-08-30 17:16:32 +000030const int64_t kProcessIntervalMs = 5000;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000031
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +000032// Weight factor to apply to the standard deviation.
33const float kWeightFactor = 0.997f;
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +000034// Weight factor to apply to the average.
35const float kWeightFactorMean = 0.98f;
36
pbos@webrtc.orga9575702013-08-30 17:16:32 +000037// Delay between consecutive rampups. (Used for quick recovery.)
38const int kQuickRampUpDelayMs = 10 * 1000;
39// Delay between rampup attempts. Initially uses standard, scales up to max.
asapersson@webrtc.org23a4d852014-08-13 14:33:49 +000040const int kStandardRampUpDelayMs = 40 * 1000;
asapersson@webrtc.org2881ab12014-06-12 08:46:46 +000041const int kMaxRampUpDelayMs = 240 * 1000;
pbos@webrtc.orga9575702013-08-30 17:16:32 +000042// Expontential back-off factor, to prevent annoying up-down behaviour.
43const double kRampUpBackoffFactor = 2.0;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000044
asapersson@webrtc.orgd9803072014-06-16 14:27:19 +000045// Max number of overuses detected before always applying the rampup delay.
asapersson@webrtc.org23a4d852014-08-13 14:33:49 +000046const int kMaxOverusesBeforeApplyRampupDelay = 4;
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +000047
48// The maximum exponent to use in VCMExpFilter.
49const float kSampleDiffMs = 33.0f;
50const float kMaxExp = 7.0f;
51
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000052} // namespace
53
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +000054// TODO(asapersson): Remove this class. Not used.
Peter Boström4b91bd02015-06-26 06:58:16 +020055Statistics::Statistics(const CpuOveruseOptions& options)
56 : sum_(0.0),
57 count_(0),
58 options_(options),
59 filtered_samples_(new rtc::ExpFilter(kWeightFactorMean)),
60 filtered_variance_(new rtc::ExpFilter(kWeightFactor)) {
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000061 Reset();
62}
63
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +000064void Statistics::Reset() {
65 sum_ = 0.0;
66 count_ = 0;
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000067 filtered_variance_->Reset(kWeightFactor);
68 filtered_variance_->Apply(1.0f, InitialVariance());
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +000069}
70
71void Statistics::AddSample(float sample_ms) {
72 sum_ += sample_ms;
73 ++count_;
74
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000075 if (count_ < static_cast<uint32_t>(options_.min_frame_samples)) {
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +000076 // Initialize filtered samples.
77 filtered_samples_->Reset(kWeightFactorMean);
78 filtered_samples_->Apply(1.0f, InitialMean());
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +000079 return;
80 }
81
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +000082 float exp = sample_ms / kSampleDiffMs;
83 exp = std::min(exp, kMaxExp);
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +000084 filtered_samples_->Apply(exp, sample_ms);
minyue@webrtc.org74aaf292014-07-16 21:28:26 +000085 filtered_variance_->Apply(exp, (sample_ms - filtered_samples_->filtered()) *
86 (sample_ms - filtered_samples_->filtered()));
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +000087}
88
89float Statistics::InitialMean() const {
90 if (count_ == 0)
91 return 0.0;
92 return sum_ / count_;
93}
94
95float Statistics::InitialVariance() const {
96 // Start in between the underuse and overuse threshold.
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +000097 float average_stddev = (options_.low_capture_jitter_threshold_ms +
98 options_.high_capture_jitter_threshold_ms) / 2.0f;
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +000099 return average_stddev * average_stddev;
100}
101
minyue@webrtc.org74aaf292014-07-16 21:28:26 +0000102float Statistics::Mean() const { return filtered_samples_->filtered(); }
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +0000103
104float Statistics::StdDev() const {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +0000105 return sqrt(std::max(filtered_variance_->filtered(), 0.0f));
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +0000106}
107
108uint64_t Statistics::Count() const { return count_; }
109
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000110
111// Class for calculating the average encode time.
112class OveruseFrameDetector::EncodeTimeAvg {
113 public:
114 EncodeTimeAvg()
115 : kWeightFactor(0.5f),
asapersson@webrtc.orgd9803072014-06-16 14:27:19 +0000116 kInitialAvgEncodeTimeMs(5.0f),
minyue@webrtc.org74aaf292014-07-16 21:28:26 +0000117 filtered_encode_time_ms_(new rtc::ExpFilter(kWeightFactor)) {
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000118 filtered_encode_time_ms_->Apply(1.0f, kInitialAvgEncodeTimeMs);
119 }
120 ~EncodeTimeAvg() {}
121
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000122 void AddSample(float encode_time_ms, int64_t diff_last_sample_ms) {
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000123 float exp = diff_last_sample_ms / kSampleDiffMs;
124 exp = std::min(exp, kMaxExp);
125 filtered_encode_time_ms_->Apply(exp, encode_time_ms);
126 }
127
asapersson@webrtc.org2881ab12014-06-12 08:46:46 +0000128 int Value() const {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +0000129 return static_cast<int>(filtered_encode_time_ms_->filtered() + 0.5);
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000130 }
131
132 private:
133 const float kWeightFactor;
asapersson@webrtc.orgd9803072014-06-16 14:27:19 +0000134 const float kInitialAvgEncodeTimeMs;
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000135 rtc::scoped_ptr<rtc::ExpFilter> filtered_encode_time_ms_;
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000136};
137
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000138// Class for calculating the processing usage on the send-side (the average
139// processing time of a frame divided by the average time difference between
140// captured frames).
141class OveruseFrameDetector::SendProcessingUsage {
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000142 public:
Peter Boström4b91bd02015-06-26 06:58:16 +0200143 explicit SendProcessingUsage(const CpuOveruseOptions& options)
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000144 : kWeightFactorFrameDiff(0.998f),
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000145 kWeightFactorProcessing(0.995f),
asapersson@webrtc.orge41dbee2014-05-13 13:45:13 +0000146 kInitialSampleDiffMs(40.0f),
147 kMaxSampleDiffMs(45.0f),
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000148 count_(0),
Peter Boström4b91bd02015-06-26 06:58:16 +0200149 options_(options),
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000150 filtered_processing_ms_(new rtc::ExpFilter(kWeightFactorProcessing)),
minyue@webrtc.org74aaf292014-07-16 21:28:26 +0000151 filtered_frame_diff_ms_(new rtc::ExpFilter(kWeightFactorFrameDiff)) {
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000152 Reset();
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000153 }
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000154 ~SendProcessingUsage() {}
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000155
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000156 void Reset() {
157 count_ = 0;
158 filtered_frame_diff_ms_->Reset(kWeightFactorFrameDiff);
159 filtered_frame_diff_ms_->Apply(1.0f, kInitialSampleDiffMs);
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000160 filtered_processing_ms_->Reset(kWeightFactorProcessing);
161 filtered_processing_ms_->Apply(1.0f, InitialProcessingMs());
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000162 }
163
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000164 void AddCaptureSample(float sample_ms) {
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000165 float exp = sample_ms / kSampleDiffMs;
166 exp = std::min(exp, kMaxExp);
167 filtered_frame_diff_ms_->Apply(exp, sample_ms);
168 }
169
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000170 void AddSample(float processing_ms, int64_t diff_last_sample_ms) {
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000171 ++count_;
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000172 float exp = diff_last_sample_ms / kSampleDiffMs;
173 exp = std::min(exp, kMaxExp);
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000174 filtered_processing_ms_->Apply(exp, processing_ms);
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000175 }
176
asapersson@webrtc.org2881ab12014-06-12 08:46:46 +0000177 int Value() const {
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000178 if (count_ < static_cast<uint32_t>(options_.min_frame_samples)) {
179 return static_cast<int>(InitialUsageInPercent() + 0.5f);
180 }
minyue@webrtc.org74aaf292014-07-16 21:28:26 +0000181 float frame_diff_ms = std::max(filtered_frame_diff_ms_->filtered(), 1.0f);
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000182 frame_diff_ms = std::min(frame_diff_ms, kMaxSampleDiffMs);
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000183 float encode_usage_percent =
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000184 100.0f * filtered_processing_ms_->filtered() / frame_diff_ms;
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000185 return static_cast<int>(encode_usage_percent + 0.5);
186 }
187
asapersson@webrtc.org2881ab12014-06-12 08:46:46 +0000188 private:
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000189 float InitialUsageInPercent() const {
190 // Start in between the underuse and overuse threshold.
191 return (options_.low_encode_usage_threshold_percent +
192 options_.high_encode_usage_threshold_percent) / 2.0f;
193 }
194
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000195 float InitialProcessingMs() const {
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000196 return InitialUsageInPercent() * kInitialSampleDiffMs / 100;
197 }
198
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000199 const float kWeightFactorFrameDiff;
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000200 const float kWeightFactorProcessing;
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000201 const float kInitialSampleDiffMs;
202 const float kMaxSampleDiffMs;
203 uint64_t count_;
Peter Boström4b91bd02015-06-26 06:58:16 +0200204 const CpuOveruseOptions options_;
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000205 rtc::scoped_ptr<rtc::ExpFilter> filtered_processing_ms_;
206 rtc::scoped_ptr<rtc::ExpFilter> filtered_frame_diff_ms_;
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000207};
208
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000209// Class for calculating the processing time of frames.
210class OveruseFrameDetector::FrameQueue {
211 public:
212 FrameQueue() : last_processing_time_ms_(-1) {}
213 ~FrameQueue() {}
214
215 // Called when a frame is captured.
216 // Starts the measuring of the processing time of the frame.
217 void Start(int64_t capture_time, int64_t now) {
218 const size_t kMaxSize = 90; // Allows for processing time of 1.5s at 60fps.
219 if (frame_times_.size() > kMaxSize) {
220 LOG(LS_WARNING) << "Max size reached, removed oldest frame.";
221 frame_times_.erase(frame_times_.begin());
222 }
223 if (frame_times_.find(capture_time) != frame_times_.end()) {
224 // Frame should not exist.
225 assert(false);
226 return;
227 }
228 frame_times_[capture_time] = now;
229 }
230
231 // Called when the processing of a frame has finished.
232 // Returns the processing time of the frame.
233 int End(int64_t capture_time, int64_t now) {
234 std::map<int64_t, int64_t>::iterator it = frame_times_.find(capture_time);
235 if (it == frame_times_.end()) {
236 return -1;
237 }
238 // Remove any old frames up to current.
239 // Old frames have been skipped by the capture process thread.
240 // TODO(asapersson): Consider measuring time from first frame in list.
241 last_processing_time_ms_ = now - (*it).second;
242 frame_times_.erase(frame_times_.begin(), ++it);
243 return last_processing_time_ms_;
244 }
245
246 void Reset() { frame_times_.clear(); }
Peter Boströmae37abb2015-06-18 19:00:34 +0200247 int NumFrames() const { return static_cast<int>(frame_times_.size()); }
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000248 int last_processing_time_ms() const { return last_processing_time_ms_; }
249
250 private:
251 // Captured frames mapped by the capture time.
252 std::map<int64_t, int64_t> frame_times_;
253 int last_processing_time_ms_;
254};
255
256// TODO(asapersson): Remove this class. Not used.
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000257// Class for calculating the capture queue delay change.
258class OveruseFrameDetector::CaptureQueueDelay {
259 public:
260 CaptureQueueDelay()
261 : kWeightFactor(0.5f),
262 delay_ms_(0),
minyue@webrtc.org74aaf292014-07-16 21:28:26 +0000263 filtered_delay_ms_per_s_(new rtc::ExpFilter(kWeightFactor)) {
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000264 filtered_delay_ms_per_s_->Apply(1.0f, 0.0f);
265 }
266 ~CaptureQueueDelay() {}
267
268 void FrameCaptured(int64_t now) {
269 const size_t kMaxSize = 200;
270 if (frames_.size() > kMaxSize) {
271 frames_.pop_front();
272 }
273 frames_.push_back(now);
274 }
275
276 void FrameProcessingStarted(int64_t now) {
277 if (frames_.empty()) {
278 return;
279 }
280 delay_ms_ = now - frames_.front();
281 frames_.pop_front();
282 }
283
284 void CalculateDelayChange(int64_t diff_last_sample_ms) {
285 if (diff_last_sample_ms <= 0) {
286 return;
287 }
288 float exp = static_cast<float>(diff_last_sample_ms) / kProcessIntervalMs;
289 exp = std::min(exp, kMaxExp);
290 filtered_delay_ms_per_s_->Apply(exp,
291 delay_ms_ * 1000.0f / diff_last_sample_ms);
292 ClearFrames();
293 }
294
295 void ClearFrames() {
296 frames_.clear();
297 }
298
299 int delay_ms() const {
300 return delay_ms_;
301 }
302
asapersson@webrtc.org2881ab12014-06-12 08:46:46 +0000303 int Value() const {
minyue@webrtc.org74aaf292014-07-16 21:28:26 +0000304 return static_cast<int>(filtered_delay_ms_per_s_->filtered() + 0.5);
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000305 }
306
307 private:
308 const float kWeightFactor;
309 std::list<int64_t> frames_;
310 int delay_ms_;
kwiberg@webrtc.org00b8f6b2015-02-26 14:34:55 +0000311 rtc::scoped_ptr<rtc::ExpFilter> filtered_delay_ms_per_s_;
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000312};
313
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000314OveruseFrameDetector::OveruseFrameDetector(
315 Clock* clock,
Peter Boström4b91bd02015-06-26 06:58:16 +0200316 const CpuOveruseOptions& options,
317 CpuOveruseObserver* observer,
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000318 CpuOveruseMetricsObserver* metrics_observer)
Peter Boström4b91bd02015-06-26 06:58:16 +0200319 : options_(options),
320 observer_(observer),
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000321 metrics_observer_(metrics_observer),
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000322 clock_(clock),
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000323 next_process_time_(clock_->TimeInMilliseconds()),
asapersson@webrtc.orgb60346e2014-02-17 19:02:15 +0000324 num_process_times_(0),
Peter Boström4b91bd02015-06-26 06:58:16 +0200325 capture_deltas_(options),
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000326 last_capture_time_(0),
327 last_overuse_time_(0),
328 checks_above_threshold_(0),
asapersson@webrtc.orgd9803072014-06-16 14:27:19 +0000329 num_overuse_detections_(0),
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000330 last_rampup_time_(0),
331 in_quick_rampup_(false),
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +0000332 current_rampup_delay_ms_(kStandardRampUpDelayMs),
asapersson@webrtc.orgb24d3352013-11-20 13:51:40 +0000333 num_pixels_(0),
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000334 last_encode_sample_ms_(0),
335 encode_time_(new EncodeTimeAvg()),
Peter Boström4b91bd02015-06-26 06:58:16 +0200336 usage_(new SendProcessingUsage(options)),
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000337 frame_queue_(new FrameQueue()),
338 last_sample_time_ms_(0),
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000339 capture_queue_delay_(new CaptureQueueDelay()) {
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000340 DCHECK(metrics_observer != nullptr);
Peter Boström4b91bd02015-06-26 06:58:16 +0200341 // Make sure stats are initially up-to-date. This simplifies unit testing
342 // since we don't have to trigger an update using one of the methods which
343 // would also alter the overuse state.
344 UpdateCpuOveruseMetrics();
tommi@webrtc.org7a57f8f2015-02-08 18:27:46 +0000345 processing_thread_.DetachFromThread();
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000346}
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000347
348OveruseFrameDetector::~OveruseFrameDetector() {
349}
350
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000351int OveruseFrameDetector::CaptureQueueDelayMsPerS() const {
tommi@webrtc.org7a57f8f2015-02-08 18:27:46 +0000352 rtc::CritScope cs(&crit_);
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000353 return capture_queue_delay_->delay_ms();
354}
355
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000356int OveruseFrameDetector::LastProcessingTimeMs() const {
tommi@webrtc.org7a57f8f2015-02-08 18:27:46 +0000357 rtc::CritScope cs(&crit_);
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000358 return frame_queue_->last_processing_time_ms();
359}
360
361int OveruseFrameDetector::FramesInQueue() const {
tommi@webrtc.org7a57f8f2015-02-08 18:27:46 +0000362 rtc::CritScope cs(&crit_);
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000363 return frame_queue_->NumFrames();
364}
365
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000366void OveruseFrameDetector::UpdateCpuOveruseMetrics() {
367 metrics_.capture_jitter_ms = static_cast<int>(capture_deltas_.StdDev() + 0.5);
368 metrics_.avg_encode_time_ms = encode_time_->Value();
369 metrics_.encode_usage_percent = usage_->Value();
370 metrics_.capture_queue_delay_ms_per_s = capture_queue_delay_->Value();
371
372 metrics_observer_->CpuOveruseMetricsUpdated(metrics_);
asapersson@webrtc.orgab6bf4f2014-05-27 07:43:15 +0000373}
374
pkasting@chromium.org0b1534c2014-12-15 22:09:40 +0000375int64_t OveruseFrameDetector::TimeUntilNextProcess() {
tommi@webrtc.org7a57f8f2015-02-08 18:27:46 +0000376 DCHECK(processing_thread_.CalledOnValidThread());
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000377 return next_process_time_ - clock_->TimeInMilliseconds();
378}
379
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000380bool OveruseFrameDetector::FrameSizeChanged(int num_pixels) const {
381 if (num_pixels != num_pixels_) {
382 return true;
383 }
384 return false;
385}
386
387bool OveruseFrameDetector::FrameTimeoutDetected(int64_t now) const {
asapersson@webrtc.orgb60346e2014-02-17 19:02:15 +0000388 if (last_capture_time_ == 0) {
389 return false;
390 }
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000391 return (now - last_capture_time_) > options_.frame_timeout_interval_ms;
392}
393
394void OveruseFrameDetector::ResetAll(int num_pixels) {
395 num_pixels_ = num_pixels;
396 capture_deltas_.Reset();
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000397 usage_->Reset();
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000398 frame_queue_->Reset();
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000399 capture_queue_delay_->ClearFrames();
400 last_capture_time_ = 0;
401 num_process_times_ = 0;
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000402 UpdateCpuOveruseMetrics();
asapersson@webrtc.orgb60346e2014-02-17 19:02:15 +0000403}
404
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000405void OveruseFrameDetector::FrameCaptured(int width,
406 int height,
407 int64_t capture_time_ms) {
tommi@webrtc.org7a57f8f2015-02-08 18:27:46 +0000408 rtc::CritScope cs(&crit_);
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +0000409
asapersson@webrtc.orgb60346e2014-02-17 19:02:15 +0000410 int64_t now = clock_->TimeInMilliseconds();
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000411 if (FrameSizeChanged(width * height) || FrameTimeoutDetected(now)) {
412 ResetAll(width * height);
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +0000413 }
414
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000415 if (last_capture_time_ != 0) {
asapersson@webrtc.orgb60346e2014-02-17 19:02:15 +0000416 capture_deltas_.AddSample(now - last_capture_time_);
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000417 usage_->AddCaptureSample(now - last_capture_time_);
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000418 }
asapersson@webrtc.orgb60346e2014-02-17 19:02:15 +0000419 last_capture_time_ = now;
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000420
asapersson@webrtc.orgb60346e2014-02-17 19:02:15 +0000421 capture_queue_delay_->FrameCaptured(now);
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000422
423 if (options_.enable_extended_processing_usage) {
424 frame_queue_->Start(capture_time_ms, now);
425 }
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000426 UpdateCpuOveruseMetrics();
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000427}
428
429void OveruseFrameDetector::FrameProcessingStarted() {
tommi@webrtc.org7a57f8f2015-02-08 18:27:46 +0000430 rtc::CritScope cs(&crit_);
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000431 capture_queue_delay_->FrameProcessingStarted(clock_->TimeInMilliseconds());
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000432}
433
asapersson@webrtc.orgc7ff8f92013-11-26 11:12:33 +0000434void OveruseFrameDetector::FrameEncoded(int encode_time_ms) {
tommi@webrtc.org7a57f8f2015-02-08 18:27:46 +0000435 rtc::CritScope cs(&crit_);
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000436 int64_t now = clock_->TimeInMilliseconds();
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000437 if (last_encode_sample_ms_ != 0) {
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000438 int64_t diff_ms = now - last_encode_sample_ms_;
439 encode_time_->AddSample(encode_time_ms, diff_ms);
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000440 }
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000441 last_encode_sample_ms_ = now;
442
443 if (!options_.enable_extended_processing_usage) {
444 AddProcessingTime(encode_time_ms);
445 }
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000446 UpdateCpuOveruseMetrics();
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000447}
448
449void OveruseFrameDetector::FrameSent(int64_t capture_time_ms) {
tommi@webrtc.org7a57f8f2015-02-08 18:27:46 +0000450 rtc::CritScope cs(&crit_);
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000451 if (!options_.enable_extended_processing_usage) {
452 return;
453 }
454 int delay_ms = frame_queue_->End(capture_time_ms,
455 clock_->TimeInMilliseconds());
456 if (delay_ms > 0) {
457 AddProcessingTime(delay_ms);
458 }
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000459 UpdateCpuOveruseMetrics();
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000460}
461
462void OveruseFrameDetector::AddProcessingTime(int elapsed_ms) {
463 int64_t now = clock_->TimeInMilliseconds();
464 if (last_sample_time_ms_ != 0) {
465 int64_t diff_ms = now - last_sample_time_ms_;
466 usage_->AddSample(elapsed_ms, diff_ms);
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000467 }
468 last_sample_time_ms_ = now;
asapersson@webrtc.orgc7ff8f92013-11-26 11:12:33 +0000469}
470
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000471int32_t OveruseFrameDetector::Process() {
tommi@webrtc.org7a57f8f2015-02-08 18:27:46 +0000472 DCHECK(processing_thread_.CalledOnValidThread());
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000473
mflodman@webrtc.org6879c8a2013-07-23 11:35:00 +0000474 int64_t now = clock_->TimeInMilliseconds();
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000475
476 // Used to protect against Process() being called too often.
477 if (now < next_process_time_)
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000478 return 0;
479
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000480 int64_t diff_ms = now - next_process_time_ + kProcessIntervalMs;
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000481 next_process_time_ = now + kProcessIntervalMs;
tommi@webrtc.org7a57f8f2015-02-08 18:27:46 +0000482
483 rtc::CritScope cs(&crit_);
asapersson@webrtc.orgb60346e2014-02-17 19:02:15 +0000484 ++num_process_times_;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000485
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000486 capture_queue_delay_->CalculateDelayChange(diff_ms);
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000487 UpdateCpuOveruseMetrics();
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000488
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000489 if (num_process_times_ <= options_.min_process_count) {
asapersson@webrtc.orgb60346e2014-02-17 19:02:15 +0000490 return 0;
491 }
492
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000493 if (IsOverusing()) {
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000494 // If the last thing we did was going up, and now have to back down, we need
495 // to check if this peak was short. If so we should back off to avoid going
496 // back and forth between this load, the system doesn't seem to handle it.
497 bool check_for_backoff = last_rampup_time_ > last_overuse_time_;
498 if (check_for_backoff) {
asapersson@webrtc.orgd9803072014-06-16 14:27:19 +0000499 if (now - last_rampup_time_ < kStandardRampUpDelayMs ||
500 num_overuse_detections_ > kMaxOverusesBeforeApplyRampupDelay) {
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000501 // Going up was not ok for very long, back off.
502 current_rampup_delay_ms_ *= kRampUpBackoffFactor;
503 if (current_rampup_delay_ms_ > kMaxRampUpDelayMs)
504 current_rampup_delay_ms_ = kMaxRampUpDelayMs;
505 } else {
506 // Not currently backing off, reset rampup delay.
507 current_rampup_delay_ms_ = kStandardRampUpDelayMs;
508 }
509 }
510
511 last_overuse_time_ = now;
512 in_quick_rampup_ = false;
513 checks_above_threshold_ = 0;
asapersson@webrtc.orgd9803072014-06-16 14:27:19 +0000514 ++num_overuse_detections_;
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000515
516 if (observer_ != NULL)
517 observer_->OveruseDetected();
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000518 } else if (IsUnderusing(now)) {
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000519 last_rampup_time_ = now;
520 in_quick_rampup_ = true;
521
522 if (observer_ != NULL)
523 observer_->NormalUsage();
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000524 }
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000525
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000526 int rampup_delay =
527 in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_;
asapersson@webrtc.orgd9803072014-06-16 14:27:19 +0000528 LOG(LS_VERBOSE) << " Frame stats: capture avg: " << capture_deltas_.Mean()
529 << " capture stddev " << capture_deltas_.StdDev()
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000530 << " encode usage " << usage_->Value()
asapersson@webrtc.orgd9803072014-06-16 14:27:19 +0000531 << " overuse detections " << num_overuse_detections_
532 << " rampup delay " << rampup_delay;
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000533
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +0000534 return 0;
535}
536
537bool OveruseFrameDetector::IsOverusing() {
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000538 bool overusing = false;
539 if (options_.enable_capture_jitter_method) {
540 overusing = capture_deltas_.StdDev() >=
541 options_.high_capture_jitter_threshold_ms;
542 } else if (options_.enable_encode_usage_method) {
asapersson@webrtc.org7f105132014-10-29 10:05:21 +0000543 overusing = usage_->Value() >= options_.high_encode_usage_threshold_percent;
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000544 }
545
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000546 if (overusing) {
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000547 ++checks_above_threshold_;
548 } else {
549 checks_above_threshold_ = 0;
550 }
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000551 return checks_above_threshold_ >= options_.high_threshold_consecutive_count;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000552}
553
554bool OveruseFrameDetector::IsUnderusing(int64_t time_now) {
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000555 int delay = in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_;
556 if (time_now < last_rampup_time_ + delay)
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000557 return false;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000558
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000559 bool underusing = false;
560 if (options_.enable_capture_jitter_method) {
561 underusing = capture_deltas_.StdDev() <
562 options_.low_capture_jitter_threshold_ms;
563 } else if (options_.enable_encode_usage_method) {
asapersson@webrtc.org7f105132014-10-29 10:05:21 +0000564 underusing = usage_->Value() < options_.low_encode_usage_threshold_percent;
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000565 }
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000566 return underusing;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000567}
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000568} // namespace webrtc