Makes BBR more like the Quic implementation.

Bug: webrtc:8415
Change-Id: I2c21fbe88afec88726cbdd7c6e7626cccb07ce71
Reviewed-on: https://webrtc-review.googlesource.com/77762
Commit-Queue: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#23420}
This commit is contained in:
Sebastian Jansson 2018-05-28 18:21:02 +02:00 committed by Commit Bot
parent 535bde3752
commit 7645b18c04
3 changed files with 200 additions and 191 deletions

View File

@ -27,7 +27,7 @@ rtc_source_set("bbr_controller") {
"bbr_network_controller.h",
]
deps = [
":data_transfer_tracker",
":bandwidth_sampler",
":rtt_stats",
":windowed_filter",
"../../../api:optional",

View File

@ -156,22 +156,49 @@ BbrNetworkController::DebugState::DebugState(const BbrNetworkController& sender)
recovery_state(sender.recovery_state_),
recovery_window(sender.recovery_window_),
last_sample_is_app_limited(sender.last_sample_is_app_limited_),
end_of_app_limited_phase(sender.end_of_app_limited_phase_) {}
end_of_app_limited_phase(sender.sampler_->end_of_app_limited_phase()) {}
BbrNetworkController::DebugState::DebugState(const DebugState& state) = default;
BbrNetworkController::BbrNetworkController(NetworkControllerConfig config)
: random_(10),
: rtt_stats_(),
random_(10),
mode_(STARTUP),
sampler_(new BandwidthSampler()),
round_trip_count_(0),
last_sent_packet_(0),
current_round_trip_end_(0),
max_bandwidth_(kBandwidthWindowSize, DataRate::Zero(), 0),
default_bandwidth_(DataRate::kbps(kInitialBandwidthKbps)),
max_ack_height_(kBandwidthWindowSize, DataSize::Zero(), 0),
aggregation_epoch_start_time_(),
aggregation_epoch_bytes_(DataSize::Zero()),
bytes_acked_since_queue_drained_(DataSize::Zero()),
max_aggregation_bytes_multiplier_(0),
min_rtt_(TimeDelta::Zero()),
last_rtt_(TimeDelta::Zero()),
min_rtt_timestamp_(Timestamp::ms(0)),
congestion_window_(DataSize::bytes(kInitialCongestionWindowBytes)),
initial_congestion_window_(
DataSize::bytes(kInitialCongestionWindowBytes)),
max_congestion_window_(DataSize::bytes(kDefaultMaxCongestionWindowBytes)),
pacing_rate_(DataRate::Zero()),
pacing_gain_(1),
congestion_window_gain_constant_(kProbeBWCongestionWindowGain),
rtt_variance_weight_(kBbrRttVariationWeight),
recovery_window_(max_congestion_window_) {
cycle_current_offset_(0),
last_cycle_start_(Timestamp::ms(0)),
is_at_full_bandwidth_(false),
rounds_without_bandwidth_gain_(0),
bandwidth_at_last_round_(DataRate::Zero()),
exit_probe_rtt_at_(),
probe_rtt_round_passed_(false),
last_sample_is_app_limited_(false),
recovery_state_(NOT_IN_RECOVERY),
end_recovery_at_(),
recovery_window_(max_congestion_window_),
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())
@ -181,6 +208,7 @@ BbrNetworkController::BbrNetworkController(NetworkControllerConfig config)
if (config_.num_startup_rtts > 0) {
EnterStartupMode();
} else {
is_at_full_bandwidth_ = true;
EnterProbeBandwidthMode(constraints_->at_time);
}
}
@ -292,11 +320,14 @@ bool BbrNetworkController::InSlowStart() const {
}
NetworkControlUpdate BbrNetworkController::OnSentPacket(SentPacket msg) {
last_send_time_ = msg.send_time;
last_sent_packet_ = msg.sequence_number;
if (!aggregation_epoch_start_time_) {
aggregation_epoch_start_time_ = msg.send_time;
aggregation_epoch_bytes_ = DataSize::Zero();
}
sampler_->OnPacketSent(msg.send_time, msg.sequence_number, msg.size,
msg.data_in_flight);
return NetworkControlUpdate();
}
@ -358,44 +389,39 @@ NetworkControlUpdate BbrNetworkController::OnTransportPacketsFeedback(
rtt_stats_.UpdateRtt(send_delta, TimeDelta::Zero(), feedback_recv_time);
}
DataSize bytes_in_flight = msg.data_in_flight;
DataSize total_acked_size = DataSize::Zero();
const DataSize total_data_acked_before = sampler_->total_data_acked();
bool is_round_start = false;
bool min_rtt_expired = false;
std::vector<PacketResult> acked_packets = msg.ReceivedWithSendInfo();
std::vector<PacketResult> lost_packets = msg.LostWithSendInfo();
DiscardLostPackets(lost_packets);
std::vector<PacketResult> acked_packets = msg.ReceivedWithSendInfo();
// Input the new data into the BBR model of the connection.
if (!acked_packets.empty()) {
for (const PacketResult& packet : acked_packets) {
const SentPacket& sent_packet = *packet.sent_packet;
send_ack_tracker_.AddSample(sent_packet.size, sent_packet.send_time,
msg.feedback_time);
total_acked_size += sent_packet.size;
}
Timestamp last_acked_send_time =
acked_packets.rbegin()->sent_packet->send_time;
is_round_start = UpdateRoundTripCounter(last_acked_send_time);
UpdateBandwidth(msg.feedback_time, acked_packets);
// Min rtt will be the rtt for the last packet, since all packets are acked
// at the same time.
Timestamp last_send_time = acked_packets.back().sent_packet->send_time;
min_rtt_expired = UpdateMinRtt(msg.feedback_time, last_send_time);
UpdateRecoveryState(last_acked_send_time, !lost_packets.empty(),
int64_t last_acked_packet =
acked_packets.rbegin()->sent_packet->sequence_number;
is_round_start = UpdateRoundTripCounter(last_acked_packet);
min_rtt_expired =
UpdateBandwidthAndMinRtt(msg.feedback_time, acked_packets);
UpdateRecoveryState(last_acked_packet, !lost_packets.empty(),
is_round_start);
UpdateAckAggregationBytes(msg.feedback_time, total_acked_size);
const DataSize data_acked =
sampler_->total_data_acked() - total_data_acked_before;
UpdateAckAggregationBytes(msg.feedback_time, data_acked);
if (max_aggregation_bytes_multiplier_ > 0) {
if (msg.data_in_flight <=
1.25 * GetTargetCongestionWindow(pacing_gain_)) {
bytes_acked_since_queue_drained_ = DataSize::Zero();
} else {
bytes_acked_since_queue_drained_ += total_acked_size;
bytes_acked_since_queue_drained_ += data_acked;
}
}
}
}
total_bytes_acked_ += total_acked_size;
// Handle logic specific to PROBE_BW mode.
if (mode_ == PROBE_BW) {
@ -413,16 +439,22 @@ NetworkControlUpdate BbrNetworkController::OnTransportPacketsFeedback(
MaybeEnterOrExitProbeRtt(msg, is_round_start, min_rtt_expired);
// Calculate number of packets acked and lost.
DataSize bytes_lost = DataSize::Zero();
DataSize data_acked = sampler_->total_data_acked() - total_data_acked_before;
DataSize data_lost = DataSize::Zero();
for (const PacketResult& packet : lost_packets) {
bytes_lost += packet.sent_packet->size;
data_lost += packet.sent_packet->size;
}
// After the model is updated, recalculate the pacing rate and congestion
// window.
CalculatePacingRate();
CalculateCongestionWindow(total_acked_size);
CalculateRecoveryWindow(total_acked_size, bytes_lost, bytes_in_flight);
CalculateCongestionWindow(data_acked);
CalculateRecoveryWindow(data_acked, data_lost, msg.data_in_flight);
// Cleanup internal state.
if (!acked_packets.empty()) {
sampler_->RemoveObsoletePackets(
acked_packets.back().sent_packet->sequence_number);
}
return CreateRateUpdate(msg.feedback_time);
}
@ -485,32 +517,54 @@ void BbrNetworkController::EnterProbeBandwidthMode(Timestamp now) {
pacing_gain_ = GetPacingGain(cycle_current_offset_);
}
bool BbrNetworkController::UpdateRoundTripCounter(
Timestamp last_acked_send_time) {
if (last_acked_send_time > current_round_trip_end_) {
void BbrNetworkController::DiscardLostPackets(
const std::vector<PacketResult>& lost_packets) {
for (const PacketResult& packet : lost_packets) {
sampler_->OnPacketLost(packet.sent_packet->sequence_number);
}
}
bool BbrNetworkController::UpdateRoundTripCounter(int64_t last_acked_packet) {
if (last_acked_packet > current_round_trip_end_) {
round_trip_count_++;
current_round_trip_end_ = last_send_time_;
current_round_trip_end_ = last_sent_packet_;
return true;
}
return false;
}
bool BbrNetworkController::UpdateMinRtt(Timestamp ack_time,
Timestamp last_packet_send_time) {
// Note: This sample does not account for delayed acknowledgement time. This
// means that the RTT measurements here can be artificially high, especially
// on low bandwidth connections.
TimeDelta sample_rtt = ack_time - last_packet_send_time;
bool BbrNetworkController::UpdateBandwidthAndMinRtt(
Timestamp now,
const std::vector<PacketResult>& acked_packets) {
TimeDelta sample_rtt = TimeDelta::PlusInfinity();
for (const auto& packet : acked_packets) {
BandwidthSample bandwidth_sample = sampler_->OnPacketAcknowledged(
now, packet.sent_packet->sequence_number);
last_sample_is_app_limited_ = bandwidth_sample.is_app_limited;
if (!bandwidth_sample.rtt.IsZero()) {
sample_rtt = std::min(sample_rtt, bandwidth_sample.rtt);
}
if (!bandwidth_sample.is_app_limited ||
bandwidth_sample.bandwidth > BandwidthEstimate()) {
max_bandwidth_.Update(bandwidth_sample.bandwidth, round_trip_count_);
}
}
// If none of the RTT samples are valid, return immediately.
if (sample_rtt.IsInfinite()) {
return false;
}
last_rtt_ = sample_rtt;
min_rtt_since_last_probe_rtt_ =
std::min(min_rtt_since_last_probe_rtt_, sample_rtt);
const TimeDelta kMinRttExpiry = TimeDelta::seconds(kMinRttExpirySeconds);
// Do not expire min_rtt if none was ever available.
bool min_rtt_expired =
!min_rtt_.IsZero() &&
(ack_time >
(min_rtt_timestamp_ + TimeDelta::seconds(kMinRttExpirySeconds)));
!min_rtt_.IsZero() && (now > (min_rtt_timestamp_ + kMinRttExpiry));
if (min_rtt_expired || sample_rtt < min_rtt_ || min_rtt_.IsZero()) {
if (ShouldExtendMinRttExpiry()) {
@ -518,7 +572,7 @@ bool BbrNetworkController::UpdateMinRtt(Timestamp ack_time,
} else {
min_rtt_ = sample_rtt;
}
min_rtt_timestamp_ = ack_time;
min_rtt_timestamp_ = now;
// Reset since_last_probe_rtt fields.
min_rtt_since_last_probe_rtt_ = TimeDelta::PlusInfinity();
app_limited_since_last_probe_rtt_ = false;
@ -527,37 +581,6 @@ bool BbrNetworkController::UpdateMinRtt(Timestamp ack_time,
return min_rtt_expired;
}
void BbrNetworkController::UpdateBandwidth(
Timestamp ack_time,
const std::vector<PacketResult>& acked_packets) {
// There are two possible maximum receive bandwidths based on the duration
// from send to ack of a packet, either including or excluding the time until
// the current ack was received. Therefore looking at the last and the first
// packet is enough. This holds if at most one feedback was received during
// the sending of the acked packets.
std::array<const PacketResult, 2> packets = {
{acked_packets.front(), acked_packets.back()}};
for (const PacketResult& packet : packets) {
const Timestamp& send_time = packet.sent_packet->send_time;
is_app_limited_ = send_time > end_of_app_limited_phase_;
auto result = send_ack_tracker_.GetRatesByAckTime(send_time, ack_time);
if (result.acked_data == DataSize::Zero())
continue;
send_ack_tracker_.ClearOldSamples(send_time);
DataRate ack_rate = result.acked_data / result.ack_timespan;
DataRate send_rate = result.send_timespan.IsZero()
? DataRate::Infinity()
: result.acked_data / result.send_timespan;
DataRate bandwidth = std::min(send_rate, ack_rate);
if (!bandwidth.IsFinite())
continue;
if (!is_app_limited_ || bandwidth > BandwidthEstimate()) {
max_bandwidth_.Update(bandwidth, round_trip_count_);
}
}
}
bool BbrNetworkController::ShouldExtendMinRttExpiry() const {
if (config_.probe_rtt_disabled_if_app_limited &&
app_limited_since_last_probe_rtt_) {
@ -629,7 +652,7 @@ void BbrNetworkController::CheckIfFullBandwidthReached() {
rounds_without_bandwidth_gain_++;
if ((rounds_without_bandwidth_gain_ >= config_.num_startup_rtts) ||
(exit_startup_on_loss_ && InRecovery())) {
(config_.exit_startup_on_loss && InRecovery())) {
is_at_full_bandwidth_ = true;
}
}
@ -667,8 +690,7 @@ void BbrNetworkController::MaybeEnterOrExitProbeRtt(
}
if (mode_ == PROBE_RTT) {
is_app_limited_ = true;
end_of_app_limited_phase_ = last_send_time_;
sampler_->OnAppLimited();
if (!exit_probe_rtt_at_) {
// If the window has reached the appropriate size, schedule exiting
@ -695,12 +717,12 @@ void BbrNetworkController::MaybeEnterOrExitProbeRtt(
}
}
void BbrNetworkController::UpdateRecoveryState(Timestamp last_acked_send_time,
void BbrNetworkController::UpdateRecoveryState(int64_t last_acked_packet,
bool has_losses,
bool is_round_start) {
// Exit recovery when there are no losses for a round.
if (has_losses) {
end_recovery_at_ = last_acked_send_time;
end_recovery_at_ = last_sent_packet_;
}
switch (recovery_state_) {
@ -716,7 +738,7 @@ void BbrNetworkController::UpdateRecoveryState(Timestamp last_acked_send_time,
recovery_window_ = DataSize::Zero();
// Since the conservation phase is meant to be lasting for a whole
// round, extend the current round as if it were started right now.
current_round_trip_end_ = last_send_time_;
current_round_trip_end_ = last_sent_packet_;
}
break;
@ -729,7 +751,7 @@ void BbrNetworkController::UpdateRecoveryState(Timestamp last_acked_send_time,
case GROWTH:
// Exit recovery if appropriate.
if (!has_losses && end_recovery_at_ &&
last_acked_send_time > *end_recovery_at_) {
last_acked_packet > *end_recovery_at_) {
recovery_state_ = NOT_IN_RECOVERY;
}
@ -828,7 +850,7 @@ void BbrNetworkController::CalculateCongestionWindow(DataSize bytes_acked) {
congestion_window_ =
std::min(target_window, congestion_window_ + bytes_acked);
} else if (congestion_window_ < target_window ||
total_bytes_acked_ < initial_congestion_window_) {
sampler_->total_data_acked() < initial_congestion_window_) {
// If the connection is not yet out of startup phase, do not decrease the
// window.
congestion_window_ = congestion_window_ + bytes_acked;
@ -873,7 +895,7 @@ void BbrNetworkController::CalculateRecoveryWindow(DataSize bytes_acked,
recovery_window_ += bytes_acked / 2;
}
// Sanity checks. Ensure that we always allow to send at leastś
// Sanity checks. Ensure that we always allow to send at least
// |bytes_acked| in response.
recovery_window_ = std::max(recovery_window_, bytes_in_flight + bytes_acked);
recovery_window_ = std::max(kMinimumCongestionWindow, recovery_window_);
@ -885,12 +907,10 @@ void BbrNetworkController::OnApplicationLimited(DataSize bytes_in_flight) {
}
app_limited_since_last_probe_rtt_ = true;
sampler_->OnAppLimited();
is_app_limited_ = true;
end_of_app_limited_phase_ = last_send_time_;
RTC_LOG(LS_INFO) << "Becoming application limited. Last sent time: "
<< ToString(last_send_time_)
RTC_LOG(LS_INFO) << "Becoming application limited. Last sent packet: "
<< last_sent_packet_
<< ", CWND: " << ToString(GetCongestionWindow());
}
} // namespace bbr

View File

@ -15,12 +15,13 @@
#define MODULES_CONGESTION_CONTROLLER_BBR_BBR_NETWORK_CONTROLLER_H_
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "api/transport/network_control.h"
#include "api/transport/network_types.h"
#include "modules/congestion_controller/bbr/data_transfer_tracker.h"
#include "modules/congestion_controller/bbr/bandwidth_sampler.h"
#include "modules/congestion_controller/bbr/rtt_stats.h"
#include "modules/congestion_controller/bbr/windowed_filter.h"
@ -91,7 +92,7 @@ class BbrNetworkController : public NetworkControllerInterface {
DataSize recovery_window;
bool last_sample_is_app_limited;
Timestamp end_of_app_limited_phase;
int64_t end_of_app_limited_phase;
};
explicit BbrNetworkController(NetworkControllerConfig config);
@ -114,49 +115,6 @@ class BbrNetworkController : public NetworkControllerInterface {
NetworkControlUpdate OnTransportLossReport(TransportLossReport msg) override;
private:
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;
// 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;
// Used as the initial packet conservation mode when first entering
// recovery.
RecoveryState initial_conservation_in_startup;
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;
};
void Reset();
NetworkControlUpdate CreateRateUpdate(Timestamp at_time);
@ -195,7 +153,9 @@ class BbrNetworkController : public NetworkControllerInterface {
// Returns the current estimate of the RTT of the connection. Outside of the
// edge cases, this is minimum RTT.
TimeDelta GetMinRtt() const;
// Returns whether the connection has achieved full bandwidth required to exit
// the slow start.
bool IsAtFullBandwidth() const;
// Computes the target congestion window using the specified gain.
DataSize GetTargetCongestionWindow(double gain) const;
// The target congestion window during PROBE_RTT.
@ -209,14 +169,16 @@ class BbrNetworkController : public NetworkControllerInterface {
// Enters the PROBE_BW mode.
void EnterProbeBandwidthMode(Timestamp now);
// Discards the lost packets from BandwidthSampler state.
void DiscardLostPackets(const std::vector<PacketResult>& lost_packets);
// Updates the round-trip counter if a round-trip has passed. Returns true if
// the counter has been advanced.
bool UpdateRoundTripCounter(Timestamp last_acked_timestamp);
// |last_acked_packet| is the sequence number of the last acked packet.
bool UpdateRoundTripCounter(int64_t last_acked_packet);
// Updates the current bandwidth and min_rtt estimate based on the samples for
// the received acknowledgements. Returns true if min_rtt has expired.
void UpdateBandwidth(Timestamp now,
const std::vector<PacketResult>& acked_packets);
bool UpdateMinRtt(Timestamp ack_time, Timestamp last_packet_send_time);
bool UpdateBandwidthAndMinRtt(Timestamp now,
const std::vector<PacketResult>& acked_packets);
// Updates the current gain used in PROBE_BW mode.
void UpdateGainCyclePhase(Timestamp now,
DataSize prior_in_flight,
@ -233,7 +195,7 @@ class BbrNetworkController : public NetworkControllerInterface {
bool min_rtt_expired);
// Determines whether BBR needs to enter, exit or advance state of the
// recovery.
void UpdateRecoveryState(Timestamp last_acked_send_time,
void UpdateRecoveryState(int64_t last_acked_packet,
bool has_losses,
bool is_round_start);
@ -245,7 +207,7 @@ class BbrNetworkController : public NetworkControllerInterface {
void CalculatePacingRate();
// Determines the appropriate congestion window for the connection.
void CalculateCongestionWindow(DataSize bytes_acked);
// Determines the approriate wQuicPacketNumberindow that constrains the
// Determines the approriate window that constrains the
// in-flight during recovery.
void CalculateRecoveryWindow(DataSize bytes_acked,
DataSize bytes_lost,
@ -254,38 +216,22 @@ class BbrNetworkController : public NetworkControllerInterface {
RttStats rtt_stats_;
webrtc::Random random_;
DataTransferTracker send_ack_tracker_;
rtc::Optional<TargetRateConstraints> constraints_;
Mode mode_ = STARTUP;
Mode mode_;
BbrControllerConfig config_;
// The total number of congestion controlled bytes which were acknowledged.
DataSize total_bytes_acked_ = DataSize::Zero();
// The time at which the last acknowledged packet was sent. Set to
// Timestamp::ms(0) if no valid timestamp is available.
Timestamp last_acked_packet_sent_time_ = Timestamp::ms(0);
// The time at which the most recent packet was acknowledged.
Timestamp last_acked_packet_ack_time_ = Timestamp::ms(0);
bool is_app_limited_ = false;
// The packet that will be acknowledged after this one will cause the sampler
// to exit the app-limited phase.
Timestamp end_of_app_limited_phase_ = Timestamp::ms(0);
// Bandwidth sampler provides BBR with the bandwidth measurements at
// individual points.
std::unique_ptr<BandwidthSampler> sampler_;
// The number of the round trips that have occurred during the connection.
BbrRoundTripCount round_trip_count_ = 0;
// The send time of the most recently sent packet.
Timestamp last_send_time_ = Timestamp::ms(0);
// The packet number of the most recently sent packet.
int64_t last_sent_packet_;
// Acknowledgement of any packet after |current_round_trip_end_| will cause
// the round trip counter to advance.
Timestamp current_round_trip_end_ = Timestamp::ms(0);
int64_t current_round_trip_end_;
// The filter that tracks the maximum bandwidth over the multiple recent
// round-trips.
@ -298,22 +244,22 @@ class BbrNetworkController : public NetworkControllerInterface {
// The time this aggregation started and the number of bytes acked during it.
rtc::Optional<Timestamp> aggregation_epoch_start_time_;
DataSize aggregation_epoch_bytes_ = DataSize::Zero();
DataSize aggregation_epoch_bytes_;
// The number of bytes acknowledged since the last time bytes in flight
// dropped below the target window.
DataSize bytes_acked_since_queue_drained_ = DataSize::Zero();
DataSize bytes_acked_since_queue_drained_;
// The muliplier for calculating the max amount of extra CWND to add to
// compensate for ack aggregation.
double max_aggregation_bytes_multiplier_ = 0;
double max_aggregation_bytes_multiplier_;
// Minimum RTT estimate. Automatically expires within 10 seconds (and
// triggers PROBE_RTT mode) if no new value is sampled during that period.
TimeDelta min_rtt_ = TimeDelta::Zero();
TimeDelta last_rtt_ = TimeDelta::Zero();
TimeDelta min_rtt_;
TimeDelta last_rtt_;
// The time at which the current value of |min_rtt_| was assigned.
Timestamp min_rtt_timestamp_ = Timestamp::ms(0);
Timestamp min_rtt_timestamp_;
// The maximum allowed number of bytes in flight.
DataSize congestion_window_;
@ -325,12 +271,12 @@ class BbrNetworkController : public NetworkControllerInterface {
DataSize max_congestion_window_;
// The current pacing rate of the connection.
DataRate pacing_rate_ = DataRate::Zero();
DataRate pacing_rate_;
// The gain currently applied to the pacing rate.
double pacing_gain_ = 1;
double pacing_gain_;
// The gain currently applied to the congestion window.
double congestion_window_gain_ = 1;
double congestion_window_gain_;
// The gain used for the congestion window during PROBE_BW. Latched from
// quic_bbr_cwnd_gain flag.
@ -338,45 +284,88 @@ class BbrNetworkController : public NetworkControllerInterface {
// The coefficient by which mean RTT variance is added to the congestion
// window. Latched from quic_bbr_rtt_variation_weight flag.
const double rtt_variance_weight_;
// If true, exit startup if 1RTT has passed with no bandwidth increase and
// the connection is in recovery.
bool exit_startup_on_loss_ = false;
// Number of round-trips in PROBE_BW mode, used for determining the current
// pacing gain cycle.
int cycle_current_offset_ = 0;
int cycle_current_offset_;
// The time at which the last pacing gain cycle was started.
Timestamp last_cycle_start_ = Timestamp::ms(0);
Timestamp last_cycle_start_;
// Indicates whether the connection has reached the full bandwidth mode.
bool is_at_full_bandwidth_ = false;
bool is_at_full_bandwidth_;
// Number of rounds during which there was no significant bandwidth increase.
BbrRoundTripCount rounds_without_bandwidth_gain_ = 0;
BbrRoundTripCount rounds_without_bandwidth_gain_;
// The bandwidth compared to which the increase is measured.
DataRate bandwidth_at_last_round_ = DataRate::Zero();
DataRate bandwidth_at_last_round_;
// Time at which PROBE_RTT has to be exited. Setting it to zero indicates
// that the time is yet unknown as the number of packets in flight has not
// reached the required value.
rtc::Optional<Timestamp> exit_probe_rtt_at_;
// Indicates whether a round-trip has passed since PROBE_RTT became active.
bool probe_rtt_round_passed_ = false;
bool probe_rtt_round_passed_;
// Indicates whether the most recent bandwidth sample was marked as
// app-limited.
bool last_sample_is_app_limited_ = false;
bool last_sample_is_app_limited_;
// Current state of recovery.
RecoveryState recovery_state_ = NOT_IN_RECOVERY;
RecoveryState recovery_state_;
// Receiving acknowledgement of a packet after |end_recovery_at_| will cause
// BBR to exit the recovery mode. A value after epoch indicates at least one
// loss has been detected, so it must not be set back to epoch.
rtc::Optional<Timestamp> end_recovery_at_;
// BBR to exit the recovery mode. An unset value indicates at least one
// loss has been detected, so it must not be reset.
rtc::Optional<int64_t> end_recovery_at_;
// A window used to limit the number of bytes in flight during loss recovery.
DataSize recovery_window_;
bool app_limited_since_last_probe_rtt_ = false;
TimeDelta min_rtt_since_last_probe_rtt_ = TimeDelta::PlusInfinity();
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_;
RTC_DISALLOW_COPY_AND_ASSIGN(BbrNetworkController);
};