diff --git a/modules/congestion_controller/goog_cc/BUILD.gn b/modules/congestion_controller/goog_cc/BUILD.gn index e21e1a112d..2daca286ba 100644 --- a/modules/congestion_controller/goog_cc/BUILD.gn +++ b/modules/congestion_controller/goog_cc/BUILD.gn @@ -97,6 +97,7 @@ rtc_source_set("alr_detector") { "../../../rtc_base:safe_conversions", "../../../rtc_base:timeutils", "../../../rtc_base/experiments:alr_experiment", + "../../../rtc_base/experiments:field_trial_parser", "../../pacing:interval_budget", "//third_party/abseil-cpp/absl/memory", "//third_party/abseil-cpp/absl/types:optional", diff --git a/modules/congestion_controller/goog_cc/alr_detector.cc b/modules/congestion_controller/goog_cc/alr_detector.cc index 2bcea3e3a6..89c11c187c 100644 --- a/modules/congestion_controller/goog_cc/alr_detector.cc +++ b/modules/congestion_controller/goog_cc/alr_detector.cc @@ -18,22 +18,14 @@ #include "logging/rtc_event_log/events/rtc_event_alr_state.h" #include "logging/rtc_event_log/rtc_event_log.h" #include "rtc_base/checks.h" -#include "rtc_base/experiments/alr_experiment.h" #include "rtc_base/numerics/safe_conversions.h" #include "rtc_base/time_utils.h" namespace webrtc { -AlrDetector::AlrDetector(const WebRtcKeyValueConfig* key_value_config) - : AlrDetector(key_value_config, nullptr) {} - -AlrDetector::AlrDetector(const WebRtcKeyValueConfig* key_value_config, - RtcEventLog* event_log) - : bandwidth_usage_percent_(kDefaultAlrBandwidthUsagePercent), - alr_start_budget_level_percent_(kDefaultAlrStartBudgetLevelPercent), - alr_stop_budget_level_percent_(kDefaultAlrStopBudgetLevelPercent), - alr_budget_(0, true), - event_log_(event_log) { +namespace { +absl::optional GetExperimentSettings( + const WebRtcKeyValueConfig* key_value_config) { RTC_CHECK(AlrExperimentSettings::MaxOneFieldTrialEnabled(*key_value_config)); absl::optional experiment_settings = AlrExperimentSettings::CreateFromFieldTrial( @@ -44,13 +36,45 @@ AlrDetector::AlrDetector(const WebRtcKeyValueConfig* key_value_config, *key_value_config, AlrExperimentSettings::kStrictPacingAndProbingExperimentName); } - if (experiment_settings) { - alr_stop_budget_level_percent_ = - experiment_settings->alr_stop_budget_level_percent; - alr_start_budget_level_percent_ = - experiment_settings->alr_start_budget_level_percent; - bandwidth_usage_percent_ = experiment_settings->alr_bandwidth_usage_percent; - } + return experiment_settings; +} +} // namespace + +AlrDetector::AlrDetector(const WebRtcKeyValueConfig* key_value_config) + : AlrDetector(key_value_config, + nullptr, + GetExperimentSettings(key_value_config)) {} + +AlrDetector::AlrDetector(const WebRtcKeyValueConfig* key_value_config, + RtcEventLog* event_log) + : AlrDetector(key_value_config, + event_log, + GetExperimentSettings(key_value_config)) {} + +AlrDetector::AlrDetector( + const WebRtcKeyValueConfig* key_value_config, + RtcEventLog* event_log, + absl::optional experiment_settings) + : bandwidth_usage_ratio_( + "bw_usage", + experiment_settings + ? experiment_settings->alr_bandwidth_usage_percent / 100.0 + : kDefaultBandwidthUsageRatio), + start_budget_level_ratio_( + "start", + experiment_settings + ? experiment_settings->alr_start_budget_level_percent / 100.0 + : kDefaultStartBudgetLevelRatio), + stop_budget_level_ratio_( + "stop", + experiment_settings + ? experiment_settings->alr_stop_budget_level_percent / 100.0 + : kDefaultStopBudgetLevelRatio), + alr_budget_(0, true), + event_log_(event_log) { + ParseFieldTrial({&bandwidth_usage_ratio_, &start_budget_level_ratio_, + &stop_budget_level_ratio_}, + key_value_config->Lookup("WebRTC-AlrDetectorParameters")); } AlrDetector::~AlrDetector() {} @@ -68,12 +92,12 @@ void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t send_time_ms) { alr_budget_.UseBudget(bytes_sent); alr_budget_.IncreaseBudget(delta_time_ms); bool state_changed = false; - if (alr_budget_.budget_level_percent() > alr_start_budget_level_percent_ && + if (alr_budget_.budget_level_percent() > start_budget_level_ratio_ * 100 && !alr_started_time_ms_) { alr_started_time_ms_.emplace(rtc::TimeMillis()); state_changed = true; } else if (alr_budget_.budget_level_percent() < - alr_stop_budget_level_percent_ && + stop_budget_level_ratio_ * 100 && alr_started_time_ms_) { state_changed = true; alr_started_time_ms_.reset(); @@ -86,13 +110,14 @@ void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t send_time_ms) { void AlrDetector::SetEstimatedBitrate(int bitrate_bps) { RTC_DCHECK(bitrate_bps); - const auto target_rate_kbps = static_cast(bitrate_bps) * - bandwidth_usage_percent_ / (1000 * 100); - alr_budget_.set_target_rate_kbps(rtc::dchecked_cast(target_rate_kbps)); + int target_rate_kbps = + static_cast(bitrate_bps) * bandwidth_usage_ratio_ / 1000; + alr_budget_.set_target_rate_kbps(target_rate_kbps); } absl::optional AlrDetector::GetApplicationLimitedRegionStartTime() const { return alr_started_time_ms_; } + } // namespace webrtc diff --git a/modules/congestion_controller/goog_cc/alr_detector.h b/modules/congestion_controller/goog_cc/alr_detector.h index b58c92682b..364294f1d5 100644 --- a/modules/congestion_controller/goog_cc/alr_detector.h +++ b/modules/congestion_controller/goog_cc/alr_detector.h @@ -17,6 +17,8 @@ #include "absl/types/optional.h" #include "api/transport/webrtc_key_value_config.h" #include "modules/pacing/interval_budget.h" +#include "rtc_base/experiments/alr_experiment.h" +#include "rtc_base/experiments/field_trial_units.h" namespace webrtc { @@ -45,23 +47,27 @@ class AlrDetector { // started or empty result if the sender is currently not application-limited. absl::optional GetApplicationLimitedRegionStartTime() const; - // Sent traffic percentage as a function of network capacity used to determine - // application-limited region. ALR region start when bandwidth usage drops - // below kAlrStartUsagePercent and ends when it raises above - // kAlrEndUsagePercent. NOTE: This is intentionally conservative at the moment - // until BW adjustments of application limited region is fine tuned. - static constexpr int kDefaultAlrBandwidthUsagePercent = 65; - static constexpr int kDefaultAlrStartBudgetLevelPercent = 80; - static constexpr int kDefaultAlrStopBudgetLevelPercent = 50; - void UpdateBudgetWithElapsedTime(int64_t delta_time_ms); void UpdateBudgetWithBytesSent(size_t bytes_sent); private: + // Sent traffic ratio as a function of network capacity used to determine + // application-limited region. ALR region start when bandwidth usage drops + // below kAlrStartUsageRatio and ends when it raises above + // kAlrEndUsageRatio. NOTE: This is intentionally conservative at the moment + // until BW adjustments of application limited region is fine tuned. + static constexpr double kDefaultBandwidthUsageRatio = 0.65; + static constexpr double kDefaultStartBudgetLevelRatio = 0.80; + static constexpr double kDefaultStopBudgetLevelRatio = 0.50; + + AlrDetector(const WebRtcKeyValueConfig* key_value_config, + RtcEventLog* event_log, + absl::optional experiment_settings); + friend class GoogCcStatePrinter; - int bandwidth_usage_percent_; - int alr_start_budget_level_percent_; - int alr_stop_budget_level_percent_; + FieldTrialParameter bandwidth_usage_ratio_; + FieldTrialParameter start_budget_level_ratio_; + FieldTrialParameter stop_budget_level_ratio_; absl::optional last_send_time_ms_; diff --git a/modules/congestion_controller/goog_cc/alr_detector_unittest.cc b/modules/congestion_controller/goog_cc/alr_detector_unittest.cc index c1f96a1f8b..eac19d0081 100644 --- a/modules/congestion_controller/goog_cc/alr_detector_unittest.cc +++ b/modules/congestion_controller/goog_cc/alr_detector_unittest.cc @@ -70,89 +70,90 @@ class SimulateOutgoingTrafficIn { }; } // namespace -class AlrDetectorTest : public ::testing::Test { - public: - AlrDetectorTest() : alr_detector_(&field_trials_) {} - void SetUp() override { - alr_detector_.SetEstimatedBitrate(kEstimatedBitrateBps); - } +TEST(AlrDetectorTest, AlrDetection) { + FieldTrialBasedConfig field_trials; + int64_t timestamp_ms = 1000; + AlrDetector alr_detector(&field_trials); + alr_detector.SetEstimatedBitrate(kEstimatedBitrateBps); - protected: - FieldTrialBasedConfig field_trials_; - AlrDetector alr_detector_; - int64_t timestamp_ms_ = 1000; -}; - -TEST_F(AlrDetectorTest, AlrDetection) { // Start in non-ALR state. - EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime()); + EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime()); // Stay in non-ALR state when usage is close to 100%. - SimulateOutgoingTrafficIn(&alr_detector_, ×tamp_ms_) + SimulateOutgoingTrafficIn(&alr_detector, ×tamp_ms) .ForTimeMs(1000) .AtPercentOfEstimatedBitrate(90); - EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime()); + EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime()); // Verify that we ALR starts when bitrate drops below 20%. - SimulateOutgoingTrafficIn(&alr_detector_, ×tamp_ms_) + SimulateOutgoingTrafficIn(&alr_detector, ×tamp_ms) .ForTimeMs(1500) .AtPercentOfEstimatedBitrate(20); - EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime()); + EXPECT_TRUE(alr_detector.GetApplicationLimitedRegionStartTime()); // Verify that ALR ends when usage is above 65%. - SimulateOutgoingTrafficIn(&alr_detector_, ×tamp_ms_) + SimulateOutgoingTrafficIn(&alr_detector, ×tamp_ms) .ForTimeMs(4000) .AtPercentOfEstimatedBitrate(100); - EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime()); + EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime()); } -TEST_F(AlrDetectorTest, ShortSpike) { +TEST(AlrDetectorTest, ShortSpike) { + FieldTrialBasedConfig field_trials; + int64_t timestamp_ms = 1000; + AlrDetector alr_detector(&field_trials); + alr_detector.SetEstimatedBitrate(kEstimatedBitrateBps); // Start in non-ALR state. - EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime()); + EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime()); // Verify that we ALR starts when bitrate drops below 20%. - SimulateOutgoingTrafficIn(&alr_detector_, ×tamp_ms_) + SimulateOutgoingTrafficIn(&alr_detector, ×tamp_ms) .ForTimeMs(1000) .AtPercentOfEstimatedBitrate(20); - EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime()); + EXPECT_TRUE(alr_detector.GetApplicationLimitedRegionStartTime()); // Verify that we stay in ALR region even after a short bitrate spike. - SimulateOutgoingTrafficIn(&alr_detector_, ×tamp_ms_) + SimulateOutgoingTrafficIn(&alr_detector, ×tamp_ms) .ForTimeMs(100) .AtPercentOfEstimatedBitrate(150); - EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime()); + EXPECT_TRUE(alr_detector.GetApplicationLimitedRegionStartTime()); // ALR ends when usage is above 65%. - SimulateOutgoingTrafficIn(&alr_detector_, ×tamp_ms_) + SimulateOutgoingTrafficIn(&alr_detector, ×tamp_ms) .ForTimeMs(3000) .AtPercentOfEstimatedBitrate(100); - EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime()); + EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime()); } -TEST_F(AlrDetectorTest, BandwidthEstimateChanges) { +TEST(AlrDetectorTest, BandwidthEstimateChanges) { + FieldTrialBasedConfig field_trials; + int64_t timestamp_ms = 1000; + AlrDetector alr_detector(&field_trials); + alr_detector.SetEstimatedBitrate(kEstimatedBitrateBps); + // Start in non-ALR state. - EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime()); + EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime()); // ALR starts when bitrate drops below 20%. - SimulateOutgoingTrafficIn(&alr_detector_, ×tamp_ms_) + SimulateOutgoingTrafficIn(&alr_detector, ×tamp_ms) .ForTimeMs(1000) .AtPercentOfEstimatedBitrate(20); - EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime()); + EXPECT_TRUE(alr_detector.GetApplicationLimitedRegionStartTime()); // When bandwidth estimate drops the detector should stay in ALR mode and quit // it shortly afterwards as the sender continues sending the same amount of // traffic. This is necessary to ensure that ProbeController can still react // to the BWE drop by initiating a new probe. - alr_detector_.SetEstimatedBitrate(kEstimatedBitrateBps / 5); - EXPECT_TRUE(alr_detector_.GetApplicationLimitedRegionStartTime()); - SimulateOutgoingTrafficIn(&alr_detector_, ×tamp_ms_) + alr_detector.SetEstimatedBitrate(kEstimatedBitrateBps / 5); + EXPECT_TRUE(alr_detector.GetApplicationLimitedRegionStartTime()); + SimulateOutgoingTrafficIn(&alr_detector, ×tamp_ms) .ForTimeMs(1000) .AtPercentOfEstimatedBitrate(50); - EXPECT_FALSE(alr_detector_.GetApplicationLimitedRegionStartTime()); + EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime()); } -TEST_F(AlrDetectorTest, ParseControlFieldTrial) { - webrtc::test::ScopedFieldTrials field_trial( +TEST(AlrDetectorTest, ParseControlFieldTrial) { + webrtc::test::ScopedFieldTrials scoped_field_trial( "WebRTC-ProbingScreenshareBwe/Control/"); absl::optional parsed_params = AlrExperimentSettings::CreateFromFieldTrial( @@ -160,8 +161,8 @@ TEST_F(AlrDetectorTest, ParseControlFieldTrial) { EXPECT_FALSE(static_cast(parsed_params)); } -TEST_F(AlrDetectorTest, ParseActiveFieldTrial) { - webrtc::test::ScopedFieldTrials field_trial( +TEST(AlrDetectorTest, ParseActiveFieldTrial) { + webrtc::test::ScopedFieldTrials scoped_field_trial( "WebRTC-ProbingScreenshareBwe/1.1,2875,85,20,-20,1/"); absl::optional parsed_params = AlrExperimentSettings::CreateFromFieldTrial( @@ -175,4 +176,31 @@ TEST_F(AlrDetectorTest, ParseActiveFieldTrial) { EXPECT_EQ(1, parsed_params->group_id); } +TEST(AlrDetectorTest, ParseAlrSpecificFieldTrial) { + webrtc::test::ScopedFieldTrials scoped_field_trial( + "WebRTC-AlrDetectorParameters/" + "bw_usage:90%,start:0%,stop:-10%/"); + FieldTrialBasedConfig field_trials; + AlrDetector alr_detector(&field_trials); + int64_t timestamp_ms = 1000; + alr_detector.SetEstimatedBitrate(kEstimatedBitrateBps); + + // Start in non-ALR state. + EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime()); + + // ALR does not start at 100% utilization. + SimulateOutgoingTrafficIn(&alr_detector, ×tamp_ms) + .ForTimeMs(1000) + .AtPercentOfEstimatedBitrate(100); + EXPECT_FALSE(alr_detector.GetApplicationLimitedRegionStartTime()); + + // ALR does start at 85% utilization. + // Overused 10% above so it should take about 2s to reach a budget level of + // 0%. + SimulateOutgoingTrafficIn(&alr_detector, ×tamp_ms) + .ForTimeMs(2100) + .AtPercentOfEstimatedBitrate(85); + EXPECT_TRUE(alr_detector.GetApplicationLimitedRegionStartTime()); +} + } // namespace webrtc