From 5976bde2e6f5a3ece99b688e09284f4faa60f05f Mon Sep 17 00:00:00 2001 From: Christoffer Rodbro Date: Thu, 29 Nov 2018 17:12:52 +0100 Subject: [PATCH] Unittests for loss based bandwidth estimation. Bug: none Change-Id: I204071683c1c6e28040ea3bce900c4b04108cba7 Reviewed-on: https://webrtc-review.googlesource.com/c/112380 Commit-Queue: Christoffer Rodbro Reviewed-by: Sebastian Jansson Cr-Commit-Position: refs/heads/master@{#25844} --- .../loss_based_bandwidth_estimation.cc | 4 +- .../goog_cc_network_control_unittest.cc | 164 +++++++++++++----- test/scenario/simulated_time.cc | 3 +- 3 files changed, 120 insertions(+), 51 deletions(-) diff --git a/modules/bitrate_controller/loss_based_bandwidth_estimation.cc b/modules/bitrate_controller/loss_based_bandwidth_estimation.cc index 5d7f8aa2c3..f22f970321 100644 --- a/modules/bitrate_controller/loss_based_bandwidth_estimation.cc +++ b/modules/bitrate_controller/loss_based_bandwidth_estimation.cc @@ -156,9 +156,9 @@ void LossBasedBandwidthEstimation::UpdateAcknowledgedBitrate( if (acknowledged_bitrate > acknowledged_bitrate_max_) { acknowledged_bitrate_max_ = acknowledged_bitrate; } else { - acknowledged_bitrate_max_ += + acknowledged_bitrate_max_ -= ExponentialUpdate(config_.acknowledged_rate_max_window, time_passed) * - (acknowledged_bitrate - acknowledged_bitrate_max_); + (acknowledged_bitrate_max_ - acknowledged_bitrate); } } diff --git a/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc b/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc index fecd1b32d4..071fe0972a 100644 --- a/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc +++ b/modules/congestion_controller/goog_cc/goog_cc_network_control_unittest.cc @@ -28,6 +28,58 @@ namespace { const uint32_t kInitialBitrateKbps = 60; const DataRate kInitialBitrate = DataRate::kbps(kInitialBitrateKbps); const float kDefaultPacingRate = 2.5f; + +void UpdatesTargetRateBasedOnLinkCapacity(double loss_rate = 0.0) { + Scenario s("googcc_unit/target_capacity", false); + SimulatedTimeClientConfig config; + config.transport.cc = + TransportControllerConfig::CongestionController::kGoogCcFeedback; + config.transport.rates.min_rate = DataRate::kbps(10); + config.transport.rates.max_rate = DataRate::kbps(1500); + config.transport.rates.start_rate = DataRate::kbps(300); + NetworkNodeConfig net_conf; + auto send_net = s.CreateSimulationNode([loss_rate](NetworkNodeConfig* c) { + c->simulation.bandwidth = DataRate::kbps(500); + c->simulation.delay = TimeDelta::ms(100); + c->simulation.loss_rate = loss_rate; + c->update_frequency = TimeDelta::ms(5); + }); + auto ret_net = s.CreateSimulationNode([](NetworkNodeConfig* c) { + c->simulation.delay = TimeDelta::ms(100); + c->update_frequency = TimeDelta::ms(5); + }); + StatesPrinter* truth = s.CreatePrinter( + "send.truth.txt", TimeDelta::PlusInfinity(), {send_net->ConfigPrinter()}); + SimulatedTimeClient* client = s.CreateSimulatedTimeClient( + "send", config, {PacketStreamConfig()}, {send_net}, {ret_net}); + + truth->PrintRow(); + s.RunFor(TimeDelta::seconds(25)); + truth->PrintRow(); + EXPECT_NEAR(client->target_rate_kbps(), 450, 100); + + send_net->UpdateConfig([](NetworkNodeConfig* c) { + c->simulation.bandwidth = DataRate::kbps(800); + c->simulation.delay = TimeDelta::ms(100); + }); + + truth->PrintRow(); + s.RunFor(TimeDelta::seconds(20)); + truth->PrintRow(); + EXPECT_NEAR(client->target_rate_kbps(), 750, 150); + + send_net->UpdateConfig([](NetworkNodeConfig* c) { + c->simulation.bandwidth = DataRate::kbps(100); + c->simulation.delay = TimeDelta::ms(200); + }); + ret_net->UpdateConfig( + [](NetworkNodeConfig* c) { c->simulation.delay = TimeDelta::ms(200); }); + + truth->PrintRow(); + s.RunFor(TimeDelta::seconds(30)); + truth->PrintRow(); + EXPECT_NEAR(client->target_rate_kbps(), 90, 20); +} } // namespace class GoogCcNetworkControllerTest : public ::testing::Test { @@ -349,54 +401,7 @@ TEST_F(GoogCcNetworkControllerTest, LimitsToMinRateIfRttIsHighInTrial) { } TEST_F(GoogCcNetworkControllerTest, UpdatesTargetRateBasedOnLinkCapacity) { - Scenario s("googcc_unit/target_capacity", false); - SimulatedTimeClientConfig config; - config.transport.cc = - TransportControllerConfig::CongestionController::kGoogCcFeedback; - config.transport.rates.min_rate = DataRate::kbps(10); - config.transport.rates.max_rate = DataRate::kbps(1500); - config.transport.rates.start_rate = DataRate::kbps(300); - NetworkNodeConfig net_conf; - auto send_net = s.CreateSimulationNode([](NetworkNodeConfig* c) { - c->simulation.bandwidth = DataRate::kbps(500); - c->simulation.delay = TimeDelta::ms(100); - c->update_frequency = TimeDelta::ms(5); - }); - auto ret_net = s.CreateSimulationNode([](NetworkNodeConfig* c) { - c->simulation.delay = TimeDelta::ms(100); - c->update_frequency = TimeDelta::ms(5); - }); - StatesPrinter* truth = s.CreatePrinter( - "send.truth.txt", TimeDelta::PlusInfinity(), {send_net->ConfigPrinter()}); - SimulatedTimeClient* client = s.CreateSimulatedTimeClient( - "send", config, {PacketStreamConfig()}, {send_net}, {ret_net}); - - truth->PrintRow(); - s.RunFor(TimeDelta::seconds(25)); - truth->PrintRow(); - EXPECT_NEAR(client->target_rate_kbps(), 450, 100); - - send_net->UpdateConfig([](NetworkNodeConfig* c) { - c->simulation.bandwidth = DataRate::kbps(800); - c->simulation.delay = TimeDelta::ms(100); - }); - - truth->PrintRow(); - s.RunFor(TimeDelta::seconds(20)); - truth->PrintRow(); - EXPECT_NEAR(client->target_rate_kbps(), 750, 150); - - send_net->UpdateConfig([](NetworkNodeConfig* c) { - c->simulation.bandwidth = DataRate::kbps(100); - c->simulation.delay = TimeDelta::ms(200); - }); - ret_net->UpdateConfig( - [](NetworkNodeConfig* c) { c->simulation.delay = TimeDelta::ms(200); }); - - truth->PrintRow(); - s.RunFor(TimeDelta::seconds(30)); - truth->PrintRow(); - EXPECT_NEAR(client->target_rate_kbps(), 90, 20); + UpdatesTargetRateBasedOnLinkCapacity(); } TEST_F(GoogCcNetworkControllerTest, DefaultEstimateVariesInSteadyState) { @@ -455,5 +460,68 @@ TEST_F(GoogCcNetworkControllerTest, StableEstimateDoesNotVaryInSteadyState) { EXPECT_GT(min_estimate / max_estimate, 0.95); } +TEST_F(GoogCcNetworkControllerTest, + LossBasedControlUpdatesTargetRateBasedOnLinkCapacity) { + ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/"); + UpdatesTargetRateBasedOnLinkCapacity(/*loss_rate*/ 0.01); +} + +TEST_F(GoogCcNetworkControllerTest, + LossBasedControlDoesModestBackoffToHighLoss) { + ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/"); + Scenario s("googcc_unit/high_loss_channel", false); + SimulatedTimeClientConfig config; + config.transport.cc = + TransportControllerConfig::CongestionController::kGoogCcFeedback; + config.transport.rates.min_rate = DataRate::kbps(10); + config.transport.rates.max_rate = DataRate::kbps(1500); + config.transport.rates.start_rate = DataRate::kbps(300); + NetworkNodeConfig net_conf; + auto send_net = s.CreateSimulationNode([](NetworkNodeConfig* c) { + c->simulation.bandwidth = DataRate::kbps(2000); + c->simulation.delay = TimeDelta::ms(200); + c->simulation.loss_rate = 0.1; + c->update_frequency = TimeDelta::ms(5); + }); + auto ret_net = s.CreateSimulationNode([](NetworkNodeConfig* c) { + c->simulation.delay = TimeDelta::ms(200); + c->update_frequency = TimeDelta::ms(5); + }); + SimulatedTimeClient* client = s.CreateSimulatedTimeClient( + "send", config, {PacketStreamConfig()}, {send_net}, {ret_net}); + + s.RunFor(TimeDelta::seconds(120)); + // Without LossBasedControl trial, bandwidth drops to ~10 kbps. + EXPECT_GT(client->target_rate_kbps(), 100); +} + +TEST_F(GoogCcNetworkControllerTest, LossBasedEstimatorCapsRateAtModerateLoss) { + ScopedFieldTrials trial("WebRTC-Bwe-LossBasedControl/Enabled/"); + Scenario s("googcc_unit/moderate_loss_channel", false); + SimulatedTimeClientConfig config; + config.transport.cc = + TransportControllerConfig::CongestionController::kGoogCcFeedback; + config.transport.rates.min_rate = DataRate::kbps(10); + config.transport.rates.max_rate = DataRate::kbps(5000); + config.transport.rates.start_rate = DataRate::kbps(300); + NetworkNodeConfig net_conf; + auto send_net = s.CreateSimulationNode([](NetworkNodeConfig* c) { + c->simulation.bandwidth = DataRate::kbps(5000); + c->simulation.delay = TimeDelta::ms(100); + c->simulation.loss_rate = 0.02; + c->update_frequency = TimeDelta::ms(5); + }); + auto ret_net = s.CreateSimulationNode([](NetworkNodeConfig* c) { + c->simulation.delay = TimeDelta::ms(100); + c->update_frequency = TimeDelta::ms(5); + }); + SimulatedTimeClient* client = s.CreateSimulatedTimeClient( + "send", config, {PacketStreamConfig()}, {send_net}, {ret_net}); + + s.RunFor(TimeDelta::seconds(60)); + // Without LossBasedControl trial, bitrate reaches above 4 mbps. + EXPECT_NEAR(client->target_rate_kbps(), 2000, 500); +} + } // namespace test } // namespace webrtc diff --git a/test/scenario/simulated_time.cc b/test/scenario/simulated_time.cc index 9759533359..becd79367d 100644 --- a/test/scenario/simulated_time.cc +++ b/test/scenario/simulated_time.cc @@ -229,7 +229,8 @@ bool SimulatedFeedback::TryDeliverPacket(rtc::CopyOnWriteBuffer packet, it->second}); receive_times_.erase(it); } - if (receive_times_.size() >= RawFeedbackReportPacket::MAX_FEEDBACKS) { + if (report.receive_times.size() >= + RawFeedbackReportPacket::MAX_FEEDBACKS) { return_node_->TryDeliverPacket(FeedbackToBuffer(report), return_receiver_id_, at_time); report = SimpleFeedbackReportPacket();