OLD | NEW |
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 | 19 |
20 #include "webrtc/api/video/video_frame.h" | 20 #include "webrtc/api/video/video_frame.h" |
21 #include "webrtc/base/checks.h" | 21 #include "webrtc/base/checks.h" |
22 #include "webrtc/base/logging.h" | 22 #include "webrtc/base/logging.h" |
23 #include "webrtc/base/numerics/exp_filter.h" | 23 #include "webrtc/base/numerics/exp_filter.h" |
24 #include "webrtc/common_video/include/frame_callback.h" | 24 #include "webrtc/common_video/include/frame_callback.h" |
25 #include "webrtc/system_wrappers/include/clock.h" | |
26 | 25 |
27 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) | 26 #if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) |
28 #include <mach/mach.h> | 27 #include <mach/mach.h> |
29 #endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) | 28 #endif // defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) |
30 | 29 |
31 namespace webrtc { | 30 namespace webrtc { |
32 | 31 |
33 namespace { | 32 namespace { |
34 const int64_t kCheckForOveruseIntervalMs = 5000; | 33 const int64_t kCheckForOveruseIntervalMs = 5000; |
35 const int64_t kTimeToFirstCheckForOveruseMs = 100; | 34 const int64_t kTimeToFirstCheckForOveruseMs = 100; |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
196 std::unique_ptr<rtc::QueuedTask>(this), kCheckForOveruseIntervalMs); | 195 std::unique_ptr<rtc::QueuedTask>(this), kCheckForOveruseIntervalMs); |
197 // Return false to prevent this task from being deleted. Ownership has been | 196 // Return false to prevent this task from being deleted. Ownership has been |
198 // transferred to the task queue when PostDelayedTask was called. | 197 // transferred to the task queue when PostDelayedTask was called. |
199 return false; | 198 return false; |
200 } | 199 } |
201 rtc::SequencedTaskChecker task_checker_; | 200 rtc::SequencedTaskChecker task_checker_; |
202 OveruseFrameDetector* overuse_detector_; | 201 OveruseFrameDetector* overuse_detector_; |
203 }; | 202 }; |
204 | 203 |
205 OveruseFrameDetector::OveruseFrameDetector( | 204 OveruseFrameDetector::OveruseFrameDetector( |
206 Clock* clock, | |
207 const CpuOveruseOptions& options, | 205 const CpuOveruseOptions& options, |
208 ScalingObserverInterface* observer, | 206 ScalingObserverInterface* observer, |
209 EncodedFrameObserver* encoder_timing, | 207 EncodedFrameObserver* encoder_timing, |
210 CpuOveruseMetricsObserver* metrics_observer) | 208 CpuOveruseMetricsObserver* metrics_observer) |
211 : check_overuse_task_(nullptr), | 209 : check_overuse_task_(nullptr), |
212 options_(options), | 210 options_(options), |
213 observer_(observer), | 211 observer_(observer), |
214 encoder_timing_(encoder_timing), | 212 encoder_timing_(encoder_timing), |
215 metrics_observer_(metrics_observer), | 213 metrics_observer_(metrics_observer), |
216 clock_(clock), | |
217 num_process_times_(0), | 214 num_process_times_(0), |
218 last_capture_time_ms_(-1), | 215 // TODO(nisse): Use rtc::Optional |
219 last_processed_capture_time_ms_(-1), | 216 last_capture_time_us_(-1), |
| 217 last_processed_capture_time_us_(-1), |
220 num_pixels_(0), | 218 num_pixels_(0), |
221 last_overuse_time_ms_(-1), | 219 last_overuse_time_ms_(-1), |
222 checks_above_threshold_(0), | 220 checks_above_threshold_(0), |
223 num_overuse_detections_(0), | 221 num_overuse_detections_(0), |
224 last_rampup_time_ms_(-1), | 222 last_rampup_time_ms_(-1), |
225 in_quick_rampup_(false), | 223 in_quick_rampup_(false), |
226 current_rampup_delay_ms_(kStandardRampUpDelayMs), | 224 current_rampup_delay_ms_(kStandardRampUpDelayMs), |
227 usage_(new SendProcessingUsage(options)) { | 225 usage_(new SendProcessingUsage(options)) { |
228 task_checker_.Detach(); | 226 task_checker_.Detach(); |
229 } | 227 } |
(...skipping 23 matching lines...) Expand all Loading... |
253 } | 251 } |
254 | 252 |
255 bool OveruseFrameDetector::FrameSizeChanged(int num_pixels) const { | 253 bool OveruseFrameDetector::FrameSizeChanged(int num_pixels) const { |
256 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); | 254 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); |
257 if (num_pixels != num_pixels_) { | 255 if (num_pixels != num_pixels_) { |
258 return true; | 256 return true; |
259 } | 257 } |
260 return false; | 258 return false; |
261 } | 259 } |
262 | 260 |
263 bool OveruseFrameDetector::FrameTimeoutDetected(int64_t now) const { | 261 bool OveruseFrameDetector::FrameTimeoutDetected(int64_t now_us) const { |
264 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); | 262 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); |
265 if (last_capture_time_ms_ == -1) | 263 if (last_capture_time_us_ == -1) |
266 return false; | 264 return false; |
267 return (now - last_capture_time_ms_) > options_.frame_timeout_interval_ms; | 265 return (now_us - last_capture_time_us_) > |
| 266 options_.frame_timeout_interval_ms * rtc::kNumMicrosecsPerMillisec; |
268 } | 267 } |
269 | 268 |
270 void OveruseFrameDetector::ResetAll(int num_pixels) { | 269 void OveruseFrameDetector::ResetAll(int num_pixels) { |
271 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); | 270 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); |
272 num_pixels_ = num_pixels; | 271 num_pixels_ = num_pixels; |
273 usage_->Reset(); | 272 usage_->Reset(); |
274 frame_timing_.clear(); | 273 frame_timing_.clear(); |
275 last_capture_time_ms_ = -1; | 274 last_capture_time_us_ = -1; |
276 last_processed_capture_time_ms_ = -1; | 275 last_processed_capture_time_us_ = -1; |
277 num_process_times_ = 0; | 276 num_process_times_ = 0; |
278 metrics_ = rtc::Optional<CpuOveruseMetrics>(); | 277 metrics_ = rtc::Optional<CpuOveruseMetrics>(); |
279 } | 278 } |
280 | 279 |
281 void OveruseFrameDetector::FrameCaptured(const VideoFrame& frame, | 280 void OveruseFrameDetector::FrameCaptured(const VideoFrame& frame, |
282 int64_t time_when_first_seen_ms) { | 281 int64_t time_when_first_seen_us) { |
283 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); | 282 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); |
284 | 283 |
285 if (FrameSizeChanged(frame.width() * frame.height()) || | 284 if (FrameSizeChanged(frame.width() * frame.height()) || |
286 FrameTimeoutDetected(time_when_first_seen_ms)) { | 285 FrameTimeoutDetected(time_when_first_seen_us)) { |
287 ResetAll(frame.width() * frame.height()); | 286 ResetAll(frame.width() * frame.height()); |
288 } | 287 } |
289 | 288 |
290 if (last_capture_time_ms_ != -1) | 289 if (last_capture_time_us_ != -1) |
291 usage_->AddCaptureSample(time_when_first_seen_ms - last_capture_time_ms_); | 290 usage_->AddCaptureSample( |
| 291 1e-3 * (time_when_first_seen_us - last_capture_time_us_)); |
292 | 292 |
293 last_capture_time_ms_ = time_when_first_seen_ms; | 293 last_capture_time_us_ = time_when_first_seen_us; |
294 | 294 |
295 frame_timing_.push_back(FrameTiming(frame.ntp_time_ms(), frame.timestamp(), | 295 frame_timing_.push_back(FrameTiming(frame.timestamp_us(), frame.timestamp(), |
296 time_when_first_seen_ms)); | 296 time_when_first_seen_us)); |
297 } | 297 } |
298 | 298 |
299 void OveruseFrameDetector::FrameSent(uint32_t timestamp, | 299 void OveruseFrameDetector::FrameSent(uint32_t timestamp, |
300 int64_t time_sent_in_ms) { | 300 int64_t time_sent_in_us) { |
301 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); | 301 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); |
302 // Delay before reporting actual encoding time, used to have the ability to | 302 // Delay before reporting actual encoding time, used to have the ability to |
303 // detect total encoding time when encoding more than one layer. Encoding is | 303 // detect total encoding time when encoding more than one layer. Encoding is |
304 // here assumed to finish within a second (or that we get enough long-time | 304 // here assumed to finish within a second (or that we get enough long-time |
305 // samples before one second to trigger an overuse even when this is not the | 305 // samples before one second to trigger an overuse even when this is not the |
306 // case). | 306 // case). |
307 static const int64_t kEncodingTimeMeasureWindowMs = 1000; | 307 static const int64_t kEncodingTimeMeasureWindowMs = 1000; |
308 for (auto& it : frame_timing_) { | 308 for (auto& it : frame_timing_) { |
309 if (it.timestamp == timestamp) { | 309 if (it.timestamp == timestamp) { |
310 it.last_send_ms = time_sent_in_ms; | 310 it.last_send_us = time_sent_in_us; |
311 break; | 311 break; |
312 } | 312 } |
313 } | 313 } |
314 // TODO(pbos): Handle the case/log errors when not finding the corresponding | 314 // TODO(pbos): Handle the case/log errors when not finding the corresponding |
315 // frame (either very slow encoding or incorrect wrong timestamps returned | 315 // frame (either very slow encoding or incorrect wrong timestamps returned |
316 // from the encoder). | 316 // from the encoder). |
317 // This is currently the case for all frames on ChromeOS, so logging them | 317 // This is currently the case for all frames on ChromeOS, so logging them |
318 // would be spammy, and triggering overuse would be wrong. | 318 // would be spammy, and triggering overuse would be wrong. |
319 // https://crbug.com/350106 | 319 // https://crbug.com/350106 |
320 while (!frame_timing_.empty()) { | 320 while (!frame_timing_.empty()) { |
321 FrameTiming timing = frame_timing_.front(); | 321 FrameTiming timing = frame_timing_.front(); |
322 if (time_sent_in_ms - timing.capture_ms < kEncodingTimeMeasureWindowMs) | 322 if (time_sent_in_us - timing.capture_us < |
| 323 kEncodingTimeMeasureWindowMs * rtc::kNumMicrosecsPerMillisec) |
323 break; | 324 break; |
324 if (timing.last_send_ms != -1) { | 325 if (timing.last_send_us != -1) { |
325 int encode_duration_ms = | 326 int encode_duration_us = |
326 static_cast<int>(timing.last_send_ms - timing.capture_ms); | 327 static_cast<int>(timing.last_send_us - timing.capture_us); |
327 if (encoder_timing_) { | 328 if (encoder_timing_) { |
328 encoder_timing_->OnEncodeTiming(timing.capture_ntp_ms, | 329 // TODO(nisse): Update encoder_timing_ to also use us units. |
329 encode_duration_ms); | 330 encoder_timing_->OnEncodeTiming(timing.capture_time_us / |
| 331 rtc::kNumMicrosecsPerMillisec, |
| 332 encode_duration_us / |
| 333 rtc::kNumMicrosecsPerMillisec); |
330 } | 334 } |
331 if (last_processed_capture_time_ms_ != -1) { | 335 if (last_processed_capture_time_us_ != -1) { |
332 int64_t diff_ms = timing.capture_ms - last_processed_capture_time_ms_; | 336 int64_t diff_us = timing.capture_us - last_processed_capture_time_us_; |
333 usage_->AddSample(encode_duration_ms, diff_ms); | 337 usage_->AddSample(1e-3 * encode_duration_us, 1e-3 * diff_us); |
334 } | 338 } |
335 last_processed_capture_time_ms_ = timing.capture_ms; | 339 last_processed_capture_time_us_ = timing.capture_us; |
336 EncodedFrameTimeMeasured(encode_duration_ms); | 340 EncodedFrameTimeMeasured(encode_duration_us / |
| 341 rtc::kNumMicrosecsPerMillisec); |
337 } | 342 } |
338 frame_timing_.pop_front(); | 343 frame_timing_.pop_front(); |
339 } | 344 } |
340 } | 345 } |
341 | 346 |
342 void OveruseFrameDetector::CheckForOveruse() { | 347 void OveruseFrameDetector::CheckForOveruse() { |
343 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); | 348 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); |
344 ++num_process_times_; | 349 ++num_process_times_; |
345 if (num_process_times_ <= options_.min_process_count || !metrics_) | 350 if (num_process_times_ <= options_.min_process_count || !metrics_) |
346 return; | 351 return; |
347 | 352 |
348 int64_t now = clock_->TimeInMilliseconds(); | 353 int64_t now_ms = rtc::TimeMillis(); |
349 | 354 |
350 if (IsOverusing(*metrics_)) { | 355 if (IsOverusing(*metrics_)) { |
351 // If the last thing we did was going up, and now have to back down, we need | 356 // If the last thing we did was going up, and now have to back down, we need |
352 // to check if this peak was short. If so we should back off to avoid going | 357 // to check if this peak was short. If so we should back off to avoid going |
353 // back and forth between this load, the system doesn't seem to handle it. | 358 // back and forth between this load, the system doesn't seem to handle it. |
354 bool check_for_backoff = last_rampup_time_ms_ > last_overuse_time_ms_; | 359 bool check_for_backoff = last_rampup_time_ms_ > last_overuse_time_ms_; |
355 if (check_for_backoff) { | 360 if (check_for_backoff) { |
356 if (now - last_rampup_time_ms_ < kStandardRampUpDelayMs || | 361 if (now_ms - last_rampup_time_ms_ < kStandardRampUpDelayMs || |
357 num_overuse_detections_ > kMaxOverusesBeforeApplyRampupDelay) { | 362 num_overuse_detections_ > kMaxOverusesBeforeApplyRampupDelay) { |
358 // Going up was not ok for very long, back off. | 363 // Going up was not ok for very long, back off. |
359 current_rampup_delay_ms_ *= kRampUpBackoffFactor; | 364 current_rampup_delay_ms_ *= kRampUpBackoffFactor; |
360 if (current_rampup_delay_ms_ > kMaxRampUpDelayMs) | 365 if (current_rampup_delay_ms_ > kMaxRampUpDelayMs) |
361 current_rampup_delay_ms_ = kMaxRampUpDelayMs; | 366 current_rampup_delay_ms_ = kMaxRampUpDelayMs; |
362 } else { | 367 } else { |
363 // Not currently backing off, reset rampup delay. | 368 // Not currently backing off, reset rampup delay. |
364 current_rampup_delay_ms_ = kStandardRampUpDelayMs; | 369 current_rampup_delay_ms_ = kStandardRampUpDelayMs; |
365 } | 370 } |
366 } | 371 } |
367 | 372 |
368 last_overuse_time_ms_ = now; | 373 last_overuse_time_ms_ = now_ms; |
369 in_quick_rampup_ = false; | 374 in_quick_rampup_ = false; |
370 checks_above_threshold_ = 0; | 375 checks_above_threshold_ = 0; |
371 ++num_overuse_detections_; | 376 ++num_overuse_detections_; |
372 | 377 |
373 if (observer_) | 378 if (observer_) |
374 observer_->ScaleDown(kScaleReasonCpu); | 379 observer_->ScaleDown(kScaleReasonCpu); |
375 } else if (IsUnderusing(*metrics_, now)) { | 380 } else if (IsUnderusing(*metrics_, now_ms)) { |
376 last_rampup_time_ms_ = now; | 381 last_rampup_time_ms_ = now_ms; |
377 in_quick_rampup_ = true; | 382 in_quick_rampup_ = true; |
378 | 383 |
379 if (observer_) | 384 if (observer_) |
380 observer_->ScaleUp(kScaleReasonCpu); | 385 observer_->ScaleUp(kScaleReasonCpu); |
381 } | 386 } |
382 | 387 |
383 int rampup_delay = | 388 int rampup_delay = |
384 in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_; | 389 in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_; |
385 | 390 |
386 LOG(LS_VERBOSE) << " Frame stats: " | 391 LOG(LS_VERBOSE) << " Frame stats: " |
(...skipping 17 matching lines...) Expand all Loading... |
404 int64_t time_now) { | 409 int64_t time_now) { |
405 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); | 410 RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); |
406 int delay = in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_; | 411 int delay = in_quick_rampup_ ? kQuickRampUpDelayMs : current_rampup_delay_ms_; |
407 if (time_now < last_rampup_time_ms_ + delay) | 412 if (time_now < last_rampup_time_ms_ + delay) |
408 return false; | 413 return false; |
409 | 414 |
410 return metrics.encode_usage_percent < | 415 return metrics.encode_usage_percent < |
411 options_.low_encode_usage_threshold_percent; | 416 options_.low_encode_usage_threshold_percent; |
412 } | 417 } |
413 } // namespace webrtc | 418 } // namespace webrtc |
OLD | NEW |