blob: 8519ce7804a005361f7ac01b59a1e268efd08e2f [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "video/overuse_frame_detector.h"
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000012
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>
sprangc5d62e22017-04-02 23:53:04 -070019#include <string>
20#include <utility>
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +000021
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "api/video/video_frame.h"
23#include "common_video/include/frame_callback.h"
24#include "rtc_base/checks.h"
25#include "rtc_base/logging.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020026#include "rtc_base/timeutils.h"
27#include "system_wrappers/include/field_trial.h"
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000028
pbosa1025072016-05-14 03:04:19 -070029#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
torbjorng448468d2016-02-10 08:11:57 -080030#include <mach/mach.h>
pbosa1025072016-05-14 03:04:19 -070031#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
torbjorng448468d2016-02-10 08:11:57 -080032
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000033namespace webrtc {
34
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000035namespace {
perkjd52063f2016-09-07 06:32:18 -070036const int64_t kCheckForOveruseIntervalMs = 5000;
37const int64_t kTimeToFirstCheckForOveruseMs = 100;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000038
pbos@webrtc.orga9575702013-08-30 17:16:32 +000039// Delay between consecutive rampups. (Used for quick recovery.)
40const int kQuickRampUpDelayMs = 10 * 1000;
41// Delay between rampup attempts. Initially uses standard, scales up to max.
asapersson@webrtc.org23a4d852014-08-13 14:33:49 +000042const int kStandardRampUpDelayMs = 40 * 1000;
asapersson@webrtc.org2881ab12014-06-12 08:46:46 +000043const int kMaxRampUpDelayMs = 240 * 1000;
pbos@webrtc.orga9575702013-08-30 17:16:32 +000044// Expontential back-off factor, to prevent annoying up-down behaviour.
45const double kRampUpBackoffFactor = 2.0;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000046
asapersson@webrtc.orgd9803072014-06-16 14:27:19 +000047// Max number of overuses detected before always applying the rampup delay.
asapersson@webrtc.org23a4d852014-08-13 14:33:49 +000048const int kMaxOverusesBeforeApplyRampupDelay = 4;
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +000049
sprangb1ca0732017-02-01 08:38:12 -080050const auto kScaleReasonCpu = AdaptationObserverInterface::AdaptReason::kCpu;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000051} // namespace
52
torbjorng448468d2016-02-10 08:11:57 -080053CpuOveruseOptions::CpuOveruseOptions()
54 : high_encode_usage_threshold_percent(85),
55 frame_timeout_interval_ms(1500),
torbjorng448468d2016-02-10 08:11:57 -080056 min_process_count(3),
Niels Möllereee7ced2017-12-01 11:25:01 +010057 high_threshold_consecutive_count(2),
58 filter_time_ms(5000) {
pbosa1025072016-05-14 03:04:19 -070059#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
torbjorng448468d2016-02-10 08:11:57 -080060 // This is proof-of-concept code for letting the physical core count affect
61 // the interval into which we attempt to scale. For now, the code is Mac OS
62 // specific, since that's the platform were we saw most problems.
63 // TODO(torbjorng): Enhance SystemInfo to return this metric.
64
65 mach_port_t mach_host = mach_host_self();
66 host_basic_info hbi = {};
67 mach_msg_type_number_t info_count = HOST_BASIC_INFO_COUNT;
68 kern_return_t kr =
69 host_info(mach_host, HOST_BASIC_INFO, reinterpret_cast<host_info_t>(&hbi),
70 &info_count);
71 mach_port_deallocate(mach_task_self(), mach_host);
72
73 int n_physical_cores;
74 if (kr != KERN_SUCCESS) {
75 // If we couldn't get # of physical CPUs, don't panic. Assume we have 1.
76 n_physical_cores = 1;
Mirko Bonadei675513b2017-11-09 11:09:25 +010077 RTC_LOG(LS_ERROR)
78 << "Failed to determine number of physical cores, assuming 1";
torbjorng448468d2016-02-10 08:11:57 -080079 } else {
80 n_physical_cores = hbi.physical_cpu;
Mirko Bonadei675513b2017-11-09 11:09:25 +010081 RTC_LOG(LS_INFO) << "Number of physical cores:" << n_physical_cores;
torbjorng448468d2016-02-10 08:11:57 -080082 }
83
84 // Change init list default for few core systems. The assumption here is that
85 // encoding, which we measure here, takes about 1/4 of the processing of a
86 // two-way call. This is roughly true for x86 using both vp8 and vp9 without
87 // hardware encoding. Since we don't affect the incoming stream here, we only
88 // control about 1/2 of the total processing needs, but this is not taken into
89 // account.
90 if (n_physical_cores == 1)
91 high_encode_usage_threshold_percent = 20; // Roughly 1/4 of 100%.
92 else if (n_physical_cores == 2)
93 high_encode_usage_threshold_percent = 40; // Roughly 1/4 of 200%.
pbosa1025072016-05-14 03:04:19 -070094#endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
torbjorng448468d2016-02-10 08:11:57 -080095
torbjorng448468d2016-02-10 08:11:57 -080096 // Note that we make the interval 2x+epsilon wide, since libyuv scaling steps
97 // are close to that (when squared). This wide interval makes sure that
98 // scaling up or down does not jump all the way across the interval.
99 low_encode_usage_threshold_percent =
100 (high_encode_usage_threshold_percent - 1) / 2;
101}
102
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000103// Class for calculating the processing usage on the send-side (the average
104// processing time of a frame divided by the average time difference between
105// captured frames).
106class OveruseFrameDetector::SendProcessingUsage {
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000107 public:
Peter Boström4b91bd02015-06-26 06:58:16 +0200108 explicit SendProcessingUsage(const CpuOveruseOptions& options)
Niels Möllereee7ced2017-12-01 11:25:01 +0100109 : options_(options) {
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000110 Reset();
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000111 }
sprangc5d62e22017-04-02 23:53:04 -0700112 virtual ~SendProcessingUsage() {}
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000113
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000114 void Reset() {
Niels Möllereee7ced2017-12-01 11:25:01 +0100115 // Start in between the underuse and overuse threshold.
116 load_estimate_ = (options_.low_encode_usage_threshold_percent +
117 options_.high_encode_usage_threshold_percent) /
118 200.0;
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000119 }
120
Niels Möllereee7ced2017-12-01 11:25:01 +0100121 void AddSample(double encode_time, double diff_time) {
122 RTC_CHECK_GE(diff_time, 0.0);
sprangfda496a2017-06-15 04:21:07 -0700123
Niels Möllereee7ced2017-12-01 11:25:01 +0100124 // Use the filter update
125 //
126 // load <-- x/d (1-exp (-d/T)) + exp (-d/T) load
127 //
128 // where we must take care for small d, using the proper limit
129 // (1 - exp(-d/tau)) / d = 1/tau - d/2tau^2 + O(d^2)
130 double tau = (1e-3 * options_.filter_time_ms);
131 double e = diff_time / tau;
132 double c;
133 if (e < 0.0001) {
134 c = (1 - e / 2) / tau;
135 } else {
136 c = -expm1(-e) / diff_time;
asapersson@webrtc.orgce12f1f2014-03-24 21:59:16 +0000137 }
Niels Möllereee7ced2017-12-01 11:25:01 +0100138 load_estimate_ = c * encode_time + exp(-e) * load_estimate_;
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000139 }
140
Niels Möllereee7ced2017-12-01 11:25:01 +0100141 virtual int Value() { return static_cast<int>(100.0 * load_estimate_ + 0.5); }
142
asapersson@webrtc.org2881ab12014-06-12 08:46:46 +0000143 private:
Peter Boström4b91bd02015-06-26 06:58:16 +0200144 const CpuOveruseOptions options_;
Niels Möllereee7ced2017-12-01 11:25:01 +0100145 double load_estimate_;
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000146};
147
sprangc5d62e22017-04-02 23:53:04 -0700148// Class used for manual testing of overuse, enabled via field trial flag.
149class OveruseFrameDetector::OverdoseInjector
150 : public OveruseFrameDetector::SendProcessingUsage {
151 public:
152 OverdoseInjector(const CpuOveruseOptions& options,
153 int64_t normal_period_ms,
154 int64_t overuse_period_ms,
155 int64_t underuse_period_ms)
156 : OveruseFrameDetector::SendProcessingUsage(options),
157 normal_period_ms_(normal_period_ms),
158 overuse_period_ms_(overuse_period_ms),
159 underuse_period_ms_(underuse_period_ms),
160 state_(State::kNormal),
161 last_toggling_ms_(-1) {
162 RTC_DCHECK_GT(overuse_period_ms, 0);
163 RTC_DCHECK_GT(normal_period_ms, 0);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100164 RTC_LOG(LS_INFO) << "Simulating overuse with intervals " << normal_period_ms
165 << "ms normal mode, " << overuse_period_ms
166 << "ms overuse mode.";
sprangc5d62e22017-04-02 23:53:04 -0700167 }
168
169 ~OverdoseInjector() override {}
170
171 int Value() override {
172 int64_t now_ms = rtc::TimeMillis();
173 if (last_toggling_ms_ == -1) {
174 last_toggling_ms_ = now_ms;
Niels Möllereee7ced2017-12-01 11:25:01 +0100175
sprangc5d62e22017-04-02 23:53:04 -0700176 } else {
177 switch (state_) {
178 case State::kNormal:
179 if (now_ms > last_toggling_ms_ + normal_period_ms_) {
180 state_ = State::kOveruse;
181 last_toggling_ms_ = now_ms;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100182 RTC_LOG(LS_INFO) << "Simulating CPU overuse.";
sprangc5d62e22017-04-02 23:53:04 -0700183 }
184 break;
185 case State::kOveruse:
186 if (now_ms > last_toggling_ms_ + overuse_period_ms_) {
187 state_ = State::kUnderuse;
188 last_toggling_ms_ = now_ms;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100189 RTC_LOG(LS_INFO) << "Simulating CPU underuse.";
sprangc5d62e22017-04-02 23:53:04 -0700190 }
191 break;
192 case State::kUnderuse:
193 if (now_ms > last_toggling_ms_ + underuse_period_ms_) {
194 state_ = State::kNormal;
195 last_toggling_ms_ = now_ms;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100196 RTC_LOG(LS_INFO) << "Actual CPU overuse measurements in effect.";
sprangc5d62e22017-04-02 23:53:04 -0700197 }
198 break;
199 }
200 }
201
202 rtc::Optional<int> overried_usage_value;
203 switch (state_) {
204 case State::kNormal:
205 break;
206 case State::kOveruse:
207 overried_usage_value.emplace(250);
208 break;
209 case State::kUnderuse:
210 overried_usage_value.emplace(5);
211 break;
212 }
sprangc5d62e22017-04-02 23:53:04 -0700213 return overried_usage_value.value_or(SendProcessingUsage::Value());
214 }
215
216 private:
217 const int64_t normal_period_ms_;
218 const int64_t overuse_period_ms_;
219 const int64_t underuse_period_ms_;
220 enum class State { kNormal, kOveruse, kUnderuse } state_;
221 int64_t last_toggling_ms_;
222};
223
224std::unique_ptr<OveruseFrameDetector::SendProcessingUsage>
225OveruseFrameDetector::CreateSendProcessingUsage(
226 const CpuOveruseOptions& options) {
227 std::unique_ptr<SendProcessingUsage> instance;
228 std::string toggling_interval =
229 field_trial::FindFullName("WebRTC-ForceSimulatedOveruseIntervalMs");
230 if (!toggling_interval.empty()) {
231 int normal_period_ms = 0;
232 int overuse_period_ms = 0;
233 int underuse_period_ms = 0;
234 if (sscanf(toggling_interval.c_str(), "%d-%d-%d", &normal_period_ms,
235 &overuse_period_ms, &underuse_period_ms) == 3) {
236 if (normal_period_ms > 0 && overuse_period_ms > 0 &&
237 underuse_period_ms > 0) {
238 instance.reset(new OverdoseInjector(
239 options, normal_period_ms, overuse_period_ms, underuse_period_ms));
240 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100241 RTC_LOG(LS_WARNING)
sprangc5d62e22017-04-02 23:53:04 -0700242 << "Invalid (non-positive) normal/overuse/underuse periods: "
243 << normal_period_ms << " / " << overuse_period_ms << " / "
244 << underuse_period_ms;
245 }
246 } else {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100247 RTC_LOG(LS_WARNING) << "Malformed toggling interval: "
248 << toggling_interval;
sprangc5d62e22017-04-02 23:53:04 -0700249 }
250 }
251
252 if (!instance) {
253 // No valid overuse simulation parameters set, use normal usage class.
254 instance.reset(new SendProcessingUsage(options));
255 }
256
257 return instance;
258}
259
perkjd52063f2016-09-07 06:32:18 -0700260class OveruseFrameDetector::CheckOveruseTask : public rtc::QueuedTask {
261 public:
262 explicit CheckOveruseTask(OveruseFrameDetector* overuse_detector)
263 : overuse_detector_(overuse_detector) {
264 rtc::TaskQueue::Current()->PostDelayedTask(
265 std::unique_ptr<rtc::QueuedTask>(this), kTimeToFirstCheckForOveruseMs);
266 }
267
268 void Stop() {
269 RTC_CHECK(task_checker_.CalledSequentially());
270 overuse_detector_ = nullptr;
271 }
272
273 private:
274 bool Run() override {
275 RTC_CHECK(task_checker_.CalledSequentially());
276 if (!overuse_detector_)
277 return true; // This will make the task queue delete this task.
278 overuse_detector_->CheckForOveruse();
279
280 rtc::TaskQueue::Current()->PostDelayedTask(
281 std::unique_ptr<rtc::QueuedTask>(this), kCheckForOveruseIntervalMs);
282 // Return false to prevent this task from being deleted. Ownership has been
283 // transferred to the task queue when PostDelayedTask was called.
284 return false;
285 }
286 rtc::SequencedTaskChecker task_checker_;
287 OveruseFrameDetector* overuse_detector_;
288};
289
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000290OveruseFrameDetector::OveruseFrameDetector(
Peter Boström4b91bd02015-06-26 06:58:16 +0200291 const CpuOveruseOptions& options,
sprangb1ca0732017-02-01 08:38:12 -0800292 AdaptationObserverInterface* observer,
Peter Boströme4499152016-02-05 11:13:28 +0100293 EncodedFrameObserver* encoder_timing,
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000294 CpuOveruseMetricsObserver* metrics_observer)
perkjd52063f2016-09-07 06:32:18 -0700295 : check_overuse_task_(nullptr),
296 options_(options),
Peter Boström4b91bd02015-06-26 06:58:16 +0200297 observer_(observer),
Peter Boströme4499152016-02-05 11:13:28 +0100298 encoder_timing_(encoder_timing),
pbos@webrtc.org3e6e2712015-02-26 12:19:31 +0000299 metrics_observer_(metrics_observer),
asapersson@webrtc.orgb60346e2014-02-17 19:02:15 +0000300 num_process_times_(0),
nissee0e3bdf2017-01-18 02:16:20 -0800301 // TODO(nisse): Use rtc::Optional
302 last_capture_time_us_(-1),
303 last_processed_capture_time_us_(-1),
asapersson74d85e12015-09-24 00:53:32 -0700304 num_pixels_(0),
Peter Boströme4499152016-02-05 11:13:28 +0100305 last_overuse_time_ms_(-1),
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000306 checks_above_threshold_(0),
asapersson@webrtc.orgd9803072014-06-16 14:27:19 +0000307 num_overuse_detections_(0),
Peter Boströme4499152016-02-05 11:13:28 +0100308 last_rampup_time_ms_(-1),
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000309 in_quick_rampup_(false),
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +0000310 current_rampup_delay_ms_(kStandardRampUpDelayMs),
sprangc5d62e22017-04-02 23:53:04 -0700311 usage_(CreateSendProcessingUsage(options)) {
perkjd52063f2016-09-07 06:32:18 -0700312 task_checker_.Detach();
asapersson@webrtc.org9e5b0342013-12-04 13:47:44 +0000313}
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000314
315OveruseFrameDetector::~OveruseFrameDetector() {
perkjd52063f2016-09-07 06:32:18 -0700316 RTC_DCHECK(!check_overuse_task_) << "StopCheckForOverUse must be called.";
317}
318
319void OveruseFrameDetector::StartCheckForOveruse() {
320 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
321 RTC_DCHECK(!check_overuse_task_);
322 check_overuse_task_ = new CheckOveruseTask(this);
323}
324void OveruseFrameDetector::StopCheckForOveruse() {
325 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
326 check_overuse_task_->Stop();
327 check_overuse_task_ = nullptr;
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000328}
329
Peter Boströme4499152016-02-05 11:13:28 +0100330void OveruseFrameDetector::EncodedFrameTimeMeasured(int encode_duration_ms) {
perkjd52063f2016-09-07 06:32:18 -0700331 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
Peter Boströme4499152016-02-05 11:13:28 +0100332 if (!metrics_)
333 metrics_ = rtc::Optional<CpuOveruseMetrics>(CpuOveruseMetrics());
334 metrics_->encode_usage_percent = usage_->Value();
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000335
Peter Boströme4499152016-02-05 11:13:28 +0100336 metrics_observer_->OnEncodedFrameTimeMeasured(encode_duration_ms, *metrics_);
asapersson@webrtc.orgab6bf4f2014-05-27 07:43:15 +0000337}
338
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000339bool OveruseFrameDetector::FrameSizeChanged(int num_pixels) const {
perkjd52063f2016-09-07 06:32:18 -0700340 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000341 if (num_pixels != num_pixels_) {
342 return true;
343 }
344 return false;
345}
346
nissee0e3bdf2017-01-18 02:16:20 -0800347bool OveruseFrameDetector::FrameTimeoutDetected(int64_t now_us) const {
perkjd52063f2016-09-07 06:32:18 -0700348 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
nissee0e3bdf2017-01-18 02:16:20 -0800349 if (last_capture_time_us_ == -1)
asapersson@webrtc.orgb60346e2014-02-17 19:02:15 +0000350 return false;
nissee0e3bdf2017-01-18 02:16:20 -0800351 return (now_us - last_capture_time_us_) >
352 options_.frame_timeout_interval_ms * rtc::kNumMicrosecsPerMillisec;
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000353}
354
Niels Möllereee7ced2017-12-01 11:25:01 +0100355void OveruseFrameDetector::ResetAll() {
perkjd52063f2016-09-07 06:32:18 -0700356 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000357 usage_->Reset();
nissee0e3bdf2017-01-18 02:16:20 -0800358 last_capture_time_us_ = -1;
359 last_processed_capture_time_us_ = -1;
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000360 num_process_times_ = 0;
Peter Boströme4499152016-02-05 11:13:28 +0100361 metrics_ = rtc::Optional<CpuOveruseMetrics>();
sprangfda496a2017-06-15 04:21:07 -0700362}
363
Niels Möllereee7ced2017-12-01 11:25:01 +0100364void OveruseFrameDetector::FrameCaptured(int width, int height) {
perkjd52063f2016-09-07 06:32:18 -0700365 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +0000366
Niels Möllereee7ced2017-12-01 11:25:01 +0100367 if (FrameSizeChanged(width * height)) {
368 ResetAll();
369 num_pixels_ = width * height;
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +0000370 }
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000371}
372
Niels Möllereee7ced2017-12-01 11:25:01 +0100373void OveruseFrameDetector::FrameEncoded(int64_t capture_time_us,
374 int64_t encode_duration_us) {
perkjd52063f2016-09-07 06:32:18 -0700375 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
Niels Möllereee7ced2017-12-01 11:25:01 +0100376 if (FrameTimeoutDetected(capture_time_us)) {
377 ResetAll();
378 } else if (last_capture_time_us_ != -1) {
379 usage_->AddSample(1e-6 * encode_duration_us,
380 1e-6 * (capture_time_us - last_capture_time_us_));
asapersson@webrtc.org9aed0022014-10-16 06:57:12 +0000381 }
Niels Möllereee7ced2017-12-01 11:25:01 +0100382 last_capture_time_us_ = capture_time_us;
383 EncodedFrameTimeMeasured(encode_duration_us / rtc::kNumMicrosecsPerMillisec);
384
385 if (encoder_timing_) {
386 // TODO(nisse): Update encoder_timing_ to also use us units.
387 encoder_timing_->OnEncodeTiming(
388 capture_time_us / rtc::kNumMicrosecsPerMillisec,
389 encode_duration_us / rtc::kNumMicrosecsPerMillisec);
Peter Boströme4499152016-02-05 11:13:28 +0100390 }
asapersson@webrtc.orgc7ff8f92013-11-26 11:12:33 +0000391}
392
perkjd52063f2016-09-07 06:32:18 -0700393void OveruseFrameDetector::CheckForOveruse() {
394 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
395 ++num_process_times_;
396 if (num_process_times_ <= options_.min_process_count || !metrics_)
397 return;
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000398
nissee0e3bdf2017-01-18 02:16:20 -0800399 int64_t now_ms = rtc::TimeMillis();
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000400
perkjd52063f2016-09-07 06:32:18 -0700401 if (IsOverusing(*metrics_)) {
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000402 // If the last thing we did was going up, and now have to back down, we need
403 // to check if this peak was short. If so we should back off to avoid going
404 // back and forth between this load, the system doesn't seem to handle it.
Peter Boströme4499152016-02-05 11:13:28 +0100405 bool check_for_backoff = last_rampup_time_ms_ > last_overuse_time_ms_;
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000406 if (check_for_backoff) {
nissee0e3bdf2017-01-18 02:16:20 -0800407 if (now_ms - last_rampup_time_ms_ < kStandardRampUpDelayMs ||
asapersson@webrtc.orgd9803072014-06-16 14:27:19 +0000408 num_overuse_detections_ > kMaxOverusesBeforeApplyRampupDelay) {
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000409 // Going up was not ok for very long, back off.
410 current_rampup_delay_ms_ *= kRampUpBackoffFactor;
411 if (current_rampup_delay_ms_ > kMaxRampUpDelayMs)
412 current_rampup_delay_ms_ = kMaxRampUpDelayMs;
413 } else {
414 // Not currently backing off, reset rampup delay.
415 current_rampup_delay_ms_ = kStandardRampUpDelayMs;
416 }
417 }
418
nissee0e3bdf2017-01-18 02:16:20 -0800419 last_overuse_time_ms_ = now_ms;
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000420 in_quick_rampup_ = false;
421 checks_above_threshold_ = 0;
asapersson@webrtc.orgd9803072014-06-16 14:27:19 +0000422 ++num_overuse_detections_;
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000423
Peter Boström74f6e9e2016-04-04 17:56:10 +0200424 if (observer_)
sprangb1ca0732017-02-01 08:38:12 -0800425 observer_->AdaptDown(kScaleReasonCpu);
nissee0e3bdf2017-01-18 02:16:20 -0800426 } else if (IsUnderusing(*metrics_, now_ms)) {
427 last_rampup_time_ms_ = now_ms;
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000428 in_quick_rampup_ = true;
429
Peter Boström74f6e9e2016-04-04 17:56:10 +0200430 if (observer_)
sprangb1ca0732017-02-01 08:38:12 -0800431 observer_->AdaptUp(kScaleReasonCpu);
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000432 }
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000433
mflodman@webrtc.org5574dac2014-04-07 10:56:31 +0000434 int rampup_delay =
435 in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_;
asapersson74d85e12015-09-24 00:53:32 -0700436
Mirko Bonadei675513b2017-11-09 11:09:25 +0100437 RTC_LOG(LS_VERBOSE) << " Frame stats: "
438 << " encode usage " << metrics_->encode_usage_percent
439 << " overuse detections " << num_overuse_detections_
440 << " rampup delay " << rampup_delay;
asapersson@webrtc.orge2af6222013-09-23 20:05:39 +0000441}
442
asapersson74d85e12015-09-24 00:53:32 -0700443bool OveruseFrameDetector::IsOverusing(const CpuOveruseMetrics& metrics) {
perkjd52063f2016-09-07 06:32:18 -0700444 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
sprangc5d62e22017-04-02 23:53:04 -0700445
Peter Boström01f364e2016-01-07 16:38:25 +0100446 if (metrics.encode_usage_percent >=
447 options_.high_encode_usage_threshold_percent) {
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000448 ++checks_above_threshold_;
449 } else {
450 checks_above_threshold_ = 0;
451 }
asapersson@webrtc.org8a8c3ef2014-03-20 13:15:01 +0000452 return checks_above_threshold_ >= options_.high_threshold_consecutive_count;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000453}
454
asapersson74d85e12015-09-24 00:53:32 -0700455bool OveruseFrameDetector::IsUnderusing(const CpuOveruseMetrics& metrics,
456 int64_t time_now) {
perkjd52063f2016-09-07 06:32:18 -0700457 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000458 int delay = in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_;
Peter Boströme4499152016-02-05 11:13:28 +0100459 if (time_now < last_rampup_time_ms_ + delay)
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000460 return false;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000461
Peter Boström01f364e2016-01-07 16:38:25 +0100462 return metrics.encode_usage_percent <
463 options_.low_encode_usage_threshold_percent;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000464}
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000465} // namespace webrtc