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

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

Issue 2255463002: Change OverUseFrameDetector to use a task queue (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@reland_taskq_in_encoder
Patch Set: Fix event.h include in unittest Created 4 years, 4 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
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
(...skipping 13 matching lines...) Expand all
24 #include "webrtc/system_wrappers/include/clock.h" 24 #include "webrtc/system_wrappers/include/clock.h"
25 #include "webrtc/video_frame.h" 25 #include "webrtc/video_frame.h"
26 26
27 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) 27 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
28 #include <mach/mach.h> 28 #include <mach/mach.h>
29 #endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) 29 #endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS)
30 30
31 namespace webrtc { 31 namespace webrtc {
32 32
33 namespace { 33 namespace {
34 const int64_t kProcessIntervalMs = 5000; 34 const int64_t ktCheckForOveruseIntervalMs = 5000;
åsapersson 2016/08/24 08:59:04 kCheck..?
perkj_webrtc 2016/09/01 10:03:29 Done.
35 const int64_t kTimeToFirstCheckForOveruseMs = 100;
35 36
36 // Delay between consecutive rampups. (Used for quick recovery.) 37 // Delay between consecutive rampups. (Used for quick recovery.)
37 const int kQuickRampUpDelayMs = 10 * 1000; 38 const int kQuickRampUpDelayMs = 10 * 1000;
38 // Delay between rampup attempts. Initially uses standard, scales up to max. 39 // Delay between rampup attempts. Initially uses standard, scales up to max.
39 const int kStandardRampUpDelayMs = 40 * 1000; 40 const int kStandardRampUpDelayMs = 40 * 1000;
40 const int kMaxRampUpDelayMs = 240 * 1000; 41 const int kMaxRampUpDelayMs = 240 * 1000;
41 // Expontential back-off factor, to prevent annoying up-down behaviour. 42 // Expontential back-off factor, to prevent annoying up-down behaviour.
42 const double kRampUpBackoffFactor = 2.0; 43 const double kRampUpBackoffFactor = 2.0;
43 44
44 // Max number of overuses detected before always applying the rampup delay. 45 // Max number of overuses detected before always applying the rampup delay.
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 const float kWeightFactorFrameDiff; 164 const float kWeightFactorFrameDiff;
164 const float kWeightFactorProcessing; 165 const float kWeightFactorProcessing;
165 const float kInitialSampleDiffMs; 166 const float kInitialSampleDiffMs;
166 const float kMaxSampleDiffMs; 167 const float kMaxSampleDiffMs;
167 uint64_t count_; 168 uint64_t count_;
168 const CpuOveruseOptions options_; 169 const CpuOveruseOptions options_;
169 std::unique_ptr<rtc::ExpFilter> filtered_processing_ms_; 170 std::unique_ptr<rtc::ExpFilter> filtered_processing_ms_;
170 std::unique_ptr<rtc::ExpFilter> filtered_frame_diff_ms_; 171 std::unique_ptr<rtc::ExpFilter> filtered_frame_diff_ms_;
171 }; 172 };
172 173
174 class OveruseFrameDetector::CheckOveruseTask : public rtc::QueuedTask {
175 public:
176 explicit CheckOveruseTask(OveruseFrameDetector* overuse_detector)
177 : overuse_detector_(overuse_detector) {
178 rtc::TaskQueue::Current()->PostDelayedTask(
179 std::unique_ptr<rtc::QueuedTask>(this), kTimeToFirstCheckForOveruseMs);
180 }
181
182 void Stop() {
183 RTC_CHECK(task_checker_.CalledSequentially());
184 overuse_detector_ = nullptr;
185 }
186
187 private:
188 bool Run() override {
189 RTC_CHECK(task_checker_.CalledSequentially());
190 if (!overuse_detector_)
191 return true; // This will make the task queue delete this task.
192 overuse_detector_->CheckForOveruse();
193
194 rtc::TaskQueue::Current()->PostDelayedTask(
195 std::unique_ptr<rtc::QueuedTask>(this), ktCheckForOveruseIntervalMs);
196 // Return false to prevent this task from being deleted. Ownership has been
197 // transferred to the task queue when PostDelayedTask was called.
198 return false;
199 }
200 rtc::SequencedTaskChecker task_checker_;
201 OveruseFrameDetector* overuse_detector_;
202 };
203
173 OveruseFrameDetector::OveruseFrameDetector( 204 OveruseFrameDetector::OveruseFrameDetector(
174 Clock* clock, 205 Clock* clock,
175 const CpuOveruseOptions& options, 206 const CpuOveruseOptions& options,
176 CpuOveruseObserver* observer, 207 CpuOveruseObserver* observer,
177 EncodedFrameObserver* encoder_timing, 208 EncodedFrameObserver* encoder_timing,
178 CpuOveruseMetricsObserver* metrics_observer) 209 CpuOveruseMetricsObserver* metrics_observer)
179 : options_(options), 210 : check_over_use_task_(nullptr),
211 options_(options),
180 observer_(observer), 212 observer_(observer),
181 encoder_timing_(encoder_timing), 213 encoder_timing_(encoder_timing),
182 metrics_observer_(metrics_observer), 214 metrics_observer_(metrics_observer),
183 clock_(clock), 215 clock_(clock),
184 num_process_times_(0), 216 num_process_times_(0),
185 last_capture_time_ms_(-1), 217 last_capture_time_ms_(-1),
186 last_processed_capture_time_ms_(-1), 218 last_processed_capture_time_ms_(-1),
187 num_pixels_(0), 219 num_pixels_(0),
188 next_process_time_ms_(clock_->TimeInMilliseconds()),
189 last_overuse_time_ms_(-1), 220 last_overuse_time_ms_(-1),
190 checks_above_threshold_(0), 221 checks_above_threshold_(0),
191 num_overuse_detections_(0), 222 num_overuse_detections_(0),
192 last_rampup_time_ms_(-1), 223 last_rampup_time_ms_(-1),
193 in_quick_rampup_(false), 224 in_quick_rampup_(false),
194 current_rampup_delay_ms_(kStandardRampUpDelayMs), 225 current_rampup_delay_ms_(kStandardRampUpDelayMs),
195 usage_(new SendProcessingUsage(options)) { 226 usage_(new SendProcessingUsage(options)) {
196 processing_thread_.DetachFromThread(); 227 task_checker_.Detach();
197 } 228 }
198 229
199 OveruseFrameDetector::~OveruseFrameDetector() { 230 OveruseFrameDetector::~OveruseFrameDetector() {
231 RTC_DCHECK(!check_over_use_task_) << "StopCheckForOverUse must be called.";
åsapersson 2016/08/24 08:59:04 nit: OverUse->Overuse
perkj_webrtc 2016/09/01 10:03:29 Done.
232 }
233
234 void OveruseFrameDetector::StartCheckForOveruse() {
235 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
236 RTC_DCHECK(!check_over_use_task_);
237 check_over_use_task_ = new CheckOveruseTask(this);
238 }
239 void OveruseFrameDetector::StopCheckForOveruse() {
240 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
241 check_over_use_task_->Stop();
242 check_over_use_task_ = nullptr;
200 } 243 }
201 244
202 void OveruseFrameDetector::EncodedFrameTimeMeasured(int encode_duration_ms) { 245 void OveruseFrameDetector::EncodedFrameTimeMeasured(int encode_duration_ms) {
246 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
203 if (!metrics_) 247 if (!metrics_)
204 metrics_ = rtc::Optional<CpuOveruseMetrics>(CpuOveruseMetrics()); 248 metrics_ = rtc::Optional<CpuOveruseMetrics>(CpuOveruseMetrics());
205 metrics_->encode_usage_percent = usage_->Value(); 249 metrics_->encode_usage_percent = usage_->Value();
206 250
207 metrics_observer_->OnEncodedFrameTimeMeasured(encode_duration_ms, *metrics_); 251 metrics_observer_->OnEncodedFrameTimeMeasured(encode_duration_ms, *metrics_);
208 } 252 }
209 253
210 int64_t OveruseFrameDetector::TimeUntilNextProcess() {
211 RTC_DCHECK(processing_thread_.CalledOnValidThread());
212 return next_process_time_ms_ - clock_->TimeInMilliseconds();
213 }
214
215 bool OveruseFrameDetector::FrameSizeChanged(int num_pixels) const { 254 bool OveruseFrameDetector::FrameSizeChanged(int num_pixels) const {
255 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
åsapersson 2016/08/24 08:59:04 Is the check needed for private methods?
perkj_webrtc 2016/09/01 10:03:29 Yes- , if you use GUARDED_BY(..) this is needed on
216 if (num_pixels != num_pixels_) { 256 if (num_pixels != num_pixels_) {
217 return true; 257 return true;
218 } 258 }
219 return false; 259 return false;
220 } 260 }
221 261
222 bool OveruseFrameDetector::FrameTimeoutDetected(int64_t now) const { 262 bool OveruseFrameDetector::FrameTimeoutDetected(int64_t now) const {
263 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
223 if (last_capture_time_ms_ == -1) 264 if (last_capture_time_ms_ == -1)
224 return false; 265 return false;
225 return (now - last_capture_time_ms_) > options_.frame_timeout_interval_ms; 266 return (now - last_capture_time_ms_) > options_.frame_timeout_interval_ms;
226 } 267 }
227 268
228 void OveruseFrameDetector::ResetAll(int num_pixels) { 269 void OveruseFrameDetector::ResetAll(int num_pixels) {
270 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
229 num_pixels_ = num_pixels; 271 num_pixels_ = num_pixels;
230 usage_->Reset(); 272 usage_->Reset();
231 frame_timing_.clear(); 273 frame_timing_.clear();
232 last_capture_time_ms_ = -1; 274 last_capture_time_ms_ = -1;
233 last_processed_capture_time_ms_ = -1; 275 last_processed_capture_time_ms_ = -1;
234 num_process_times_ = 0; 276 num_process_times_ = 0;
235 metrics_ = rtc::Optional<CpuOveruseMetrics>(); 277 metrics_ = rtc::Optional<CpuOveruseMetrics>();
236 } 278 }
237 279
238 void OveruseFrameDetector::FrameCaptured(const VideoFrame& frame) { 280 void OveruseFrameDetector::FrameCaptured(const VideoFrame& frame,
239 rtc::CritScope cs(&crit_); 281 int64_t time_when_first_seen) {
åsapersson 2016/08/24 08:59:04 time_when_first_seen_ms
perkj_webrtc 2016/09/01 10:03:29 Done.
282 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
240 283
241 int64_t now = clock_->TimeInMilliseconds();
242 if (FrameSizeChanged(frame.width() * frame.height()) || 284 if (FrameSizeChanged(frame.width() * frame.height()) ||
243 FrameTimeoutDetected(now)) { 285 FrameTimeoutDetected(time_when_first_seen)) {
244 ResetAll(frame.width() * frame.height()); 286 ResetAll(frame.width() * frame.height());
245 } 287 }
246 288
247 if (last_capture_time_ms_ != -1) 289 if (last_capture_time_ms_ != -1)
248 usage_->AddCaptureSample(now - last_capture_time_ms_); 290 usage_->AddCaptureSample(time_when_first_seen - last_capture_time_ms_);
249 291
250 last_capture_time_ms_ = now; 292 last_capture_time_ms_ = time_when_first_seen;
251 293
252 frame_timing_.push_back( 294 frame_timing_.push_back(FrameTiming(frame.ntp_time_ms(), frame.timestamp(),
253 FrameTiming(frame.ntp_time_ms(), frame.timestamp(), now)); 295 time_when_first_seen));
254 } 296 }
255 297
256 void OveruseFrameDetector::FrameSent(uint32_t timestamp) { 298 void OveruseFrameDetector::FrameSent(uint32_t timestamp,
257 rtc::CritScope cs(&crit_); 299 int64_t time_sent_in_ms) {
300 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
258 // Delay before reporting actual encoding time, used to have the ability to 301 // Delay before reporting actual encoding time, used to have the ability to
259 // detect total encoding time when encoding more than one layer. Encoding is 302 // detect total encoding time when encoding more than one layer. Encoding is
260 // here assumed to finish within a second (or that we get enough long-time 303 // here assumed to finish within a second (or that we get enough long-time
261 // samples before one second to trigger an overuse even when this is not the 304 // samples before one second to trigger an overuse even when this is not the
262 // case). 305 // case).
263 static const int64_t kEncodingTimeMeasureWindowMs = 1000; 306 static const int64_t kEncodingTimeMeasureWindowMs = 1000;
264 int64_t now = clock_->TimeInMilliseconds();
265 for (auto& it : frame_timing_) { 307 for (auto& it : frame_timing_) {
266 if (it.timestamp == timestamp) { 308 if (it.timestamp == timestamp) {
267 it.last_send_ms = now; 309 it.last_send_ms = time_sent_in_ms;
268 break; 310 break;
269 } 311 }
270 } 312 }
271 // TODO(pbos): Handle the case/log errors when not finding the corresponding 313 // TODO(pbos): Handle the case/log errors when not finding the corresponding
272 // frame (either very slow encoding or incorrect wrong timestamps returned 314 // frame (either very slow encoding or incorrect wrong timestamps returned
273 // from the encoder). 315 // from the encoder).
274 // This is currently the case for all frames on ChromeOS, so logging them 316 // This is currently the case for all frames on ChromeOS, so logging them
275 // would be spammy, and triggering overuse would be wrong. 317 // would be spammy, and triggering overuse would be wrong.
276 // https://crbug.com/350106 318 // https://crbug.com/350106
277 while (!frame_timing_.empty()) { 319 while (!frame_timing_.empty()) {
278 FrameTiming timing = frame_timing_.front(); 320 FrameTiming timing = frame_timing_.front();
279 if (now - timing.capture_ms < kEncodingTimeMeasureWindowMs) 321 if (time_sent_in_ms - timing.capture_ms < kEncodingTimeMeasureWindowMs)
280 break; 322 break;
281 if (timing.last_send_ms != -1) { 323 if (timing.last_send_ms != -1) {
282 int encode_duration_ms = 324 int encode_duration_ms =
283 static_cast<int>(timing.last_send_ms - timing.capture_ms); 325 static_cast<int>(timing.last_send_ms - timing.capture_ms);
284 if (encoder_timing_) { 326 if (encoder_timing_) {
285 encoder_timing_->OnEncodeTiming(timing.capture_ntp_ms, 327 encoder_timing_->OnEncodeTiming(timing.capture_ntp_ms,
286 encode_duration_ms); 328 encode_duration_ms);
287 } 329 }
288 if (last_processed_capture_time_ms_ != -1) { 330 if (last_processed_capture_time_ms_ != -1) {
289 int64_t diff_ms = timing.capture_ms - last_processed_capture_time_ms_; 331 int64_t diff_ms = timing.capture_ms - last_processed_capture_time_ms_;
290 usage_->AddSample(encode_duration_ms, diff_ms); 332 usage_->AddSample(encode_duration_ms, diff_ms);
291 } 333 }
292 last_processed_capture_time_ms_ = timing.capture_ms; 334 last_processed_capture_time_ms_ = timing.capture_ms;
293 EncodedFrameTimeMeasured(encode_duration_ms); 335 EncodedFrameTimeMeasured(encode_duration_ms);
294 } 336 }
295 frame_timing_.pop_front(); 337 frame_timing_.pop_front();
296 } 338 }
297 } 339 }
298 340
299 void OveruseFrameDetector::Process() { 341 void OveruseFrameDetector::CheckForOveruse() {
300 RTC_DCHECK(processing_thread_.CalledOnValidThread()); 342 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
343 ++num_process_times_;
344 if (num_process_times_ <= options_.min_process_count || !metrics_)
345 return;
301 346
302 int64_t now = clock_->TimeInMilliseconds(); 347 int64_t now = clock_->TimeInMilliseconds();
303 348 CpuOveruseMetrics current_metrics = *metrics_;
åsapersson 2016/08/24 08:59:04 remove current_metrics and use metrics_ instead?
perkj_webrtc 2016/09/01 10:03:29 Done.
304 // Used to protect against Process() being called too often.
305 if (now < next_process_time_ms_)
306 return;
307
308 next_process_time_ms_ = now + kProcessIntervalMs;
309
310 CpuOveruseMetrics current_metrics;
311 {
312 rtc::CritScope cs(&crit_);
313 ++num_process_times_;
314 if (num_process_times_ <= options_.min_process_count || !metrics_)
315 return;
316
317 current_metrics = *metrics_;
318 }
319 349
320 if (IsOverusing(current_metrics)) { 350 if (IsOverusing(current_metrics)) {
321 // If the last thing we did was going up, and now have to back down, we need 351 // If the last thing we did was going up, and now have to back down, we need
322 // to check if this peak was short. If so we should back off to avoid going 352 // to check if this peak was short. If so we should back off to avoid going
323 // back and forth between this load, the system doesn't seem to handle it. 353 // back and forth between this load, the system doesn't seem to handle it.
324 bool check_for_backoff = last_rampup_time_ms_ > last_overuse_time_ms_; 354 bool check_for_backoff = last_rampup_time_ms_ > last_overuse_time_ms_;
325 if (check_for_backoff) { 355 if (check_for_backoff) {
326 if (now - last_rampup_time_ms_ < kStandardRampUpDelayMs || 356 if (now - last_rampup_time_ms_ < kStandardRampUpDelayMs ||
327 num_overuse_detections_ > kMaxOverusesBeforeApplyRampupDelay) { 357 num_overuse_detections_ > kMaxOverusesBeforeApplyRampupDelay) {
328 // Going up was not ok for very long, back off. 358 // Going up was not ok for very long, back off.
(...skipping 24 matching lines...) Expand all
353 int rampup_delay = 383 int rampup_delay =
354 in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_; 384 in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_;
355 385
356 LOG(LS_VERBOSE) << " Frame stats: " 386 LOG(LS_VERBOSE) << " Frame stats: "
357 << " encode usage " << current_metrics.encode_usage_percent 387 << " encode usage " << current_metrics.encode_usage_percent
358 << " overuse detections " << num_overuse_detections_ 388 << " overuse detections " << num_overuse_detections_
359 << " rampup delay " << rampup_delay; 389 << " rampup delay " << rampup_delay;
360 } 390 }
361 391
362 bool OveruseFrameDetector::IsOverusing(const CpuOveruseMetrics& metrics) { 392 bool OveruseFrameDetector::IsOverusing(const CpuOveruseMetrics& metrics) {
393 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
363 if (metrics.encode_usage_percent >= 394 if (metrics.encode_usage_percent >=
364 options_.high_encode_usage_threshold_percent) { 395 options_.high_encode_usage_threshold_percent) {
365 ++checks_above_threshold_; 396 ++checks_above_threshold_;
366 } else { 397 } else {
367 checks_above_threshold_ = 0; 398 checks_above_threshold_ = 0;
368 } 399 }
369 return checks_above_threshold_ >= options_.high_threshold_consecutive_count; 400 return checks_above_threshold_ >= options_.high_threshold_consecutive_count;
370 } 401 }
371 402
372 bool OveruseFrameDetector::IsUnderusing(const CpuOveruseMetrics& metrics, 403 bool OveruseFrameDetector::IsUnderusing(const CpuOveruseMetrics& metrics,
373 int64_t time_now) { 404 int64_t time_now) {
405 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_);
374 int delay = in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_; 406 int delay = in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_;
375 if (time_now < last_rampup_time_ms_ + delay) 407 if (time_now < last_rampup_time_ms_ + delay)
376 return false; 408 return false;
377 409
378 return metrics.encode_usage_percent < 410 return metrics.encode_usage_percent <
379 options_.low_encode_usage_threshold_percent; 411 options_.low_encode_usage_threshold_percent;
380 } 412 }
381 } // namespace webrtc 413 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698