Add configuration for ability to use the encode usage measure for triggering overuse/underuse.

BUG=1577
R=mflodman@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/10509004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@5767 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
asapersson@webrtc.org 2014-03-24 21:59:16 +00:00
parent b70c8e9dfd
commit ce12f1fd32
3 changed files with 132 additions and 12 deletions

View File

@ -66,6 +66,9 @@ struct CpuOveruseOptions {
: enable_capture_jitter_method(true),
low_capture_jitter_threshold_ms(kNormalUseStdDevMs),
high_capture_jitter_threshold_ms(kOveruseStdDevMs),
enable_encode_usage_method(false),
low_encode_usage_threshold_percent(60),
high_encode_usage_threshold_percent(90),
frame_timeout_interval_ms(1500),
min_frame_samples(120),
min_process_count(3),
@ -75,6 +78,10 @@ struct CpuOveruseOptions {
bool enable_capture_jitter_method;
float low_capture_jitter_threshold_ms; // Threshold for triggering underuse.
float high_capture_jitter_threshold_ms; // Threshold for triggering overuse.
// Method based on encode time of frames.
bool enable_encode_usage_method;
int low_encode_usage_threshold_percent; // Threshold for triggering underuse.
int high_encode_usage_threshold_percent; // Threshold for triggering overuse.
// General settings.
int frame_timeout_interval_ms; // The maximum allowed interval between two
// frames before resetting estimations.
@ -90,6 +97,11 @@ struct CpuOveruseOptions {
low_capture_jitter_threshold_ms == o.low_capture_jitter_threshold_ms &&
high_capture_jitter_threshold_ms ==
o.high_capture_jitter_threshold_ms &&
enable_encode_usage_method == o.enable_encode_usage_method &&
low_encode_usage_threshold_percent ==
o.low_encode_usage_threshold_percent &&
high_encode_usage_threshold_percent ==
o.high_encode_usage_threshold_percent &&
frame_timeout_interval_ms == o.frame_timeout_interval_ms &&
min_frame_samples == o.min_frame_samples &&
min_process_count == o.min_process_count &&

View File

@ -140,13 +140,27 @@ class OveruseFrameDetector::EncodeUsage {
EncodeUsage()
: kWeightFactorFrameDiff(0.998f),
kWeightFactorEncodeTime(0.995f),
kInitialSampleDiffMs(50.0f),
kMaxSampleDiffMs(66.0f),
count_(0),
filtered_encode_time_ms_(new VCMExpFilter(kWeightFactorEncodeTime)),
filtered_frame_diff_ms_(new VCMExpFilter(kWeightFactorFrameDiff)) {
filtered_encode_time_ms_->Apply(1.0f, kInitialAvgEncodeTimeMs);
filtered_frame_diff_ms_->Apply(1.0f, kSampleDiffMs);
Reset();
}
~EncodeUsage() {}
void SetOptions(const CpuOveruseOptions& options) {
options_ = options;
}
void Reset() {
count_ = 0;
filtered_frame_diff_ms_->Reset(kWeightFactorFrameDiff);
filtered_frame_diff_ms_->Apply(1.0f, kInitialSampleDiffMs);
filtered_encode_time_ms_->Reset(kWeightFactorEncodeTime);
filtered_encode_time_ms_->Apply(1.0f, InitialEncodeTimeMs());
}
void AddSample(float sample_ms) {
float exp = sample_ms / kSampleDiffMs;
exp = std::min(exp, kMaxExp);
@ -154,21 +168,40 @@ class OveruseFrameDetector::EncodeUsage {
}
void AddEncodeSample(float encode_time_ms, int64_t diff_last_sample_ms) {
++count_;
float exp = diff_last_sample_ms / kSampleDiffMs;
exp = std::min(exp, kMaxExp);
filtered_encode_time_ms_->Apply(exp, encode_time_ms);
}
int UsageInPercent() const {
if (count_ < static_cast<uint32_t>(options_.min_frame_samples)) {
return static_cast<int>(InitialUsageInPercent() + 0.5f);
}
float frame_diff_ms = std::max(filtered_frame_diff_ms_->Value(), 1.0f);
frame_diff_ms = std::min(frame_diff_ms, kMaxSampleDiffMs);
float encode_usage_percent =
100.0f * filtered_encode_time_ms_->Value() / frame_diff_ms;
return static_cast<int>(encode_usage_percent + 0.5);
}
float InitialUsageInPercent() const {
// Start in between the underuse and overuse threshold.
return (options_.low_encode_usage_threshold_percent +
options_.high_encode_usage_threshold_percent) / 2.0f;
}
float InitialEncodeTimeMs() const {
return InitialUsageInPercent() * kInitialSampleDiffMs / 100;
}
private:
const float kWeightFactorFrameDiff;
const float kWeightFactorEncodeTime;
const float kInitialSampleDiffMs;
const float kMaxSampleDiffMs;
uint64_t count_;
CpuOveruseOptions options_;
scoped_ptr<VCMExpFilter> filtered_encode_time_ms_;
scoped_ptr<VCMExpFilter> filtered_frame_diff_ms_;
};
@ -265,6 +298,7 @@ void OveruseFrameDetector::SetOptions(const CpuOveruseOptions& options) {
}
options_ = options;
capture_deltas_.SetOptions(options);
encode_usage_->SetOptions(options);
ResetAll(num_pixels_);
}
@ -315,6 +349,7 @@ bool OveruseFrameDetector::FrameTimeoutDetected(int64_t now) const {
void OveruseFrameDetector::ResetAll(int num_pixels) {
num_pixels_ = num_pixels;
capture_deltas_.Reset();
encode_usage_->Reset();
capture_queue_delay_->ClearFrames();
last_capture_time_ = 0;
num_process_times_ = 0;
@ -420,8 +455,15 @@ int32_t OveruseFrameDetector::Process() {
}
bool OveruseFrameDetector::IsOverusing() {
bool overusing = options_.enable_capture_jitter_method &&
(capture_deltas_.StdDev() >= options_.high_capture_jitter_threshold_ms);
bool overusing = false;
if (options_.enable_capture_jitter_method) {
overusing = capture_deltas_.StdDev() >=
options_.high_capture_jitter_threshold_ms;
} else if (options_.enable_encode_usage_method) {
overusing = encode_usage_->UsageInPercent() >=
options_.high_encode_usage_threshold_percent;
}
if (overusing) {
++checks_above_threshold_;
} else {
@ -435,8 +477,14 @@ bool OveruseFrameDetector::IsUnderusing(int64_t time_now) {
if (time_now < last_rampup_time_ + delay)
return false;
bool underusing = options_.enable_capture_jitter_method &&
(capture_deltas_.StdDev() < options_.low_capture_jitter_threshold_ms);
bool underusing = false;
if (options_.enable_capture_jitter_method) {
underusing = capture_deltas_.StdDev() <
options_.low_capture_jitter_threshold_ms;
} else if (options_.enable_encode_usage_method) {
underusing = encode_usage_->UsageInPercent() <
options_.low_encode_usage_threshold_percent;
}
return underusing;
}
} // namespace webrtc

View File

@ -66,6 +66,11 @@ class OveruseFrameDetectorTest : public ::testing::Test {
options_.high_capture_jitter_threshold_ms) / 2.0f) + 0.5;
}
int InitialEncodeUsage() {
return ((options_.low_encode_usage_threshold_percent +
options_.high_encode_usage_threshold_percent) / 2.0f) + 0.5;
}
void InsertFramesWithInterval(
size_t num_frames, int interval_ms, int width, int height) {
while (num_frames-- > 0) {
@ -74,6 +79,16 @@ class OveruseFrameDetectorTest : public ::testing::Test {
}
}
void InsertAndEncodeFramesWithInterval(
int num_frames, int interval_ms, int width, int height, int encode_ms) {
while (num_frames-- > 0) {
overuse_detector_->FrameCaptured(width, height);
clock_->AdvanceTimeMilliseconds(encode_ms);
overuse_detector_->FrameEncoded(encode_ms);
clock_->AdvanceTimeMilliseconds(interval_ms - encode_ms);
}
}
void TriggerOveruse(int num_times) {
for (int i = 0; i < num_times; ++i) {
InsertFramesWithInterval(200, kFrameInterval33ms, kWidth, kHeight);
@ -87,6 +102,22 @@ class OveruseFrameDetectorTest : public ::testing::Test {
overuse_detector_->Process();
}
void TriggerOveruseWithEncodeUsage(int num_times) {
const int kEncodeTimeMs = 32;
for (int i = 0; i < num_times; ++i) {
InsertAndEncodeFramesWithInterval(
1000, kFrameInterval33ms, kWidth, kHeight, kEncodeTimeMs);
overuse_detector_->Process();
}
}
void TriggerNormalUsageWithEncodeUsage() {
const int kEncodeTimeMs = 5;
InsertAndEncodeFramesWithInterval(
1000, kFrameInterval33ms, kWidth, kHeight, kEncodeTimeMs);
overuse_detector_->Process();
}
CpuOveruseOptions options_;
scoped_ptr<SimulatedClock> clock_;
scoped_ptr<MockCpuOveruseObserver> observer_;
@ -266,13 +297,42 @@ TEST_F(OveruseFrameDetectorTest, EncodedFrame) {
EXPECT_EQ(2, overuse_detector_->AvgEncodeTimeMs());
}
TEST_F(OveruseFrameDetectorTest, InitialEncodeUsage) {
EXPECT_EQ(InitialEncodeUsage(), overuse_detector_->EncodeUsagePercent());
}
TEST_F(OveruseFrameDetectorTest, EncodedUsage) {
for (int i = 0; i < 30; i++) {
overuse_detector_->FrameCaptured(kWidth, kHeight);
clock_->AdvanceTimeMilliseconds(5);
overuse_detector_->FrameEncoded(5);
clock_->AdvanceTimeMilliseconds(33-5);
}
const int kEncodeTimeMs = 5;
InsertAndEncodeFramesWithInterval(
1000, kFrameInterval33ms, kWidth, kHeight, kEncodeTimeMs);
EXPECT_EQ(15, overuse_detector_->EncodeUsagePercent());
}
TEST_F(OveruseFrameDetectorTest, EncodeUsageResetAfterChangingThreshold) {
EXPECT_EQ(InitialEncodeUsage(), overuse_detector_->EncodeUsagePercent());
options_.high_encode_usage_threshold_percent = 100;
overuse_detector_->SetOptions(options_);
EXPECT_EQ(InitialEncodeUsage(), overuse_detector_->EncodeUsagePercent());
options_.low_encode_usage_threshold_percent = 20;
overuse_detector_->SetOptions(options_);
EXPECT_EQ(InitialEncodeUsage(), overuse_detector_->EncodeUsagePercent());
}
TEST_F(OveruseFrameDetectorTest, TriggerOveruseWithEncodeUsage) {
options_.enable_capture_jitter_method = false;
options_.enable_encode_usage_method = true;
overuse_detector_->SetOptions(options_);
EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
TriggerOveruseWithEncodeUsage(options_.high_threshold_consecutive_count);
}
TEST_F(OveruseFrameDetectorTest, OveruseAndRecoverWithEncodeUsage) {
options_.enable_capture_jitter_method = false;
options_.enable_encode_usage_method = true;
overuse_detector_->SetOptions(options_);
EXPECT_CALL(*(observer_.get()), OveruseDetected()).Times(1);
TriggerOveruseWithEncodeUsage(options_.high_threshold_consecutive_count);
EXPECT_CALL(*(observer_.get()), NormalUsage()).Times(testing::AtLeast(1));
TriggerNormalUsageWithEncodeUsage();
}
} // namespace webrtc