blob: b8c1a0d5a718b472f42c89b1c0d3430bf3f4028c [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
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000016#include "webrtc/system_wrappers/interface/clock.h"
17#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
pbos@webrtc.orga9575702013-08-30 17:16:32 +000018#include "webrtc/system_wrappers/interface/trace.h"
mflodman@webrtc.org6879c8a2013-07-23 11:35:00 +000019#include "webrtc/video_engine/include/vie_base.h"
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000020
21namespace webrtc {
22
pbos@webrtc.orga9575702013-08-30 17:16:32 +000023Statistics::Statistics() { Reset(); }
24
25void Statistics::Reset() {
26 sum_ = sum_squared_ = 0.0;
27 count_ = 0;
28}
29
30void Statistics::AddSample(double sample) {
31 sum_ += sample;
32 sum_squared_ += sample * sample;
33 ++count_;
34}
35
36double Statistics::Mean() const {
37 if (count_ == 0)
38 return 0.0;
39 return sum_ / count_;
40}
41
42double Statistics::Variance() const {
43 if (count_ == 0)
44 return 0.0;
45 return sum_squared_ / count_ - Mean() * Mean();
46}
47
48double Statistics::StdDev() const { return sqrt(Variance()); }
49
50uint64_t Statistics::Samples() const { return count_; }
51
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000052// TODO(mflodman) Test different values for all of these to trigger correctly,
53// avoid fluctuations etc.
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000054namespace {
pbos@webrtc.orga9575702013-08-30 17:16:32 +000055const int64_t kProcessIntervalMs = 5000;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000056
pbos@webrtc.orga9575702013-08-30 17:16:32 +000057// Limits on standard deviation for under/overuse.
58const double kOveruseStdDevMs = 15.0;
59const double kNormalUseStdDevMs = 10.0;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000060
pbos@webrtc.orga9575702013-08-30 17:16:32 +000061// Rampdown checks.
62const int kConsecutiveChecksAboveThreshold = 2;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000063
pbos@webrtc.orga9575702013-08-30 17:16:32 +000064// Delay between consecutive rampups. (Used for quick recovery.)
65const int kQuickRampUpDelayMs = 10 * 1000;
66// Delay between rampup attempts. Initially uses standard, scales up to max.
67const int kStandardRampUpDelayMs = 30 * 1000;
68const int kMaxRampUpDelayMs = 120 * 1000;
69// Expontential back-off factor, to prevent annoying up-down behaviour.
70const double kRampUpBackoffFactor = 2.0;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000071
pbos@webrtc.orga9575702013-08-30 17:16:32 +000072// Minimum samples required to perform a check.
73const size_t kMinFrameSampleCount = 30;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000074} // namespace
75
mflodman@webrtc.org6879c8a2013-07-23 11:35:00 +000076OveruseFrameDetector::OveruseFrameDetector(Clock* clock)
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000077 : crit_(CriticalSectionWrapper::CreateCriticalSection()),
mflodman@webrtc.org6879c8a2013-07-23 11:35:00 +000078 observer_(NULL),
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000079 clock_(clock),
pbos@webrtc.orga9575702013-08-30 17:16:32 +000080 next_process_time_(clock_->TimeInMilliseconds()),
81 last_capture_time_(0),
82 last_overuse_time_(0),
83 checks_above_threshold_(0),
84 last_rampup_time_(0),
85 in_quick_rampup_(false),
86 current_rampup_delay_ms_(kStandardRampUpDelayMs) {}
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +000087
88OveruseFrameDetector::~OveruseFrameDetector() {
89}
90
mflodman@webrtc.org6879c8a2013-07-23 11:35:00 +000091void OveruseFrameDetector::SetObserver(CpuOveruseObserver* observer) {
92 CriticalSectionScoped cs(crit_.get());
93 observer_ = observer;
94}
95
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +000096void OveruseFrameDetector::FrameCaptured() {
97 CriticalSectionScoped cs(crit_.get());
pbos@webrtc.orga9575702013-08-30 17:16:32 +000098 int64_t time = clock_->TimeInMilliseconds();
99 if (last_capture_time_ != 0) {
100 capture_deltas_.AddSample(time - last_capture_time_);
101 }
102 last_capture_time_ = time;
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000103}
104
105int32_t OveruseFrameDetector::TimeUntilNextProcess() {
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000106 CriticalSectionScoped cs(crit_.get());
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000107 return next_process_time_ - clock_->TimeInMilliseconds();
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000108}
109
110int32_t OveruseFrameDetector::Process() {
111 CriticalSectionScoped cs(crit_.get());
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000112
mflodman@webrtc.org6879c8a2013-07-23 11:35:00 +0000113 int64_t now = clock_->TimeInMilliseconds();
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000114
115 // Used to protect against Process() being called too often.
116 if (now < next_process_time_)
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000117 return 0;
118
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000119 next_process_time_ = now + kProcessIntervalMs;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000120
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000121 // Don't trigger overuse unless we've seen any frames
122 if (capture_deltas_.Samples() < kMinFrameSampleCount)
mflodman@webrtc.org6879c8a2013-07-23 11:35:00 +0000123 return 0;
124
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000125 if (IsOverusing()) {
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000126 // If the last thing we did was going up, and now have to back down, we need
127 // to check if this peak was short. If so we should back off to avoid going
128 // back and forth between this load, the system doesn't seem to handle it.
129 bool check_for_backoff = last_rampup_time_ > last_overuse_time_;
130 if (check_for_backoff) {
131 if (now - last_rampup_time_ < kStandardRampUpDelayMs) {
132 // Going up was not ok for very long, back off.
133 current_rampup_delay_ms_ *= kRampUpBackoffFactor;
134 if (current_rampup_delay_ms_ > kMaxRampUpDelayMs)
135 current_rampup_delay_ms_ = kMaxRampUpDelayMs;
136 } else {
137 // Not currently backing off, reset rampup delay.
138 current_rampup_delay_ms_ = kStandardRampUpDelayMs;
139 }
140 }
141
142 last_overuse_time_ = now;
143 in_quick_rampup_ = false;
144 checks_above_threshold_ = 0;
145
146 if (observer_ != NULL)
147 observer_->OveruseDetected();
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000148 } else if (IsUnderusing(now)) {
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000149 last_rampup_time_ = now;
150 in_quick_rampup_ = true;
151
152 if (observer_ != NULL)
153 observer_->NormalUsage();
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000154 }
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000155
156 capture_deltas_.Reset();
157
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000158 return 0;
159}
160
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000161bool OveruseFrameDetector::IsOverusing() {
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000162 WEBRTC_TRACE(
163 webrtc::kTraceInfo,
164 webrtc::kTraceVideo,
165 -1,
166 "Capture input stats: avg: %.2fms, std_dev: %.2fms (rampup delay: "
167 "%dms, overuse: >=%.2fms, "
168 "underuse: <%.2fms)",
169 capture_deltas_.Mean(),
170 capture_deltas_.StdDev(),
171 in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_,
172 kOveruseStdDevMs,
173 kNormalUseStdDevMs);
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000174
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000175 if (capture_deltas_.StdDev() >= kOveruseStdDevMs) {
176 ++checks_above_threshold_;
177 } else {
178 checks_above_threshold_ = 0;
179 }
180
181 return checks_above_threshold_ >= kConsecutiveChecksAboveThreshold;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000182}
183
184bool OveruseFrameDetector::IsUnderusing(int64_t time_now) {
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000185 int delay = in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_;
186 if (time_now < last_rampup_time_ + delay)
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000187 return false;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000188
pbos@webrtc.orga9575702013-08-30 17:16:32 +0000189 return capture_deltas_.StdDev() < kNormalUseStdDevMs;
mflodman@webrtc.orgd4412fe2013-07-31 16:42:21 +0000190}
mflodman@webrtc.orge6168f52013-06-26 11:23:01 +0000191} // namespace webrtc