Index: webrtc/video/overuse_frame_detector.cc |
diff --git a/webrtc/video/overuse_frame_detector.cc b/webrtc/video/overuse_frame_detector.cc |
index 68b98a444cac2df6b71711c728266a8eb0ea4d1c..42ee350257f03225ac39aee2062d0ba47f704f05 100644 |
--- a/webrtc/video/overuse_frame_detector.cc |
+++ b/webrtc/video/overuse_frame_detector.cc |
@@ -16,12 +16,15 @@ |
#include <algorithm> |
#include <list> |
#include <map> |
+#include <string> |
+#include <utility> |
#include "webrtc/api/video/video_frame.h" |
#include "webrtc/base/checks.h" |
#include "webrtc/base/logging.h" |
#include "webrtc/base/numerics/exp_filter.h" |
#include "webrtc/common_video/include/frame_callback.h" |
+#include "webrtc/system_wrappers/include/field_trial.h" |
#if defined(WEBRTC_MAC) && !defined(WEBRTC_IOS) |
#include <mach/mach.h> |
@@ -116,7 +119,7 @@ class OveruseFrameDetector::SendProcessingUsage { |
filtered_frame_diff_ms_(new rtc::ExpFilter(kWeightFactorFrameDiff)) { |
Reset(); |
} |
- ~SendProcessingUsage() {} |
+ virtual ~SendProcessingUsage() {} |
void Reset() { |
count_ = 0; |
@@ -139,7 +142,7 @@ class OveruseFrameDetector::SendProcessingUsage { |
filtered_processing_ms_->Apply(exp, processing_ms); |
} |
- int Value() const { |
+ virtual int Value() { |
if (count_ < static_cast<uint32_t>(options_.min_frame_samples)) { |
return static_cast<int>(InitialUsageInPercent() + 0.5f); |
} |
@@ -171,6 +174,117 @@ class OveruseFrameDetector::SendProcessingUsage { |
std::unique_ptr<rtc::ExpFilter> filtered_frame_diff_ms_; |
}; |
+// Class used for manual testing of overuse, enabled via field trial flag. |
+class OveruseFrameDetector::OverdoseInjector |
+ : public OveruseFrameDetector::SendProcessingUsage { |
+ public: |
+ OverdoseInjector(const CpuOveruseOptions& options, |
+ int64_t normal_period_ms, |
+ int64_t overuse_period_ms, |
+ int64_t underuse_period_ms) |
+ : OveruseFrameDetector::SendProcessingUsage(options), |
+ normal_period_ms_(normal_period_ms), |
+ overuse_period_ms_(overuse_period_ms), |
+ underuse_period_ms_(underuse_period_ms), |
+ state_(State::kNormal), |
+ last_toggling_ms_(-1) { |
+ RTC_DCHECK_GT(overuse_period_ms, 0); |
+ RTC_DCHECK_GT(normal_period_ms, 0); |
+ LOG(LS_INFO) << "Simulating overuse with intervals " << normal_period_ms |
+ << "ms normal mode, " << overuse_period_ms |
+ << "ms overuse mode."; |
+ } |
+ |
+ ~OverdoseInjector() override {} |
+ |
+ int Value() override { |
+ int64_t now_ms = rtc::TimeMillis(); |
+ if (last_toggling_ms_ == -1) { |
+ last_toggling_ms_ = now_ms; |
+ } else { |
+ switch (state_) { |
+ case State::kNormal: |
+ if (now_ms > last_toggling_ms_ + normal_period_ms_) { |
+ state_ = State::kOveruse; |
+ last_toggling_ms_ = now_ms; |
+ LOG(LS_INFO) << "Simulating CPU overuse."; |
+ } |
+ break; |
+ case State::kOveruse: |
+ if (now_ms > last_toggling_ms_ + overuse_period_ms_) { |
+ state_ = State::kUnderuse; |
+ last_toggling_ms_ = now_ms; |
+ LOG(LS_INFO) << "Simulating CPU underuse."; |
+ } |
+ break; |
+ case State::kUnderuse: |
+ if (now_ms > last_toggling_ms_ + underuse_period_ms_) { |
+ state_ = State::kNormal; |
+ last_toggling_ms_ = now_ms; |
+ LOG(LS_INFO) << "Actual CPU overuse measurements in effect."; |
+ } |
+ break; |
+ } |
+ } |
+ |
+ rtc::Optional<int> overried_usage_value; |
+ switch (state_) { |
+ case State::kNormal: |
+ break; |
+ case State::kOveruse: |
+ overried_usage_value.emplace(250); |
+ break; |
+ case State::kUnderuse: |
+ overried_usage_value.emplace(5); |
+ break; |
+ } |
+ |
+ return overried_usage_value.value_or(SendProcessingUsage::Value()); |
+ } |
+ |
+ private: |
+ const int64_t normal_period_ms_; |
+ const int64_t overuse_period_ms_; |
+ const int64_t underuse_period_ms_; |
+ enum class State { kNormal, kOveruse, kUnderuse } state_; |
+ int64_t last_toggling_ms_; |
+}; |
+ |
+std::unique_ptr<OveruseFrameDetector::SendProcessingUsage> |
+OveruseFrameDetector::CreateSendProcessingUsage( |
+ const CpuOveruseOptions& options) { |
+ std::unique_ptr<SendProcessingUsage> instance; |
+ std::string toggling_interval = |
+ field_trial::FindFullName("WebRTC-ForceSimulatedOveruseIntervalMs"); |
+ if (!toggling_interval.empty()) { |
+ int normal_period_ms = 0; |
+ int overuse_period_ms = 0; |
+ int underuse_period_ms = 0; |
+ if (sscanf(toggling_interval.c_str(), "%d-%d-%d", &normal_period_ms, |
+ &overuse_period_ms, &underuse_period_ms) == 3) { |
+ if (normal_period_ms > 0 && overuse_period_ms > 0 && |
+ underuse_period_ms > 0) { |
+ instance.reset(new OverdoseInjector( |
+ options, normal_period_ms, overuse_period_ms, underuse_period_ms)); |
+ } else { |
+ LOG(LS_WARNING) |
+ << "Invalid (non-positive) normal/overuse/underuse periods: " |
+ << normal_period_ms << " / " << overuse_period_ms << " / " |
+ << underuse_period_ms; |
+ } |
+ } else { |
+ LOG(LS_WARNING) << "Malformed toggling interval: " << toggling_interval; |
+ } |
+ } |
+ |
+ if (!instance) { |
+ // No valid overuse simulation parameters set, use normal usage class. |
+ instance.reset(new SendProcessingUsage(options)); |
+ } |
+ |
+ return instance; |
+} |
+ |
class OveruseFrameDetector::CheckOveruseTask : public rtc::QueuedTask { |
public: |
explicit CheckOveruseTask(OveruseFrameDetector* overuse_detector) |
@@ -222,7 +336,7 @@ OveruseFrameDetector::OveruseFrameDetector( |
last_rampup_time_ms_(-1), |
in_quick_rampup_(false), |
current_rampup_delay_ms_(kStandardRampUpDelayMs), |
- usage_(new SendProcessingUsage(options)) { |
+ usage_(CreateSendProcessingUsage(options)) { |
task_checker_.Detach(); |
} |
@@ -320,8 +434,9 @@ void OveruseFrameDetector::FrameSent(uint32_t timestamp, |
while (!frame_timing_.empty()) { |
FrameTiming timing = frame_timing_.front(); |
if (time_sent_in_us - timing.capture_us < |
- kEncodingTimeMeasureWindowMs * rtc::kNumMicrosecsPerMillisec) |
+ kEncodingTimeMeasureWindowMs * rtc::kNumMicrosecsPerMillisec) { |
break; |
+ } |
if (timing.last_send_us != -1) { |
int encode_duration_us = |
static_cast<int>(timing.last_send_us - timing.capture_us); |
@@ -396,6 +511,7 @@ void OveruseFrameDetector::CheckForOveruse() { |
bool OveruseFrameDetector::IsOverusing(const CpuOveruseMetrics& metrics) { |
RTC_DCHECK_CALLED_SEQUENTIALLY(&task_checker_); |
+ |
if (metrics.encode_usage_percent >= |
options_.high_encode_usage_threshold_percent) { |
++checks_above_threshold_; |