Use field trial parser for BBR Experiment.

Bug: webrtc:8415
Change-Id: If6336b16fa55c6bd891252fc3b9c0bcce56e2fd1
Reviewed-on: https://webrtc-review.googlesource.com/83620
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23761}
This commit is contained in:
Sebastian Jansson
2018-06-27 14:06:00 +02:00
committed by Commit Bot
parent e275174b1b
commit 968b1dd0d7
6 changed files with 151 additions and 239 deletions

View File

@ -34,8 +34,9 @@ rtc_source_set("bbr_controller") {
"../../../api/transport:network_control",
"../../../rtc_base:checks",
"../../../rtc_base:rtc_base_approved",
"../../../rtc_base/experiments:congestion_controller_experiment",
"../../../rtc_base/experiments:field_trial_parser",
"../../../rtc_base/system:fallthrough",
"../../../system_wrappers:field_trial_api",
"//third_party/abseil-cpp/absl/types:optional",
]
}

View File

@ -16,9 +16,9 @@
#include <vector>
#include "rtc_base/checks.h"
#include "rtc_base/experiments/congestion_controller_experiment.h"
#include "rtc_base/logging.h"
#include "rtc_base/system/fallthrough.h"
#include "system_wrappers/include/field_trial.h"
namespace webrtc {
namespace bbr {
@ -77,65 +77,84 @@ const int64_t kInitialCongestionWindowPackets = 32;
const int64_t kDefaultMinCongestionWindowPackets = 4;
const int64_t kDefaultMaxCongestionWindowPackets = 2000;
const char kBbrConfigTrial[] = "WebRTC-BweBbrConfig";
} // namespace
BbrNetworkController::BbrControllerConfig::BbrControllerConfig(
std::string field_trial)
: probe_bw_pacing_gain_offset("probe_bw_pacing_gain_offset", 0.25),
encoder_rate_gain("encoder_rate_gain", 1),
encoder_rate_gain_in_probe_rtt("encoder_rate_gain_in_probe_rtt", 1),
exit_startup_rtt_threshold("exit_startup_rtt_threshold",
TimeDelta::PlusInfinity()),
initial_congestion_window(
"initial_cwin",
kInitialCongestionWindowPackets * kDefaultTCPMSS),
min_congestion_window(
"min_cwin",
kDefaultMinCongestionWindowPackets * kDefaultTCPMSS),
max_congestion_window(
"max_cwin",
kDefaultMaxCongestionWindowPackets * kDefaultTCPMSS),
probe_rtt_congestion_window_gain("probe_rtt_cwin_gain", 0.75),
pacing_rate_as_target("pacing_rate_as_target", false),
exit_startup_on_loss("exit_startup_on_loss", true),
num_startup_rtts("num_startup_rtts", 3),
rate_based_recovery("rate_based_recovery", false),
max_aggregation_bytes_multiplier("max_aggregation_bytes_multiplier", 0),
slower_startup("slower_startup", false),
rate_based_startup("rate_based_startup", false),
initial_conservation_in_startup("initial_conservation",
CONSERVATION,
{
{"NOT_IN_RECOVERY", NOT_IN_RECOVERY},
{"CONSERVATION", CONSERVATION},
{"MEDIUM_GROWTH", MEDIUM_GROWTH},
{"GROWTH", GROWTH},
}),
fully_drain_queue("fully_drain_queue", false),
max_ack_height_window_multiplier("max_ack_height_window_multiplier", 1),
probe_rtt_based_on_bdp("probe_rtt_based_on_bdp", false),
probe_rtt_skipped_if_similar_rtt("probe_rtt_skipped_if_similar_rtt",
false),
probe_rtt_disabled_if_app_limited("probe_rtt_disabled_if_app_limited",
false) {
ParseFieldTrial(
{
&exit_startup_on_loss,
&encoder_rate_gain,
&encoder_rate_gain_in_probe_rtt,
&exit_startup_rtt_threshold,
&fully_drain_queue,
&initial_congestion_window,
&initial_conservation_in_startup,
&max_ack_height_window_multiplier,
&max_aggregation_bytes_multiplier,
&max_congestion_window,
&min_congestion_window,
&num_startup_rtts,
&pacing_rate_as_target,
&probe_bw_pacing_gain_offset,
&probe_rtt_based_on_bdp,
&probe_rtt_congestion_window_gain,
&probe_rtt_disabled_if_app_limited,
&probe_rtt_skipped_if_similar_rtt,
&rate_based_recovery,
&rate_based_startup,
&slower_startup,
},
field_trial);
}
BbrNetworkController::BbrControllerConfig::~BbrControllerConfig() = default;
BbrNetworkController::BbrControllerConfig::BbrControllerConfig(
const BbrControllerConfig&) = default;
BbrNetworkController::BbrControllerConfig
BbrNetworkController::BbrControllerConfig::DefaultConfig() {
BbrControllerConfig config;
config.probe_bw_pacing_gain_offset = 0.25;
config.encoder_rate_gain = 1;
config.encoder_rate_gain_in_probe_rtt = 1;
config.exit_startup_rtt_threshold_ms = 0;
config.probe_rtt_congestion_window_gain = 0.75;
config.exit_startup_on_loss = true;
config.num_startup_rtts = 3;
config.rate_based_recovery = false;
config.max_aggregation_bytes_multiplier = 0;
config.slower_startup = false;
config.rate_based_startup = false;
config.fully_drain_queue = false;
config.initial_conservation_in_startup = CONSERVATION;
config.max_ack_height_window_multiplier = 1;
config.probe_rtt_based_on_bdp = false;
config.probe_rtt_skipped_if_similar_rtt = false;
config.probe_rtt_disabled_if_app_limited = false;
return config;
BbrNetworkController::BbrControllerConfig::FromTrial() {
return BbrControllerConfig(
webrtc::field_trial::FindFullName(kBbrConfigTrial));
}
BbrNetworkController::BbrControllerConfig
BbrNetworkController::BbrControllerConfig::ExperimentConfig() {
auto exp = CongestionControllerExperiment::GetBbrExperimentConfig();
if (exp) {
BbrControllerConfig config;
config.exit_startup_on_loss = exp->exit_startup_on_loss;
config.exit_startup_rtt_threshold_ms = exp->exit_startup_rtt_threshold_ms;
config.fully_drain_queue = exp->fully_drain_queue;
config.initial_conservation_in_startup =
static_cast<RecoveryState>(exp->initial_conservation_in_startup);
config.num_startup_rtts = exp->num_startup_rtts;
config.probe_rtt_based_on_bdp = exp->probe_rtt_based_on_bdp;
config.probe_rtt_disabled_if_app_limited =
exp->probe_rtt_disabled_if_app_limited;
config.probe_rtt_skipped_if_similar_rtt =
exp->probe_rtt_skipped_if_similar_rtt;
config.rate_based_recovery = exp->rate_based_recovery;
config.rate_based_startup = exp->rate_based_startup;
config.slower_startup = exp->slower_startup;
config.encoder_rate_gain = exp->encoder_rate_gain;
config.encoder_rate_gain_in_probe_rtt = exp->encoder_rate_gain_in_probe_rtt;
config.max_ack_height_window_multiplier =
exp->max_ack_height_window_multiplier;
config.max_aggregation_bytes_multiplier =
exp->max_aggregation_bytes_multiplier;
config.probe_bw_pacing_gain_offset = exp->probe_bw_pacing_gain_offset;
config.probe_rtt_congestion_window_gain =
exp->probe_rtt_congestion_window_gain;
return config;
} else {
return DefaultConfig();
}
}
BbrNetworkController::DebugState::DebugState(const BbrNetworkController& sender)
: mode(sender.mode_),
@ -156,7 +175,8 @@ BbrNetworkController::DebugState::DebugState(const BbrNetworkController& sender)
BbrNetworkController::DebugState::DebugState(const DebugState& state) = default;
BbrNetworkController::BbrNetworkController(NetworkControllerConfig config)
: rtt_stats_(),
: config_(BbrControllerConfig::FromTrial()),
rtt_stats_(),
random_(10),
loss_rate_(),
mode_(STARTUP),
@ -174,13 +194,10 @@ BbrNetworkController::BbrNetworkController(NetworkControllerConfig config)
min_rtt_(TimeDelta::Zero()),
last_rtt_(TimeDelta::Zero()),
min_rtt_timestamp_(Timestamp::ms(0)),
congestion_window_(kInitialCongestionWindowPackets * kDefaultTCPMSS),
initial_congestion_window_(kInitialCongestionWindowPackets *
kDefaultTCPMSS),
min_congestion_window_(kDefaultMinCongestionWindowPackets *
kDefaultTCPMSS),
max_congestion_window_(kDefaultMaxCongestionWindowPackets *
kDefaultTCPMSS),
congestion_window_(config_.initial_congestion_window),
initial_congestion_window_(config_.initial_congestion_window),
min_congestion_window_(config_.min_congestion_window),
max_congestion_window_(config_.max_congestion_window),
pacing_rate_(DataRate::Zero()),
pacing_gain_(1),
congestion_window_gain_constant_(kProbeBWCongestionWindowGain),
@ -200,7 +217,6 @@ BbrNetworkController::BbrNetworkController(NetworkControllerConfig config)
app_limited_since_last_probe_rtt_(false),
min_rtt_since_last_probe_rtt_(TimeDelta::PlusInfinity()) {
RTC_LOG(LS_INFO) << "Creating BBR controller";
config_ = BbrControllerConfig::ExperimentConfig();
if (config.starting_bandwidth.IsFinite())
default_bandwidth_ = config.starting_bandwidth;
constraints_ = config.constraints;
@ -227,11 +243,13 @@ NetworkControlUpdate BbrNetworkController::CreateRateUpdate(Timestamp at_time) {
bandwidth = default_bandwidth_;
TimeDelta rtt = GetMinRtt();
DataRate pacing_rate = PacingRate();
DataRate target_rate = bandwidth;
DataRate target_rate =
config_.pacing_rate_as_target ? pacing_rate : bandwidth;
if (mode_ == PROBE_RTT)
target_rate = bandwidth * config_.encoder_rate_gain_in_probe_rtt;
target_rate = target_rate * config_.encoder_rate_gain_in_probe_rtt;
else
target_rate = bandwidth * config_.encoder_rate_gain;
target_rate = target_rate * config_.encoder_rate_gain;
target_rate = std::min(target_rate, pacing_rate);
if (constraints_) {
@ -669,15 +687,14 @@ void BbrNetworkController::CheckIfFullBandwidthReached() {
void BbrNetworkController::MaybeExitStartupOrDrain(
const TransportPacketsFeedback& msg) {
int64_t exit_threshold_ms = config_.exit_startup_rtt_threshold_ms;
bool rtt_over_threshold =
exit_threshold_ms > 0 && (last_rtt_ - min_rtt_).ms() > exit_threshold_ms;
if (mode_ == STARTUP && (is_at_full_bandwidth_ || rtt_over_threshold)) {
if (rtt_over_threshold)
TimeDelta exit_threshold = config_.exit_startup_rtt_threshold;
TimeDelta rtt_delta = last_rtt_ - min_rtt_;
if (mode_ == STARTUP &&
(is_at_full_bandwidth_ || rtt_delta > exit_threshold)) {
if (rtt_delta > exit_threshold)
RTC_LOG(LS_INFO) << "Exiting startup due to rtt increase from: "
<< ToString(min_rtt_) << " to:" << ToString(last_rtt_)
<< " > "
<< ToString(min_rtt_ + TimeDelta::ms(exit_threshold_ms));
<< " > " << ToString(min_rtt_ + exit_threshold);
mode_ = DRAIN;
pacing_gain_ = kDrainGain;
congestion_window_gain_ = kHighGain;

View File

@ -27,6 +27,8 @@
#include "modules/congestion_controller/bbr/windowed_filter.h"
#include "absl/types/optional.h"
#include "rtc_base/experiments/field_trial_parser.h"
#include "rtc_base/experiments/field_trial_units.h"
#include "rtc_base/random.h"
namespace webrtc {
@ -59,14 +61,63 @@ class BbrNetworkController : public NetworkControllerInterface {
// Indicates how the congestion control limits the amount of bytes in flight.
enum RecoveryState {
// Do not limit.
NOT_IN_RECOVERY,
NOT_IN_RECOVERY = 0,
// Allow an extra outstanding byte for each byte acknowledged.
CONSERVATION,
CONSERVATION = 1,
// Allow 1.5 extra outstanding bytes for each byte acknowledged.
MEDIUM_GROWTH,
MEDIUM_GROWTH = 2,
// Allow two extra outstanding bytes for each byte acknowledged (slow
// start).
GROWTH
GROWTH = 3
};
struct BbrControllerConfig {
FieldTrialParameter<double> probe_bw_pacing_gain_offset;
FieldTrialParameter<double> encoder_rate_gain;
FieldTrialParameter<double> encoder_rate_gain_in_probe_rtt;
// RTT delta to determine if startup should be exited due to increased RTT.
FieldTrialParameter<TimeDelta> exit_startup_rtt_threshold;
FieldTrialParameter<DataSize> initial_congestion_window;
FieldTrialParameter<DataSize> min_congestion_window;
FieldTrialParameter<DataSize> max_congestion_window;
FieldTrialParameter<double> probe_rtt_congestion_window_gain;
FieldTrialParameter<bool> pacing_rate_as_target;
// Configurable in QUIC BBR:
FieldTrialParameter<bool> exit_startup_on_loss;
// The number of RTTs to stay in STARTUP mode. Defaults to 3.
FieldTrialParameter<int> num_startup_rtts;
// When true, recovery is rate based rather than congestion window based.
FieldTrialParameter<bool> rate_based_recovery;
FieldTrialParameter<double> max_aggregation_bytes_multiplier;
// When true, pace at 1.5x and disable packet conservation in STARTUP.
FieldTrialParameter<bool> slower_startup;
// When true, disables packet conservation in STARTUP.
FieldTrialParameter<bool> rate_based_startup;
// Used as the initial packet conservation mode when first entering
// recovery.
FieldTrialEnum<RecoveryState> initial_conservation_in_startup;
// If true, will not exit low gain mode until bytes_in_flight drops below
// BDP or it's time for high gain mode.
FieldTrialParameter<bool> fully_drain_queue;
FieldTrialParameter<double> max_ack_height_window_multiplier;
// If true, use a CWND of 0.75*BDP during probe_rtt instead of 4 packets.
FieldTrialParameter<bool> probe_rtt_based_on_bdp;
// If true, skip probe_rtt and update the timestamp of the existing min_rtt
// to now if min_rtt over the last cycle is within 12.5% of the current
// min_rtt. Even if the min_rtt is 12.5% too low, the 25% gain cycling and
// 2x CWND gain should overcome an overly small min_rtt.
FieldTrialParameter<bool> probe_rtt_skipped_if_similar_rtt;
// If true, disable PROBE_RTT entirely as long as the connection was
// recently app limited.
FieldTrialParameter<bool> probe_rtt_disabled_if_app_limited;
explicit BbrControllerConfig(std::string field_trial);
~BbrControllerConfig();
BbrControllerConfig(const BbrControllerConfig&);
static BbrControllerConfig FromTrial();
};
// Debug state can be exported in order to troubleshoot potential congestion
@ -213,6 +264,8 @@ class BbrNetworkController : public NetworkControllerInterface {
DataSize bytes_lost,
DataSize bytes_in_flight);
BbrControllerConfig config_;
RttStats rtt_stats_;
webrtc::Random random_;
LossRateFilter loss_rate_;
@ -325,52 +378,6 @@ class BbrNetworkController : public NetworkControllerInterface {
// A window used to limit the number of bytes in flight during loss recovery.
DataSize recovery_window_;
struct BbrControllerConfig {
// Default config based on default QUIC config
static BbrControllerConfig DefaultConfig();
static BbrControllerConfig ExperimentConfig();
double probe_bw_pacing_gain_offset;
double encoder_rate_gain;
double encoder_rate_gain_in_probe_rtt;
// RTT delta to determine if startup should be exited due to increased RTT.
int64_t exit_startup_rtt_threshold_ms;
double probe_rtt_congestion_window_gain;
// Configurable in QUIC BBR:
bool exit_startup_on_loss;
// The number of RTTs to stay in STARTUP mode. Defaults to 3.
BbrRoundTripCount num_startup_rtts;
// When true, recovery is rate based rather than congestion window based.
bool rate_based_recovery;
double max_aggregation_bytes_multiplier;
// When true, pace at 1.5x and disable packet conservation in STARTUP.
bool slower_startup;
// When true, disables packet conservation in STARTUP.
bool rate_based_startup;
// Used as the initial packet conservation mode when first entering
// recovery.
RecoveryState initial_conservation_in_startup;
// If true, will not exit low gain mode until bytes_in_flight drops below
// BDP or it's time for high gain mode.
bool fully_drain_queue;
double max_ack_height_window_multiplier;
// If true, use a CWND of 0.75*BDP during probe_rtt instead of 4 packets.
bool probe_rtt_based_on_bdp;
// If true, skip probe_rtt and update the timestamp of the existing min_rtt
// to now if min_rtt over the last cycle is within 12.5% of the current
// min_rtt. Even if the min_rtt is 12.5% too low, the 25% gain cycling and
// 2x CWND gain should overcome an overly small min_rtt.
bool probe_rtt_skipped_if_similar_rtt;
// If true, disable PROBE_RTT entirely as long as the connection was
// recently app limited.
bool probe_rtt_disabled_if_app_limited;
};
BbrControllerConfig config_;
bool app_limited_since_last_probe_rtt_;
TimeDelta min_rtt_since_last_probe_rtt_;

View File

@ -30,34 +30,4 @@ bool CongestionControllerExperiment::InjectedControllerEnabled() {
webrtc::field_trial::FindFullName(kControllerExperiment);
return trial_string.find("Enabled,Injected") == 0;
}
absl::optional<CongestionControllerExperiment::BbrExperimentConfig>
CongestionControllerExperiment::GetBbrExperimentConfig() {
if (!BbrControllerEnabled())
return absl::nullopt;
std::string trial_string =
webrtc::field_trial::FindFullName(kControllerExperiment);
BbrExperimentConfig config;
if (sscanf(
trial_string.c_str(),
"Enabled,BBR,"
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,"
"%lf,%lf,%lf,%lf,%lf,%lf",
&config.exit_startup_on_loss, &config.exit_startup_rtt_threshold_ms,
&config.fully_drain_queue, &config.initial_conservation_in_startup,
&config.num_startup_rtts, &config.probe_rtt_based_on_bdp,
&config.probe_rtt_disabled_if_app_limited,
&config.probe_rtt_skipped_if_similar_rtt, &config.rate_based_recovery,
&config.rate_based_startup, &config.slower_startup,
&config.encoder_rate_gain, &config.encoder_rate_gain_in_probe_rtt,
&config.max_ack_height_window_multiplier,
&config.max_aggregation_bytes_multiplier,
&config.probe_bw_pacing_gain_offset,
&config.probe_rtt_congestion_window_gain) == 17) {
return config;
} else {
return absl::nullopt;
}
}
} // namespace webrtc

View File

@ -9,32 +9,12 @@
*/
#ifndef RTC_BASE_EXPERIMENTS_CONGESTION_CONTROLLER_EXPERIMENT_H_
#define RTC_BASE_EXPERIMENTS_CONGESTION_CONTROLLER_EXPERIMENT_H_
#include <api/optional.h>
namespace webrtc {
class CongestionControllerExperiment {
public:
struct BbrExperimentConfig {
int exit_startup_on_loss;
int exit_startup_rtt_threshold_ms;
int fully_drain_queue;
int initial_conservation_in_startup;
int num_startup_rtts;
int probe_rtt_based_on_bdp;
int probe_rtt_disabled_if_app_limited;
int probe_rtt_skipped_if_similar_rtt;
int rate_based_recovery;
int rate_based_startup;
int slower_startup;
double encoder_rate_gain;
double encoder_rate_gain_in_probe_rtt;
double max_ack_height_window_multiplier;
double max_aggregation_bytes_multiplier;
double probe_bw_pacing_gain_offset;
double probe_rtt_congestion_window_gain;
};
static bool BbrControllerEnabled();
static bool InjectedControllerEnabled();
static absl::optional<BbrExperimentConfig> GetBbrExperimentConfig();
};
} // namespace webrtc

View File

@ -13,35 +13,6 @@
#include "test/field_trial.h"
namespace webrtc {
namespace {
void ExpectEquals(CongestionControllerExperiment::BbrExperimentConfig a,
CongestionControllerExperiment::BbrExperimentConfig b) {
EXPECT_EQ(a.exit_startup_on_loss, b.exit_startup_on_loss);
EXPECT_EQ(a.exit_startup_rtt_threshold_ms, b.exit_startup_rtt_threshold_ms);
EXPECT_EQ(a.fully_drain_queue, b.fully_drain_queue);
EXPECT_EQ(a.initial_conservation_in_startup,
b.initial_conservation_in_startup);
EXPECT_EQ(a.num_startup_rtts, b.num_startup_rtts);
EXPECT_EQ(a.probe_rtt_based_on_bdp, b.probe_rtt_based_on_bdp);
EXPECT_EQ(a.probe_rtt_disabled_if_app_limited,
b.probe_rtt_disabled_if_app_limited);
EXPECT_EQ(a.probe_rtt_skipped_if_similar_rtt,
b.probe_rtt_skipped_if_similar_rtt);
EXPECT_EQ(a.rate_based_recovery, b.rate_based_recovery);
EXPECT_EQ(a.rate_based_startup, b.rate_based_startup);
EXPECT_EQ(a.slower_startup, b.slower_startup);
EXPECT_EQ(a.encoder_rate_gain, b.encoder_rate_gain);
EXPECT_EQ(a.encoder_rate_gain_in_probe_rtt, b.encoder_rate_gain_in_probe_rtt);
EXPECT_EQ(a.max_ack_height_window_multiplier,
b.max_ack_height_window_multiplier);
EXPECT_EQ(a.max_aggregation_bytes_multiplier,
b.max_aggregation_bytes_multiplier);
EXPECT_EQ(a.probe_bw_pacing_gain_offset, b.probe_bw_pacing_gain_offset);
EXPECT_EQ(a.probe_rtt_congestion_window_gain,
b.probe_rtt_congestion_window_gain);
}
} // namespace
TEST(CongestionControllerExperimentTest, BbrDisabledByDefault) {
webrtc::test::ScopedFieldTrials field_trials("");
EXPECT_FALSE(CongestionControllerExperiment::BbrControllerEnabled());
@ -52,38 +23,4 @@ TEST(CongestionControllerExperimentTest, BbrEnabledByFieldTrial) {
"WebRTC-BweCongestionController/Enabled,BBR/");
EXPECT_TRUE(CongestionControllerExperiment::BbrControllerEnabled());
}
TEST(CongestionControllerExperimentTest, BbrBadParametersFails) {
webrtc::test::ScopedFieldTrials field_trials(
"WebRTC-BweCongestionController/Enabled,BBR,"
"garbage,here/");
EXPECT_FALSE(CongestionControllerExperiment::GetBbrExperimentConfig());
}
TEST(CongestionControllerExperimentTest, BbrZeroParametersParsed) {
CongestionControllerExperiment::BbrExperimentConfig truth = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
webrtc::test::ScopedFieldTrials field_trials(
"WebRTC-BweCongestionController/Enabled,BBR,"
"0,0,0,0,0,0,0,0,0,0,0,"
"0,0,0,0,0,0/");
auto config = CongestionControllerExperiment::GetBbrExperimentConfig();
EXPECT_TRUE(config);
if (config)
ExpectEquals(truth, *config);
}
TEST(CongestionControllerExperimentTest, BbrNonZeroParametersParsed) {
CongestionControllerExperiment::BbrExperimentConfig truth = {
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25};
webrtc::test::ScopedFieldTrials field_trials(
"WebRTC-BweCongestionController/Enabled,BBR,"
"1,1,1,1,1,1,1,1,1,1,1,"
"0.25,0.25,0.25,0.25,0.25,0.25/");
auto config = CongestionControllerExperiment::GetBbrExperimentConfig();
EXPECT_TRUE(config);
if (config)
ExpectEquals(truth, *config);
}
} // namespace webrtc