mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-15 06:40:43 +01:00

These are useful for plotting creating data files that can be used to visualize and debug congestion controller behavior. Bug: webrtc:9467 Change-Id: I75b03a309b4b7d562fefe82a828ae1e6a9f069c8 Reviewed-on: https://webrtc-review.googlesource.com/86126 Commit-Queue: Sebastian Jansson <srte@webrtc.org> Reviewed-by: Björn Terelius <terelius@webrtc.org> Cr-Commit-Position: refs/heads/master@{#23822}
395 lines
15 KiB
C++
395 lines
15 KiB
C++
/*
|
|
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
// BBR (Bottleneck Bandwidth and RTT) congestion control algorithm.
|
|
// Based on the Quic BBR implementation in Chromium.
|
|
|
|
#ifndef MODULES_CONGESTION_CONTROLLER_BBR_BBR_NETWORK_CONTROLLER_H_
|
|
#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/bandwidth_sampler.h"
|
|
#include "modules/congestion_controller/bbr/loss_rate_filter.h"
|
|
#include "modules/congestion_controller/bbr/rtt_stats.h"
|
|
#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 {
|
|
namespace bbr {
|
|
|
|
typedef int64_t BbrRoundTripCount;
|
|
|
|
// BbrSender implements BBR congestion control algorithm. BBR aims to estimate
|
|
// the current available Bottleneck Bandwidth and RTT (hence the name), and
|
|
// regulates the pacing rate and the size of the congestion window based on
|
|
// those signals.
|
|
//
|
|
// BBR relies on pacing in order to function properly. Do not use BBR when
|
|
// pacing is disabled.
|
|
class BbrNetworkController : public NetworkControllerInterface {
|
|
public:
|
|
enum Mode {
|
|
// Startup phase of the connection.
|
|
STARTUP,
|
|
// After achieving the highest possible bandwidth during the startup, lower
|
|
// the pacing rate in order to drain the queue.
|
|
DRAIN,
|
|
// Cruising mode.
|
|
PROBE_BW,
|
|
// Temporarily slow down sending in order to empty the buffer and measure
|
|
// the real minimum RTT.
|
|
PROBE_RTT,
|
|
};
|
|
|
|
// Indicates how the congestion control limits the amount of bytes in flight.
|
|
enum RecoveryState {
|
|
// Do not limit.
|
|
NOT_IN_RECOVERY = 0,
|
|
// Allow an extra outstanding byte for each byte acknowledged.
|
|
CONSERVATION = 1,
|
|
// Allow 1.5 extra outstanding bytes for each byte acknowledged.
|
|
MEDIUM_GROWTH = 2,
|
|
// Allow two extra outstanding bytes for each byte acknowledged (slow
|
|
// start).
|
|
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
|
|
// control issues.
|
|
struct DebugState {
|
|
explicit DebugState(const BbrNetworkController& sender);
|
|
DebugState(const DebugState& state);
|
|
|
|
Mode mode;
|
|
DataRate max_bandwidth;
|
|
BbrRoundTripCount round_trip_count;
|
|
int gain_cycle_index;
|
|
DataSize congestion_window;
|
|
|
|
bool is_at_full_bandwidth;
|
|
DataRate bandwidth_at_last_round;
|
|
BbrRoundTripCount rounds_without_bandwidth_gain;
|
|
|
|
TimeDelta min_rtt;
|
|
Timestamp min_rtt_timestamp;
|
|
|
|
RecoveryState recovery_state;
|
|
DataSize recovery_window;
|
|
|
|
bool last_sample_is_app_limited;
|
|
int64_t end_of_app_limited_phase;
|
|
};
|
|
|
|
explicit BbrNetworkController(NetworkControllerConfig config);
|
|
~BbrNetworkController() override;
|
|
|
|
// NetworkControllerInterface
|
|
NetworkControlUpdate OnNetworkAvailability(NetworkAvailability msg) override;
|
|
NetworkControlUpdate OnNetworkRouteChange(NetworkRouteChange msg) override;
|
|
NetworkControlUpdate OnProcessInterval(ProcessInterval msg) override;
|
|
NetworkControlUpdate OnSentPacket(SentPacket msg) override;
|
|
NetworkControlUpdate OnStreamsConfig(StreamsConfig msg) override;
|
|
NetworkControlUpdate OnTargetRateConstraints(
|
|
TargetRateConstraints msg) override;
|
|
NetworkControlUpdate OnTransportPacketsFeedback(
|
|
TransportPacketsFeedback msg) override;
|
|
|
|
// Part of remote bitrate estimation api, not implemented for BBR
|
|
NetworkControlUpdate OnRemoteBitrateReport(RemoteBitrateReport msg) override;
|
|
NetworkControlUpdate OnRoundTripTimeUpdate(RoundTripTimeUpdate msg) override;
|
|
NetworkControlUpdate OnTransportLossReport(TransportLossReport msg) override;
|
|
|
|
NetworkControlUpdate CreateRateUpdate(Timestamp at_time) const;
|
|
|
|
private:
|
|
void Reset();
|
|
bool InSlowStart() const;
|
|
bool InRecovery() const;
|
|
bool IsProbingForMoreBandwidth() const;
|
|
|
|
bool CanSend(DataSize bytes_in_flight);
|
|
DataRate PacingRate() const;
|
|
DataRate BandwidthEstimate() const;
|
|
DataSize GetCongestionWindow() const;
|
|
|
|
double GetPacingGain(int round_offset) const;
|
|
|
|
void OnApplicationLimited(DataSize bytes_in_flight);
|
|
// End implementation of SendAlgorithmInterface.
|
|
|
|
typedef WindowedFilter<DataRate,
|
|
MaxFilter<DataRate>,
|
|
BbrRoundTripCount,
|
|
BbrRoundTripCount>
|
|
MaxBandwidthFilter;
|
|
|
|
typedef WindowedFilter<TimeDelta,
|
|
MaxFilter<TimeDelta>,
|
|
BbrRoundTripCount,
|
|
BbrRoundTripCount>
|
|
MaxAckDelayFilter;
|
|
|
|
typedef WindowedFilter<DataSize,
|
|
MaxFilter<DataSize>,
|
|
BbrRoundTripCount,
|
|
BbrRoundTripCount>
|
|
MaxAckHeightFilter;
|
|
|
|
// 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.
|
|
DataSize ProbeRttCongestionWindow() const;
|
|
// Returns true if the current min_rtt should be kept and we should not enter
|
|
// PROBE_RTT immediately.
|
|
bool ShouldExtendMinRttExpiry() const;
|
|
|
|
// Enters the STARTUP mode.
|
|
void EnterStartupMode();
|
|
// 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.
|
|
// |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.
|
|
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,
|
|
bool has_losses);
|
|
// Tracks for how many round-trips the bandwidth has not increased
|
|
// significantly.
|
|
void CheckIfFullBandwidthReached();
|
|
// Transitions from STARTUP to DRAIN and from DRAIN to PROBE_BW if
|
|
// appropriate.
|
|
void MaybeExitStartupOrDrain(const TransportPacketsFeedback&);
|
|
// Decides whether to enter or exit PROBE_RTT.
|
|
void MaybeEnterOrExitProbeRtt(const TransportPacketsFeedback& msg,
|
|
bool is_round_start,
|
|
bool min_rtt_expired);
|
|
// Determines whether BBR needs to enter, exit or advance state of the
|
|
// recovery.
|
|
void UpdateRecoveryState(int64_t last_acked_packet,
|
|
bool has_losses,
|
|
bool is_round_start);
|
|
|
|
// Updates the ack aggregation max filter in bytes.
|
|
void UpdateAckAggregationBytes(Timestamp ack_time,
|
|
DataSize newly_acked_bytes);
|
|
|
|
// Determines the appropriate pacing rate for the connection.
|
|
void CalculatePacingRate();
|
|
// Determines the appropriate congestion window for the connection.
|
|
void CalculateCongestionWindow(DataSize bytes_acked);
|
|
// Determines the approriate window that constrains the
|
|
// in-flight during recovery.
|
|
void CalculateRecoveryWindow(DataSize bytes_acked,
|
|
DataSize bytes_lost,
|
|
DataSize bytes_in_flight);
|
|
|
|
BbrControllerConfig config_;
|
|
|
|
RttStats rtt_stats_;
|
|
webrtc::Random random_;
|
|
LossRateFilter loss_rate_;
|
|
|
|
absl::optional<TargetRateConstraints> constraints_;
|
|
|
|
Mode mode_;
|
|
|
|
// 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 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.
|
|
int64_t current_round_trip_end_;
|
|
|
|
// The filter that tracks the maximum bandwidth over the multiple recent
|
|
// round-trips.
|
|
MaxBandwidthFilter max_bandwidth_;
|
|
|
|
DataRate default_bandwidth_;
|
|
|
|
// Tracks the maximum number of bytes acked faster than the sending rate.
|
|
MaxAckHeightFilter max_ack_height_;
|
|
|
|
// The time this aggregation started and the number of bytes acked during it.
|
|
absl::optional<Timestamp> aggregation_epoch_start_time_;
|
|
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_;
|
|
|
|
// The muliplier for calculating the max amount of extra CWND to add to
|
|
// compensate for ack aggregation.
|
|
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 last_rtt_;
|
|
// The time at which the current value of |min_rtt_| was assigned.
|
|
Timestamp min_rtt_timestamp_;
|
|
|
|
// The maximum allowed number of bytes in flight.
|
|
DataSize congestion_window_;
|
|
|
|
// The initial value of the |congestion_window_|.
|
|
DataSize initial_congestion_window_;
|
|
|
|
// The smallest value the |congestion_window_| can achieve.
|
|
DataSize min_congestion_window_;
|
|
|
|
// The largest value the |congestion_window_| can achieve.
|
|
DataSize max_congestion_window_;
|
|
|
|
// The current pacing rate of the connection.
|
|
DataRate pacing_rate_;
|
|
|
|
// The gain currently applied to the pacing rate.
|
|
double pacing_gain_;
|
|
// The gain currently applied to the congestion window.
|
|
double congestion_window_gain_;
|
|
|
|
// The gain used for the congestion window during PROBE_BW. Latched from
|
|
// quic_bbr_cwnd_gain flag.
|
|
const double congestion_window_gain_constant_;
|
|
// 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_;
|
|
|
|
// Number of round-trips in PROBE_BW mode, used for determining the current
|
|
// pacing gain cycle.
|
|
int cycle_current_offset_;
|
|
// The time at which the last pacing gain cycle was started.
|
|
Timestamp last_cycle_start_;
|
|
|
|
// Indicates whether the connection has reached the full bandwidth mode.
|
|
bool is_at_full_bandwidth_;
|
|
// Number of rounds during which there was no significant bandwidth increase.
|
|
BbrRoundTripCount rounds_without_bandwidth_gain_;
|
|
// The bandwidth compared to which the increase is measured.
|
|
DataRate bandwidth_at_last_round_;
|
|
|
|
// Set to true upon exiting quiescence.
|
|
bool exiting_quiescence_;
|
|
|
|
// 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.
|
|
absl::optional<Timestamp> exit_probe_rtt_at_;
|
|
// Indicates whether a round-trip has passed since PROBE_RTT became active.
|
|
bool probe_rtt_round_passed_;
|
|
|
|
// Indicates whether the most recent bandwidth sample was marked as
|
|
// app-limited.
|
|
bool last_sample_is_app_limited_;
|
|
|
|
// Current state of recovery.
|
|
RecoveryState recovery_state_;
|
|
// Receiving acknowledgement of a packet after |end_recovery_at_| will cause
|
|
// BBR to exit the recovery mode. A set value indicates at least one
|
|
// loss has been detected, so it must not be reset.
|
|
absl::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_;
|
|
TimeDelta min_rtt_since_last_probe_rtt_;
|
|
|
|
RTC_DISALLOW_COPY_AND_ASSIGN(BbrNetworkController);
|
|
};
|
|
|
|
// Used in log output
|
|
std::ostream& operator<<( // no-presubmit-check TODO(webrtc:8982)
|
|
std::ostream& os, // no-presubmit-check TODO(webrtc:8982)
|
|
const BbrNetworkController::Mode& mode);
|
|
|
|
} // namespace bbr
|
|
} // namespace webrtc
|
|
|
|
#endif // MODULES_CONGESTION_CONTROLLER_BBR_BBR_NETWORK_CONTROLLER_H_
|