From 43e11c881b50ffd307cca5c0ab05d789066f4e95 Mon Sep 17 00:00:00 2001 From: Per Kjellander Date: Tue, 30 Aug 2022 20:43:51 +0200 Subject: [PATCH] Field trials for ProbeController when a network state estimate is known. Ensure initial second probe can be disabled. Can configure separate probe duration if the network state estimate is known. Can probe immediately if network state estimate increase more than a factor Bug: webrtc:14392 Change-Id: Iefb980f0b10c7c51db62793c3bd3f187fc67593d Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/273349 Reviewed-by: Diep Bui Commit-Queue: Per Kjellander Cr-Commit-Position: refs/heads/main@{#37966} --- .../goog_cc/probe_controller.cc | 33 ++++++-- .../goog_cc/probe_controller.h | 7 ++ .../goog_cc/probe_controller_unittest.cc | 84 +++++++++++++++++++ 3 files changed, 119 insertions(+), 5 deletions(-) diff --git a/modules/congestion_controller/goog_cc/probe_controller.cc b/modules/congestion_controller/goog_cc/probe_controller.cc index 23dc0d47d6..e60c72224d 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.cc +++ b/modules/congestion_controller/goog_cc/probe_controller.cc @@ -24,7 +24,6 @@ #include "logging/rtc_event_log/events/rtc_event_probe_cluster_created.h" #include "rtc_base/checks.h" #include "rtc_base/logging.h" -#include "rtc_base/numerics/safe_conversions.h" #include "system_wrappers/include/metrics.h" namespace webrtc { @@ -88,7 +87,12 @@ ProbeControllerConfig::ProbeControllerConfig( alr_probe_scale("alr_scale", 2), network_state_estimate_probing_interval("network_state_interval", TimeDelta::PlusInfinity()), + network_state_estimate_fast_rampup_rate("network_state_fast_rampup_rate", + 0), network_state_probe_scale("network_state_scale", 1.0), + network_state_probe_duration("network_state_probe_duration", + TimeDelta::Millis(15)), + first_allocation_probe_scale("alloc_p1", 1), second_allocation_probe_scale("alloc_p2", 2), allocation_allow_further_probing("alloc_probe_further", false), @@ -103,7 +107,8 @@ ProbeControllerConfig::ProbeControllerConfig( &alr_probing_interval, &alr_probe_scale, &first_allocation_probe_scale, &second_allocation_probe_scale, &allocation_allow_further_probing, &min_probe_duration, &network_state_estimate_probing_interval, - &network_state_probe_scale, &probe_if_bwe_limited_due_to_loss}, + &network_state_estimate_fast_rampup_rate, &network_state_probe_scale, + &network_state_probe_duration, &probe_if_bwe_limited_due_to_loss}, key_value_config->Lookup("WebRTC-Bwe-ProbingConfiguration")); // Specialized keys overriding subsets of WebRTC-Bwe-ProbingConfiguration @@ -249,7 +254,8 @@ std::vector ProbeController::InitiateExponentialProbing( // 1.2 Mbps to continue probing. std::vector probes = {config_.first_exponential_probe_scale * start_bitrate_}; - if (config_.second_exponential_probe_scale) { + if (config_.second_exponential_probe_scale && + config_.second_exponential_probe_scale.GetOptional().value() > 0) { probes.push_back(config_.second_exponential_probe_scale.Value() * start_bitrate_); } @@ -350,6 +356,14 @@ void ProbeController::SetMaxBitrate(DataRate max_bitrate) { void ProbeController::SetNetworkStateEstimate( webrtc::NetworkStateEstimate estimate) { + if (config_.network_state_estimate_fast_rampup_rate > 0 && + estimated_bitrate_ < estimate.link_capacity_upper && + (!network_estimate_ || + estimate.link_capacity_upper >= + config_.network_state_estimate_fast_rampup_rate * + network_estimate_->link_capacity_upper)) { + send_probe_on_next_process_interval_ = true; + } network_estimate_ = estimate; } @@ -370,6 +384,7 @@ void ProbeController::Reset(Timestamp at_time) { time_of_last_large_drop_ = now; bitrate_before_last_large_drop_ = DataRate::Zero(); max_total_allocated_bitrate_ = DataRate::Zero(); + send_probe_on_next_process_interval_ = false; } bool ProbeController::TimeForAlrProbe(Timestamp at_time) const { @@ -407,7 +422,8 @@ std::vector ProbeController::Process(Timestamp at_time) { if (estimated_bitrate_.IsZero() || state_ != State::kProbingComplete) { return {}; } - if (TimeForAlrProbe(at_time) || TimeForNetworkStateProbe(at_time)) { + if (send_probe_on_next_process_interval_ || TimeForAlrProbe(at_time) || + TimeForNetworkStateProbe(at_time)) { return InitiateProbing( at_time, {estimated_bitrate_ * config_.alr_probe_scale}, true); } @@ -440,6 +456,7 @@ std::vector ProbeController::InitiateProbing( max_probe_bitrate = std::min(max_probe_bitrate, max_total_allocated_bitrate_ * 2); } + send_probe_on_next_process_interval_ = false; std::vector pending_probes; for (DataRate bitrate : bitrates_to_probe) { @@ -453,7 +470,13 @@ std::vector ProbeController::InitiateProbing( ProbeClusterConfig config; config.at_time = now; config.target_data_rate = bitrate; - config.target_duration = config_.min_probe_duration; + if (network_estimate_ && + config_.network_state_estimate_probing_interval->IsFinite()) { + config.target_duration = config_.network_state_probe_duration; + } else { + config.target_duration = config_.min_probe_duration; + } + config.target_probe_count = config_.min_probe_packets_sent; config.id = next_probe_cluster_id_; next_probe_cluster_id_++; diff --git a/modules/congestion_controller/goog_cc/probe_controller.h b/modules/congestion_controller/goog_cc/probe_controller.h index 489a335200..399b38ebca 100644 --- a/modules/congestion_controller/goog_cc/probe_controller.h +++ b/modules/congestion_controller/goog_cc/probe_controller.h @@ -50,7 +50,13 @@ struct ProbeControllerConfig { // Configures how often we send probes if NetworkStateEstimate is available. FieldTrialParameter network_state_estimate_probing_interval; + // If the network state estimate increase more than this rate, a probe is sent + // the next process interval. + FieldTrialParameter network_state_estimate_fast_rampup_rate; FieldTrialParameter network_state_probe_scale; + // Overrides min_probe_duration if network_state_estimate_probing_interval + // is set and a network state estimate is known. + FieldTrialParameter network_state_probe_duration; // Configures the probes emitted by changed to the allocated bitrate. FieldTrialOptional first_allocation_probe_scale; @@ -142,6 +148,7 @@ class ProbeController { DataRate min_bitrate_to_probe_further_ = DataRate::PlusInfinity(); Timestamp time_last_probing_initiated_ = Timestamp::MinusInfinity(); DataRate estimated_bitrate_ = DataRate::Zero(); + bool send_probe_on_next_process_interval_; absl::optional network_estimate_; DataRate start_bitrate_ = DataRate::Zero(); DataRate max_bitrate_ = DataRate::PlusInfinity(); diff --git a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc index 8070820a77..8860a0f106 100644 --- a/modules/congestion_controller/goog_cc/probe_controller_unittest.cc +++ b/modules/congestion_controller/goog_cc/probe_controller_unittest.cc @@ -108,6 +108,27 @@ TEST(ProbeControllerTest, ProbeOnlyWhenNetworkIsUp) { EXPECT_GE(probes.size(), 2u); } +TEST(ProbeControllerTest, CanConfigureInitialProbeRateFactor) { + ProbeControllerFixture fixture("WebRTC-Bwe-ProbingConfiguration/p1:2,p2:3/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + auto probes = probe_controller->SetBitrates( + kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + EXPECT_EQ(probes.size(), 2u); + EXPECT_EQ(probes[0].target_data_rate, kStartBitrate * 2); + EXPECT_EQ(probes[1].target_data_rate, kStartBitrate * 3); +} + +TEST(ProbeControllerTest, DisableSecondInitialProbeIfRateFactorZero) { + ProbeControllerFixture fixture("WebRTC-Bwe-ProbingConfiguration/p1:2,p2:0/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + auto probes = probe_controller->SetBitrates( + kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + EXPECT_EQ(probes.size(), 1u); + EXPECT_EQ(probes[0].target_data_rate, kStartBitrate * 2); +} + TEST(ProbeControllerTest, InitiatesProbingOnMaxBitrateIncrease) { ProbeControllerFixture fixture; std::unique_ptr probe_controller = @@ -632,5 +653,68 @@ TEST(ProbeControllerTest, AlrProbesLimitedByNetworkStateEstimate) { EXPECT_EQ(probes[0].target_data_rate, state_estimate.link_capacity_upper); } +TEST(ProbeControllerTest, CanSetLongerProbeDurationAfterNetworkStateEstimate) { + ProbeControllerFixture fixture( + "WebRTC-Bwe-ProbingConfiguration/" + "network_state_interval:5s,network_state_probe_duration:100ms/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + + auto probes = probe_controller->SetBitrates( + kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + probes = probe_controller->SetEstimatedBitrate( + DataRate::KilobitsPerSec(5), /*bwe_limited_due_to_packet_loss=*/false, + fixture.CurrentTime()); + ASSERT_FALSE(probes.empty()); + EXPECT_LT(probes[0].target_duration, TimeDelta::Millis(100)); + + NetworkStateEstimate state_estimate; + state_estimate.link_capacity_upper = DataRate::KilobitsPerSec(6); + probe_controller->SetNetworkStateEstimate(state_estimate); + fixture.AdvanceTime(TimeDelta::Seconds(5)); + probes = probe_controller->Process(fixture.CurrentTime()); + ASSERT_EQ(probes.size(), 1u); + EXPECT_EQ(probes[0].target_duration, TimeDelta::Millis(100)); +} + +TEST(ProbeControllerTest, ProbeAfterLargeNetworkStateChange) { + ProbeControllerFixture fixture( + "WebRTC-Bwe-ProbingConfiguration/" + "network_state_interval:5s,network_state_fast_rampup_rate:2.0/"); + std::unique_ptr probe_controller = + fixture.CreateController(); + + auto probes = probe_controller->SetBitrates( + kMinBitrate, kStartBitrate, kMaxBitrate, fixture.CurrentTime()); + probes = probe_controller->SetEstimatedBitrate( + kStartBitrate, /*bwe_limited_due_to_packet_loss=*/false, + fixture.CurrentTime()); + // Need to wait at least one second before process can trigger a new probe. + fixture.AdvanceTime(TimeDelta::Millis(1100)); + probes = probe_controller->Process(fixture.CurrentTime()); + EXPECT_TRUE(probes.empty()); + + NetworkStateEstimate state_estimate; + state_estimate.link_capacity_upper = kStartBitrate; + probe_controller->SetNetworkStateEstimate(state_estimate); + // No probe since NetworkStateEstimate is not higher than the set + // estimated bitrate. + probes = probe_controller->Process(fixture.CurrentTime()); + EXPECT_TRUE(probes.empty()); + + // If NetworkState increase just a bit, dont expect the probe to be sent + // immediately. + state_estimate.link_capacity_upper = kStartBitrate * 1.4; + probe_controller->SetNetworkStateEstimate(state_estimate); + probes = probe_controller->Process(fixture.CurrentTime()); + EXPECT_TRUE(probes.empty()); + + // If NetworkState increase dramatically, expect a probe to be sent. + state_estimate.link_capacity_upper = kStartBitrate * 1.4 * 2; + probe_controller->SetNetworkStateEstimate(state_estimate); + probes = probe_controller->Process(fixture.CurrentTime()); + EXPECT_EQ(probes.size(), 1u); +} + } // namespace test } // namespace webrtc