Ensure loss-based controller is always enabled.

The new default parameters are the ones that were used in the Chrome
Finch trial. The deleted unit test is invalidated by these changes.

Bug: chromium:941413
Change-Id: I597f4b0defaebe5bb3a6710b071fae2ee5c6f461
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/160652
Commit-Queue: Jonas Olsson <jonasolsson@webrtc.org>
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30049}
This commit is contained in:
Jonas Olsson
2019-12-10 10:43:55 +01:00
committed by Commit Bot
parent 565c05888d
commit 60ec3703cd
5 changed files with 73 additions and 233 deletions

View File

@ -71,56 +71,6 @@ CallClient* CreateVideoSendingClient(
s->CreateVideoStream(route->forward(), VideoStreamConfig());
return client;
}
void UpdatesTargetRateBasedOnLinkCapacity(std::string test_name = "") {
ScopedFieldTrials trial("WebRTC-SendSideBwe-WithOverhead/Enabled/");
auto factory = CreateFeedbackOnlyFactory();
Scenario s("googcc_unit/target_capacity" + test_name, false);
CallClientConfig config;
config.transport.cc_factory = &factory;
config.transport.rates.min_rate = DataRate::kbps(10);
config.transport.rates.max_rate = DataRate::kbps(1500);
config.transport.rates.start_rate = DataRate::kbps(300);
auto send_net = s.CreateMutableSimulationNode([](NetworkSimulationConfig* c) {
c->bandwidth = DataRate::kbps(500);
c->delay = TimeDelta::ms(100);
c->loss_rate = 0.0;
});
auto ret_net = s.CreateMutableSimulationNode(
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(100); });
StatesPrinter* truth = s.CreatePrinter(
"send.truth.txt", TimeDelta::PlusInfinity(), {send_net->ConfigPrinter()});
auto* client = CreateVideoSendingClient(&s, config, {send_net->node()},
{ret_net->node()});
truth->PrintRow();
s.RunFor(TimeDelta::seconds(25));
truth->PrintRow();
EXPECT_NEAR(client->target_rate().kbps(), 450, 100);
send_net->UpdateConfig([](NetworkSimulationConfig* c) {
c->bandwidth = DataRate::kbps(800);
c->delay = TimeDelta::ms(100);
});
truth->PrintRow();
s.RunFor(TimeDelta::seconds(20));
truth->PrintRow();
EXPECT_NEAR(client->target_rate().kbps(), 750, 150);
send_net->UpdateConfig([](NetworkSimulationConfig* c) {
c->bandwidth = DataRate::kbps(100);
c->delay = TimeDelta::ms(200);
});
ret_net->UpdateConfig(
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(200); });
truth->PrintRow();
s.RunFor(TimeDelta::seconds(50));
truth->PrintRow();
EXPECT_NEAR(client->target_rate().kbps(), 90, 25);
}
} // namespace
class GoogCcNetworkControllerTest : public ::testing::Test {
@ -416,7 +366,53 @@ TEST_F(GoogCcNetworkControllerTest, LimitsToFloorIfRttIsHighInTrial) {
}
TEST_F(GoogCcNetworkControllerTest, UpdatesTargetRateBasedOnLinkCapacity) {
UpdatesTargetRateBasedOnLinkCapacity();
ScopedFieldTrials trial("WebRTC-SendSideBwe-WithOverhead/Enabled/");
auto factory = CreateFeedbackOnlyFactory();
Scenario s("googcc_unit/target_capacity", false);
CallClientConfig config;
config.transport.cc_factory = &factory;
config.transport.rates.min_rate = DataRate::kbps(10);
config.transport.rates.max_rate = DataRate::kbps(1500);
config.transport.rates.start_rate = DataRate::kbps(300);
auto send_net = s.CreateMutableSimulationNode([](NetworkSimulationConfig* c) {
c->bandwidth = DataRate::kbps(500);
c->delay = TimeDelta::ms(100);
c->loss_rate = 0.0;
});
auto ret_net = s.CreateMutableSimulationNode(
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(100); });
StatesPrinter* truth = s.CreatePrinter(
"send.truth.txt", TimeDelta::PlusInfinity(), {send_net->ConfigPrinter()});
auto* client = CreateVideoSendingClient(&s, config, {send_net->node()},
{ret_net->node()});
truth->PrintRow();
s.RunFor(TimeDelta::seconds(25));
truth->PrintRow();
EXPECT_NEAR(client->target_rate().kbps(), 450, 100);
send_net->UpdateConfig([](NetworkSimulationConfig* c) {
c->bandwidth = DataRate::kbps(800);
c->delay = TimeDelta::ms(100);
});
truth->PrintRow();
s.RunFor(TimeDelta::seconds(20));
truth->PrintRow();
EXPECT_NEAR(client->target_rate().kbps(), 750, 150);
send_net->UpdateConfig([](NetworkSimulationConfig* c) {
c->bandwidth = DataRate::kbps(100);
c->delay = TimeDelta::ms(200);
});
ret_net->UpdateConfig(
[](NetworkSimulationConfig* c) { c->delay = TimeDelta::ms(200); });
truth->PrintRow();
s.RunFor(TimeDelta::seconds(50));
truth->PrintRow();
EXPECT_NEAR(client->target_rate().kbps(), 90, 25);
}
TEST_F(GoogCcNetworkControllerTest, StableEstimateDoesNotVaryInSteadyState) {
@ -456,16 +452,7 @@ TEST_F(GoogCcNetworkControllerTest, StableEstimateDoesNotVaryInSteadyState) {
EXPECT_GE(min_stable_target / max_stable_target, min_target / max_target);
}
TEST_F(GoogCcNetworkControllerTest,
LossBasedControlUpdatesTargetRateBasedOnLinkCapacity) {
ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/");
// TODO(srte): Should the behavior be unaffected at low loss rates?
UpdatesTargetRateBasedOnLinkCapacity("_loss_based");
}
TEST_F(GoogCcNetworkControllerTest,
LossBasedControlDoesModestBackoffToHighLoss) {
ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/");
TEST_F(GoogCcNetworkControllerTest, DoesModestBackoffToHighLoss) {
Scenario s("googcc_unit/high_loss_channel", false);
CallClientConfig config;
config.transport.rates.min_rate = DataRate::kbps(10);
@ -482,12 +469,11 @@ TEST_F(GoogCcNetworkControllerTest,
auto* client = CreateVideoSendingClient(&s, config, {send_net}, {ret_net});
s.RunFor(TimeDelta::seconds(120));
// Without LossBasedControl trial, bandwidth drops to ~10 kbps.
EXPECT_GT(client->target_rate().kbps(), 100);
}
DataRate AverageBitrateAfterCrossInducedLoss(std::string name) {
Scenario s(name, false);
TEST_F(GoogCcNetworkControllerTest, RecoversAfterCrossInducedLoss) {
Scenario s("googcc_unit/cross_loss_based", false);
NetworkSimulationConfig net_conf;
net_conf.bandwidth = DataRate::kbps(1000);
net_conf.delay = TimeDelta::ms(100);
@ -513,33 +499,16 @@ DataRate AverageBitrateAfterCrossInducedLoss(std::string name) {
s.net()->StopCrossTraffic(tcp_traffic);
s.RunFor(TimeDelta::seconds(20));
}
return DataSize::bytes(video->receive()
->GetStats()
.rtp_stats.packet_counter.TotalBytes()) /
s.TimeSinceStart();
}
TEST_F(GoogCcNetworkControllerTest,
NoLossBasedRecoversSlowerAfterCrossInducedLoss) {
// This test acts as a reference for the test below, showing that wihtout the
// trial, we have worse behavior.
DataRate average_bitrate =
AverageBitrateAfterCrossInducedLoss("googcc_unit/no_cross_loss_based");
RTC_DCHECK_LE(average_bitrate, DataRate::kbps(650));
DataSize::bytes(
video->receive()->GetStats().rtp_stats.packet_counter.TotalBytes()) /
s.TimeSinceStart();
// We recover bitrate when subject to loss spikes from cross traffic.
RTC_DCHECK_GE(average_bitrate, DataRate::kbps(720));
}
TEST_F(GoogCcNetworkControllerTest,
LossBasedRecoversFasterAfterCrossInducedLoss) {
// We recover bitrate better when subject to loss spikes from cross traffic
// when loss based controller is used.
ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/");
DataRate average_bitrate =
AverageBitrateAfterCrossInducedLoss("googcc_unit/cross_loss_based");
RTC_DCHECK_GE(average_bitrate, DataRate::kbps(750));
}
TEST_F(GoogCcNetworkControllerTest, LossBasedEstimatorCapsRateAtModerateLoss) {
ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/");
TEST_F(GoogCcNetworkControllerTest, CapsRateAtModerateLoss) {
Scenario s("googcc_unit/moderate_loss_channel", false);
CallClientConfig config;
config.transport.rates.min_rate = DataRate::kbps(10);
@ -560,13 +529,11 @@ TEST_F(GoogCcNetworkControllerTest, LossBasedEstimatorCapsRateAtModerateLoss) {
s.CreateVideoStream(route->forward(), VideoStreamConfig());
// Allow the controller to stabilize at the lower bitrate.
s.RunFor(TimeDelta::seconds(1));
// This increase in capacity would cause the target bitrate to increase to
// over 4000 kbps without LossBasedControl.
send_net->UpdateConfig(
[](NetworkSimulationConfig* c) { c->bandwidth = DataRate::kbps(5000); });
s.RunFor(TimeDelta::seconds(20));
// Using LossBasedControl, the bitrate will not increase over 2500 kbps since
// we have detected moderate loss.
// The bitrate will not increase over 2500 kbps since we have detected
// moderate loss.
EXPECT_LT(client->target_rate().kbps(), 2500);
}
@ -695,7 +662,6 @@ TEST_F(GoogCcNetworkControllerTest,
}
TEST_F(GoogCcNetworkControllerTest, NoBandwidthTogglingInLossControlTrial) {
ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/");
Scenario s("googcc_unit/no_toggling");
auto* send_net = s.CreateSimulationNode([&](NetworkSimulationConfig* c) {
c->bandwidth = DataRate::kbps(2000);

View File

@ -74,20 +74,19 @@ double ExponentialUpdate(TimeDelta window, TimeDelta interval) {
} // namespace
LossBasedControlConfig::LossBasedControlConfig()
: enabled(field_trial::IsEnabled(kBweLossBasedControl)),
min_increase_factor("min_incr", 1.02),
: min_increase_factor("min_incr", 1.02),
max_increase_factor("max_incr", 1.08),
increase_low_rtt("incr_low_rtt", TimeDelta::ms(200)),
increase_high_rtt("incr_high_rtt", TimeDelta::ms(800)),
decrease_factor("decr", 0.99),
decrease_factor("decr", 0.85),
loss_window("loss_win", TimeDelta::ms(800)),
loss_max_window("loss_max_win", TimeDelta::ms(800)),
acknowledged_rate_max_window("ackrate_max_win", TimeDelta::ms(800)),
increase_offset("incr_offset", DataRate::bps(1000)),
loss_bandwidth_balance_increase("balance_incr", DataRate::kbps(0.5)),
loss_bandwidth_balance_decrease("balance_decr", DataRate::kbps(4)),
loss_bandwidth_balance_exponent("exponent", 0.5),
allow_resets("resets", false),
loss_bandwidth_balance_increase("balance_incr", DataRate::kbps(5)),
loss_bandwidth_balance_decrease("balance_decr", DataRate::kbps(24)),
loss_bandwidth_balance_exponent("exponent", 0.7),
allow_resets("resets", true),
decrease_interval("decr_intvl", TimeDelta::ms(300)),
loss_report_timeout("timeout", TimeDelta::ms(6000)) {
std::string trial_string = field_trial::FindFullName(kBweLossBasedControl);

View File

@ -26,7 +26,6 @@ struct LossBasedControlConfig {
LossBasedControlConfig(const LossBasedControlConfig&);
LossBasedControlConfig& operator=(const LossBasedControlConfig&) = default;
~LossBasedControlConfig();
bool enabled;
FieldTrialParameter<double> min_increase_factor;
FieldTrialParameter<double> max_increase_factor;
FieldTrialParameter<TimeDelta> increase_low_rtt;
@ -54,7 +53,6 @@ class LossBasedBandwidthEstimation {
Timestamp at_time);
void MaybeReset(DataRate bitrate);
void SetInitialBitrate(DataRate bitrate);
bool Enabled() const { return config_.enabled; }
void UpdateLossStatistics(const std::vector<PacketResult>& packet_results,
Timestamp at_time);
DataRate GetEstimate() const { return loss_based_bitrate_; }

View File

@ -28,7 +28,6 @@
namespace webrtc {
namespace {
constexpr TimeDelta kBweIncreaseInterval = TimeDelta::Millis<1000>();
constexpr TimeDelta kBweDecreaseInterval = TimeDelta::Millis<300>();
constexpr TimeDelta kStartPhase = TimeDelta::Millis<2000>();
constexpr TimeDelta kBweConverganceTime = TimeDelta::Millis<20000>();
constexpr int kLimitNumPackets = 20;
@ -272,9 +271,8 @@ void SendSideBandwidthEstimation::SetSendBitrate(DataRate bitrate,
RTC_DCHECK_GT(bitrate, DataRate::Zero());
// Reset to avoid being capped by the estimate.
delay_based_limit_ = DataRate::PlusInfinity();
if (loss_based_bandwidth_estimation_.Enabled()) {
loss_based_bandwidth_estimation_.MaybeReset(bitrate);
}
loss_based_bandwidth_estimation_.MaybeReset(bitrate);
UpdateTargetBitrate(bitrate, at_time);
// Clear last sent bitrate history so the new value can be used directly
// and not capped.
@ -325,7 +323,7 @@ void SendSideBandwidthEstimation::SetAcknowledgedRate(
absl::optional<DataRate> acknowledged_rate,
Timestamp at_time) {
acknowledged_rate_ = acknowledged_rate;
if (acknowledged_rate && loss_based_bandwidth_estimation_.Enabled()) {
if (acknowledged_rate) {
loss_based_bandwidth_estimation_.UpdateAcknowledgedBitrate(
*acknowledged_rate, at_time);
}
@ -333,10 +331,8 @@ void SendSideBandwidthEstimation::SetAcknowledgedRate(
void SendSideBandwidthEstimation::IncomingPacketFeedbackVector(
const TransportPacketsFeedback& report) {
if (loss_based_bandwidth_estimation_.Enabled()) {
loss_based_bandwidth_estimation_.UpdateLossStatistics(
report.packet_feedbacks, report.feedback_time);
}
loss_based_bandwidth_estimation_.UpdateLossStatistics(report.packet_feedbacks,
report.feedback_time);
}
void SendSideBandwidthEstimation::UpdatePacketsLost(int packets_lost,
@ -440,18 +436,11 @@ void SendSideBandwidthEstimation::UpdateEstimate(Timestamp at_time) {
new_bitrate = std::max(receiver_limit_, new_bitrate);
if (delay_based_limit_.IsFinite())
new_bitrate = std::max(delay_based_limit_, new_bitrate);
if (loss_based_bandwidth_estimation_.Enabled()) {
loss_based_bandwidth_estimation_.SetInitialBitrate(new_bitrate);
}
loss_based_bandwidth_estimation_.SetInitialBitrate(new_bitrate);
if (new_bitrate != current_target_) {
min_bitrate_history_.clear();
if (loss_based_bandwidth_estimation_.Enabled()) {
min_bitrate_history_.push_back(std::make_pair(at_time, new_bitrate));
} else {
min_bitrate_history_.push_back(
std::make_pair(at_time, current_target_));
}
min_bitrate_history_.push_back(std::make_pair(at_time, new_bitrate));
UpdateTargetBitrate(new_bitrate, at_time);
return;
}
@ -464,68 +453,10 @@ void SendSideBandwidthEstimation::UpdateEstimate(Timestamp at_time) {
return;
}
if (loss_based_bandwidth_estimation_.Enabled()) {
loss_based_bandwidth_estimation_.Update(
at_time, min_bitrate_history_.front().second, last_round_trip_time_);
DataRate new_bitrate = MaybeRampupOrBackoff(current_target_, at_time);
UpdateTargetBitrate(new_bitrate, at_time);
return;
}
TimeDelta time_since_loss_packet_report = at_time - last_loss_packet_report_;
if (time_since_loss_packet_report < 1.2 * kMaxRtcpFeedbackInterval) {
// We only care about loss above a given bitrate threshold.
float loss = last_fraction_loss_ / 256.0f;
// We only make decisions based on loss when the bitrate is above a
// threshold. This is a crude way of handling loss which is uncorrelated
// to congestion.
if (current_target_ < bitrate_threshold_ || loss <= low_loss_threshold_) {
// Loss < 2%: Increase rate by 8% of the min bitrate in the last
// kBweIncreaseInterval.
// Note that by remembering the bitrate over the last second one can
// rampup up one second faster than if only allowed to start ramping
// at 8% per second rate now. E.g.:
// If sending a constant 100kbps it can rampup immediately to 108kbps
// whenever a receiver report is received with lower packet loss.
// If instead one would do: current_bitrate_ *= 1.08^(delta time),
// it would take over one second since the lower packet loss to achieve
// 108kbps.
DataRate new_bitrate =
DataRate::bps(min_bitrate_history_.front().second.bps() * 1.08 + 0.5);
// Add 1 kbps extra, just to make sure that we do not get stuck
// (gives a little extra increase at low rates, negligible at higher
// rates).
new_bitrate += DataRate::bps(1000);
UpdateTargetBitrate(new_bitrate, at_time);
return;
} else if (current_target_ > bitrate_threshold_) {
if (loss <= high_loss_threshold_) {
// Loss between 2% - 10%: Do nothing.
} else {
// Loss > 10%: Limit the rate decreases to once a kBweDecreaseInterval
// + rtt.
if (!has_decreased_since_last_fraction_loss_ &&
(at_time - time_last_decrease_) >=
(kBweDecreaseInterval + last_round_trip_time_)) {
time_last_decrease_ = at_time;
// Reduce rate:
// newRate = rate * (1 - 0.5*lossRate);
// where packetLoss = 256*lossRate;
DataRate new_bitrate =
DataRate::bps((current_target_.bps() *
static_cast<double>(512 - last_fraction_loss_)) /
512.0);
has_decreased_since_last_fraction_loss_ = true;
UpdateTargetBitrate(new_bitrate, at_time);
return;
}
}
}
}
// TODO(srte): This is likely redundant in most cases.
ApplyTargetLimits(at_time);
}
void SendSideBandwidthEstimation::UpdatePropagationRtt(
@ -580,8 +511,7 @@ DataRate SendSideBandwidthEstimation::MaybeRampupOrBackoff(DataRate new_bitrate,
DataRate SendSideBandwidthEstimation::GetUpperLimit() const {
DataRate upper_limit = std::min(delay_based_limit_, receiver_limit_);
upper_limit = std::min(upper_limit, max_bitrate_configured_);
if (loss_based_bandwidth_estimation_.Enabled() &&
loss_based_bandwidth_estimation_.GetEstimate() > DataRate::Zero()) {
if (loss_based_bandwidth_estimation_.GetEstimate() > DataRate::Zero()) {
upper_limit =
std::min(upper_limit, loss_based_bandwidth_estimation_.GetEstimate());
}

View File

@ -79,59 +79,6 @@ TEST(SendSideBweTest, InitialDelayBasedBweWithProbing) {
TestProbing(true);
}
TEST(SendSideBweTest, DoesntReapplyBitrateDecreaseWithoutFollowingRemb) {
MockRtcEventLog event_log;
EXPECT_CALL(event_log, LogProxy(LossBasedBweUpdateWithBitrateOnly()))
.Times(1);
EXPECT_CALL(event_log,
LogProxy(LossBasedBweUpdateWithBitrateAndLossFraction()))
.Times(1);
SendSideBandwidthEstimation bwe(&event_log);
static const int kMinBitrateBps = 100000;
static const int kInitialBitrateBps = 1000000;
int64_t now_ms = 1000;
bwe.SetMinMaxBitrate(DataRate::bps(kMinBitrateBps), DataRate::bps(1500000));
bwe.SetSendBitrate(DataRate::bps(kInitialBitrateBps), Timestamp::ms(now_ms));
static const uint8_t kFractionLoss = 128;
static const int64_t kRttMs = 50;
now_ms += 10000;
EXPECT_EQ(kInitialBitrateBps, bwe.target_rate().bps());
EXPECT_EQ(0, bwe.fraction_loss());
EXPECT_EQ(0, bwe.round_trip_time().ms());
// Signal heavy loss to go down in bitrate.
bwe.UpdatePacketsLost(/*packets_lost=*/50, /*number_of_packets=*/100,
Timestamp::ms(now_ms));
bwe.UpdateRtt(TimeDelta::ms(kRttMs), Timestamp::ms(now_ms));
// Trigger an update 2 seconds later to not be rate limited.
now_ms += 1000;
bwe.UpdateEstimate(Timestamp::ms(now_ms));
EXPECT_LT(bwe.target_rate().bps(), kInitialBitrateBps);
// Verify that the obtained bitrate isn't hitting the min bitrate, or this
// test doesn't make sense. If this ever happens, update the thresholds or
// loss rates so that it doesn't hit min bitrate after one bitrate update.
EXPECT_GT(bwe.target_rate().bps(), kMinBitrateBps);
EXPECT_EQ(kFractionLoss, bwe.fraction_loss());
EXPECT_EQ(kRttMs, bwe.round_trip_time().ms());
// Triggering an update shouldn't apply further downgrade nor upgrade since
// there's no intermediate receiver block received indicating whether this is
// currently good or not.
int last_bitrate_bps = bwe.target_rate().bps();
// Trigger an update 2 seconds later to not be rate limited (but it still
// shouldn't update).
now_ms += 1000;
bwe.UpdateEstimate(Timestamp::ms(now_ms));
EXPECT_EQ(last_bitrate_bps, bwe.target_rate().bps());
// The old loss rate should still be applied though.
EXPECT_EQ(kFractionLoss, bwe.fraction_loss());
EXPECT_EQ(kRttMs, bwe.round_trip_time().ms());
}
TEST(SendSideBweTest, SettingSendBitrateOverridesDelayBasedEstimate) {
::testing::NiceMock<MockRtcEventLog> event_log;
SendSideBandwidthEstimation bwe(&event_log);