Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(102)

Side by Side Diff: webrtc/video/overuse_frame_detector.cc

Issue 2789823002: Reland of Add framerate to VideoSinkWants and ability to signal on overuse (Closed)
Patch Set: Deflake CallPerfTest.ReceivesCpuOveruseAndUnderuse Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/video/overuse_frame_detector.h ('k') | webrtc/video/send_statistics_proxy.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2013 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/overuse_frame_detector.h" 11 #include "webrtc/video/overuse_frame_detector.h"
12 12
13 #include <assert.h> 13 #include <assert.h>
14 #include <math.h> 14 #include <math.h>
15 15
16 #include <algorithm> 16 #include <algorithm>
17 #include <list> 17 #include <list>
18 #include <map> 18 #include <map>
19 #include <string>
20 #include <utility>
19 21
20 #include "webrtc/api/video/video_frame.h" 22 #include "webrtc/api/video/video_frame.h"
21 #include "webrtc/base/checks.h" 23 #include "webrtc/base/checks.h"
22 #include "webrtc/base/logging.h" 24 #include "webrtc/base/logging.h"
23 #include "webrtc/base/numerics/exp_filter.h" 25 #include "webrtc/base/numerics/exp_filter.h"
24 #include "webrtc/common_video/include/frame_callback.h" 26 #include "webrtc/common_video/include/frame_callback.h"
27 #include "webrtc/system_wrappers/include/field_trial.h"
25 28
26 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) 29 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
27 #include <mach/mach.h> 30 #include <mach/mach.h>
28 #endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) 31 #endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
29 32
30 namespace webrtc { 33 namespace webrtc {
31 34
32 namespace { 35 namespace {
33 const int64_t kCheckForOveruseIntervalMs = 5000; 36 const int64_t kCheckForOveruseIntervalMs = 5000;
34 const int64_t kTimeToFirstCheckForOveruseMs = 100; 37 const int64_t kTimeToFirstCheckForOveruseMs = 100;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 : kWeightFactorFrameDiff(0.998f), 112 : kWeightFactorFrameDiff(0.998f),
110 kWeightFactorProcessing(0.995f), 113 kWeightFactorProcessing(0.995f),
111 kInitialSampleDiffMs(40.0f), 114 kInitialSampleDiffMs(40.0f),
112 kMaxSampleDiffMs(45.0f), 115 kMaxSampleDiffMs(45.0f),
113 count_(0), 116 count_(0),
114 options_(options), 117 options_(options),
115 filtered_processing_ms_(new rtc::ExpFilter(kWeightFactorProcessing)), 118 filtered_processing_ms_(new rtc::ExpFilter(kWeightFactorProcessing)),
116 filtered_frame_diff_ms_(new rtc::ExpFilter(kWeightFactorFrameDiff)) { 119 filtered_frame_diff_ms_(new rtc::ExpFilter(kWeightFactorFrameDiff)) {
117 Reset(); 120 Reset();
118 } 121 }
119 ~SendProcessingUsage() {} 122 virtual ~SendProcessingUsage() {}
120 123
121 void Reset() { 124 void Reset() {
122 count_ = 0; 125 count_ = 0;
123 filtered_frame_diff_ms_->Reset(kWeightFactorFrameDiff); 126 filtered_frame_diff_ms_->Reset(kWeightFactorFrameDiff);
124 filtered_frame_diff_ms_->Apply(1.0f, kInitialSampleDiffMs); 127 filtered_frame_diff_ms_->Apply(1.0f, kInitialSampleDiffMs);
125 filtered_processing_ms_->Reset(kWeightFactorProcessing); 128 filtered_processing_ms_->Reset(kWeightFactorProcessing);
126 filtered_processing_ms_->Apply(1.0f, InitialProcessingMs()); 129 filtered_processing_ms_->Apply(1.0f, InitialProcessingMs());
127 } 130 }
128 131
129 void AddCaptureSample(float sample_ms) { 132 void AddCaptureSample(float sample_ms) {
130 float exp = sample_ms / kSampleDiffMs; 133 float exp = sample_ms / kSampleDiffMs;
131 exp = std::min(exp, kMaxExp); 134 exp = std::min(exp, kMaxExp);
132 filtered_frame_diff_ms_->Apply(exp, sample_ms); 135 filtered_frame_diff_ms_->Apply(exp, sample_ms);
133 } 136 }
134 137
135 void AddSample(float processing_ms, int64_t diff_last_sample_ms) { 138 void AddSample(float processing_ms, int64_t diff_last_sample_ms) {
136 ++count_; 139 ++count_;
137 float exp = diff_last_sample_ms / kSampleDiffMs; 140 float exp = diff_last_sample_ms / kSampleDiffMs;
138 exp = std::min(exp, kMaxExp); 141 exp = std::min(exp, kMaxExp);
139 filtered_processing_ms_->Apply(exp, processing_ms); 142 filtered_processing_ms_->Apply(exp, processing_ms);
140 } 143 }
141 144
142 int Value() const { 145 virtual int Value() {
143 if (count_ < static_cast<uint32_t>(options_.min_frame_samples)) { 146 if (count_ < static_cast<uint32_t>(options_.min_frame_samples)) {
144 return static_cast<int>(InitialUsageInPercent() + 0.5f); 147 return static_cast<int>(InitialUsageInPercent() + 0.5f);
145 } 148 }
146 float frame_diff_ms = std::max(filtered_frame_diff_ms_->filtered(), 1.0f); 149 float frame_diff_ms = std::max(filtered_frame_diff_ms_->filtered(), 1.0f);
147 frame_diff_ms = std::min(frame_diff_ms, kMaxSampleDiffMs); 150 frame_diff_ms = std::min(frame_diff_ms, kMaxSampleDiffMs);
148 float encode_usage_percent = 151 float encode_usage_percent =
149 100.0f * filtered_processing_ms_->filtered() / frame_diff_ms; 152 100.0f * filtered_processing_ms_->filtered() / frame_diff_ms;
150 return static_cast<int>(encode_usage_percent + 0.5); 153 return static_cast<int>(encode_usage_percent + 0.5);
151 } 154 }
152 155
(...skipping 11 matching lines...) Expand all
164 const float kWeightFactorFrameDiff; 167 const float kWeightFactorFrameDiff;
165 const float kWeightFactorProcessing; 168 const float kWeightFactorProcessing;
166 const float kInitialSampleDiffMs; 169 const float kInitialSampleDiffMs;
167 const float kMaxSampleDiffMs; 170 const float kMaxSampleDiffMs;
168 uint64_t count_; 171 uint64_t count_;
169 const CpuOveruseOptions options_; 172 const CpuOveruseOptions options_;
170 std::unique_ptr<rtc::ExpFilter> filtered_processing_ms_; 173 std::unique_ptr<rtc::ExpFilter> filtered_processing_ms_;
171 std::unique_ptr<rtc::ExpFilter> filtered_frame_diff_ms_; 174 std::unique_ptr<rtc::ExpFilter> filtered_frame_diff_ms_;
172 }; 175 };
173 176
177 // Class used for manual testing of overuse, enabled via field trial flag.
178 class OveruseFrameDetector::OverdoseInjector
179 : public OveruseFrameDetector::SendProcessingUsage {
180 public:
181 OverdoseInjector(const CpuOveruseOptions& options,
182 int64_t normal_period_ms,
183 int64_t overuse_period_ms,
184 int64_t underuse_period_ms)
185 : OveruseFrameDetector::SendProcessingUsage(options),
186 normal_period_ms_(normal_period_ms),
187 overuse_period_ms_(overuse_period_ms),
188 underuse_period_ms_(underuse_period_ms),
189 state_(State::kNormal),
190 last_toggling_ms_(-1) {
191 RTC_DCHECK_GT(overuse_period_ms, 0);
192 RTC_DCHECK_GT(normal_period_ms, 0);
193 LOG(LS_INFO) << "Simulating overuse with intervals " << normal_period_ms
194 << "ms normal mode, " << overuse_period_ms
195 << "ms overuse mode.";
196 }
197
198 ~OverdoseInjector() override {}
199
200 int Value() override {
201 int64_t now_ms = rtc::TimeMillis();
202 rtc::Optional<int> overried_usage_value;
203 if (last_toggling_ms_ == -1) {
204 last_toggling_ms_ = now_ms;
205 } else {
206 switch (state_) {
ilnik 2017/03/31 09:20:19 If i understood correctly, this may be called ever
sprang_webrtc 2017/03/31 09:46:42 Done.
207 case State::kNormal:
208 if (now_ms > last_toggling_ms_ + normal_period_ms_) {
209 state_ = State::kOveruse;
210 last_toggling_ms_ = now_ms;
211 LOG(LS_INFO) << "Simulating CPU overuse.";
212 }
213 break;
214 case State::kOveruse:
215 if (now_ms > last_toggling_ms_ + overuse_period_ms_) {
216 state_ = State::kUnderuse;
217 last_toggling_ms_ = now_ms;
218 LOG(LS_INFO) << "Simulating CPU underuse.";
219 }
220 overried_usage_value.emplace(250);
221 break;
222 case State::kUnderuse:
223 if (now_ms > last_toggling_ms_ + underuse_period_ms_) {
224 state_ = State::kNormal;
225 last_toggling_ms_ = now_ms;
226 LOG(LS_INFO) << "Actual CPU overuse measurements in effect.";
227 }
228 overried_usage_value.emplace(5);
229 break;
230 }
231 }
232
233 return overried_usage_value.value_or(SendProcessingUsage::Value());
234 }
235
236 private:
237 const int64_t normal_period_ms_;
238 const int64_t overuse_period_ms_;
239 const int64_t underuse_period_ms_;
240 enum class State { kNormal, kOveruse, kUnderuse } state_;
241 int64_t last_toggling_ms_;
242 };
243
244 std::unique_ptr<OveruseFrameDetector::SendProcessingUsage>
245 OveruseFrameDetector::CreateSendProcessingUsage(
246 const CpuOveruseOptions& options) {
247 std::unique_ptr<SendProcessingUsage> instance;
248 std::string toggling_interval =
249 field_trial::FindFullName("WebRTC-ForceSimulatedOveruseIntervalMs");
250 if (!toggling_interval.empty()) {
251 int normal_period_ms = 0;
252 int overuse_period_ms = 0;
253 int underuse_period_ms = 0;
254 if (sscanf(toggling_interval.c_str(), "%d-%d-%d", &normal_period_ms,
255 &overuse_period_ms, &underuse_period_ms) == 3) {
256 if (normal_period_ms > 0 && overuse_period_ms > 0 &&
257 underuse_period_ms > 0) {
258 instance.reset(new OverdoseInjector(
259 options, normal_period_ms, overuse_period_ms, underuse_period_ms));
260 } else {
261 LOG(LS_WARNING)
262 << "Invalid (non-positive) normal/overuse/underuse periods: "
263 << normal_period_ms << " / " << overuse_period_ms << " / "
264 << underuse_period_ms;
265 }
266 } else {
267 LOG(LS_WARNING) << "Malformed toggling interval: " << toggling_interval;
268 }
269 }
270
271 if (!instance) {
272 // No valid overuse simulation parameters set, use normal usage class.
273 instance.reset(new SendProcessingUsage(options));
274 }
275
276 return instance;
277 }
278
174 class OveruseFrameDetector::CheckOveruseTask : public rtc::QueuedTask { 279 class OveruseFrameDetector::CheckOveruseTask : public rtc::QueuedTask {
175 public: 280 public:
176 explicit CheckOveruseTask(OveruseFrameDetector* overuse_detector) 281 explicit CheckOveruseTask(OveruseFrameDetector* overuse_detector)
177 : overuse_detector_(overuse_detector) { 282 : overuse_detector_(overuse_detector) {
178 rtc::TaskQueue::Current()->PostDelayedTask( 283 rtc::TaskQueue::Current()->PostDelayedTask(
179 std::unique_ptr<rtc::QueuedTask>(this), kTimeToFirstCheckForOveruseMs); 284 std::unique_ptr<rtc::QueuedTask>(this), kTimeToFirstCheckForOveruseMs);
180 } 285 }
181 286
182 void Stop() { 287 void Stop() {
183 RTC_CHECK(task_checker_.CalledSequentially()); 288 RTC_CHECK(task_checker_.CalledSequentially());
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 // TODO(nisse): Use rtc::Optional 320 // TODO(nisse): Use rtc::Optional
216 last_capture_time_us_(-1), 321 last_capture_time_us_(-1),
217 last_processed_capture_time_us_(-1), 322 last_processed_capture_time_us_(-1),
218 num_pixels_(0), 323 num_pixels_(0),
219 last_overuse_time_ms_(-1), 324 last_overuse_time_ms_(-1),
220 checks_above_threshold_(0), 325 checks_above_threshold_(0),
221 num_overuse_detections_(0), 326 num_overuse_detections_(0),
222 last_rampup_time_ms_(-1), 327 last_rampup_time_ms_(-1),
223 in_quick_rampup_(false), 328 in_quick_rampup_(false),
224 current_rampup_delay_ms_(kStandardRampUpDelayMs), 329 current_rampup_delay_ms_(kStandardRampUpDelayMs),
225 usage_(new SendProcessingUsage(options)) { 330 usage_(CreateSendProcessingUsage(options)) {
226 task_checker_.Detach(); 331 task_checker_.Detach();
227 } 332 }
228 333
229 OveruseFrameDetector::~OveruseFrameDetector() { 334 OveruseFrameDetector::~OveruseFrameDetector() {
230 RTC_DCHECK(!check_overuse_task_) << "StopCheckForOverUse must be called."; 335 RTC_DCHECK(!check_overuse_task_) << "StopCheckForOverUse must be called.";
231 } 336 }
232 337
233 void OveruseFrameDetector::StartCheckForOveruse() { 338 void OveruseFrameDetector::StartCheckForOveruse() {
234 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); 339 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
235 RTC_DCHECK(!check_overuse_task_); 340 RTC_DCHECK(!check_overuse_task_);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 } 418 }
314 // TODO(pbos): Handle the case/log errors when not finding the corresponding 419 // TODO(pbos): Handle the case/log errors when not finding the corresponding
315 // frame (either very slow encoding or incorrect wrong timestamps returned 420 // frame (either very slow encoding or incorrect wrong timestamps returned
316 // from the encoder). 421 // from the encoder).
317 // This is currently the case for all frames on ChromeOS, so logging them 422 // This is currently the case for all frames on ChromeOS, so logging them
318 // would be spammy, and triggering overuse would be wrong. 423 // would be spammy, and triggering overuse would be wrong.
319 // https://crbug.com/350106 424 // https://crbug.com/350106
320 while (!frame_timing_.empty()) { 425 while (!frame_timing_.empty()) {
321 FrameTiming timing = frame_timing_.front(); 426 FrameTiming timing = frame_timing_.front();
322 if (time_sent_in_us - timing.capture_us < 427 if (time_sent_in_us - timing.capture_us <
323 kEncodingTimeMeasureWindowMs * rtc::kNumMicrosecsPerMillisec) 428 kEncodingTimeMeasureWindowMs * rtc::kNumMicrosecsPerMillisec) {
324 break; 429 break;
430 }
325 if (timing.last_send_us != -1) { 431 if (timing.last_send_us != -1) {
326 int encode_duration_us = 432 int encode_duration_us =
327 static_cast<int>(timing.last_send_us - timing.capture_us); 433 static_cast<int>(timing.last_send_us - timing.capture_us);
328 if (encoder_timing_) { 434 if (encoder_timing_) {
329 // TODO(nisse): Update encoder_timing_ to also use us units. 435 // TODO(nisse): Update encoder_timing_ to also use us units.
330 encoder_timing_->OnEncodeTiming(timing.capture_time_us / 436 encoder_timing_->OnEncodeTiming(timing.capture_time_us /
331 rtc::kNumMicrosecsPerMillisec, 437 rtc::kNumMicrosecsPerMillisec,
332 encode_duration_us / 438 encode_duration_us /
333 rtc::kNumMicrosecsPerMillisec); 439 rtc::kNumMicrosecsPerMillisec);
334 } 440 }
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
389 in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_; 495 in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_;
390 496
391 LOG(LS_VERBOSE) << " Frame stats: " 497 LOG(LS_VERBOSE) << " Frame stats: "
392 << " encode usage " << metrics_->encode_usage_percent 498 << " encode usage " << metrics_->encode_usage_percent
393 << " overuse detections " << num_overuse_detections_ 499 << " overuse detections " << num_overuse_detections_
394 << " rampup delay " << rampup_delay; 500 << " rampup delay " << rampup_delay;
395 } 501 }
396 502
397 bool OveruseFrameDetector::IsOverusing(const CpuOveruseMetrics& metrics) { 503 bool OveruseFrameDetector::IsOverusing(const CpuOveruseMetrics& metrics) {
398 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); 504 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
505
399 if (metrics.encode_usage_percent >= 506 if (metrics.encode_usage_percent >=
400 options_.high_encode_usage_threshold_percent) { 507 options_.high_encode_usage_threshold_percent) {
401 ++checks_above_threshold_; 508 ++checks_above_threshold_;
402 } else { 509 } else {
403 checks_above_threshold_ = 0; 510 checks_above_threshold_ = 0;
404 } 511 }
405 return checks_above_threshold_ >= options_.high_threshold_consecutive_count; 512 return checks_above_threshold_ >= options_.high_threshold_consecutive_count;
406 } 513 }
407 514
408 bool OveruseFrameDetector::IsUnderusing(const CpuOveruseMetrics& metrics, 515 bool OveruseFrameDetector::IsUnderusing(const CpuOveruseMetrics& metrics,
409 int64_t time_now) { 516 int64_t time_now) {
410 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); 517 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
411 int delay = in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_; 518 int delay = in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_;
412 if (time_now < last_rampup_time_ms_ + delay) 519 if (time_now < last_rampup_time_ms_ + delay)
413 return false; 520 return false;
414 521
415 return metrics.encode_usage_percent < 522 return metrics.encode_usage_percent <
416 options_.low_encode_usage_threshold_percent; 523 options_.low_encode_usage_threshold_percent;
417 } 524 }
418 } // namespace webrtc 525 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/video/overuse_frame_detector.h ('k') | webrtc/video/send_statistics_proxy.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698