xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/congestion_control/bbr2_startup.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/quic/core/congestion_control/bbr2_startup.h"
6 
7 #include "quiche/quic/core/congestion_control/bbr2_misc.h"
8 #include "quiche/quic/core/congestion_control/bbr2_sender.h"
9 #include "quiche/quic/core/quic_bandwidth.h"
10 #include "quiche/quic/core/quic_types.h"
11 #include "quiche/quic/platform/api/quic_flag_utils.h"
12 #include "quiche/quic/platform/api/quic_flags.h"
13 #include "quiche/quic/platform/api/quic_logging.h"
14 
15 namespace quic {
16 
Bbr2StartupMode(const Bbr2Sender * sender,Bbr2NetworkModel * model,QuicTime now)17 Bbr2StartupMode::Bbr2StartupMode(const Bbr2Sender* sender,
18                                  Bbr2NetworkModel* model, QuicTime now)
19     : Bbr2ModeBase(sender, model) {
20   // Increment, instead of reset startup stats, so we don't lose data recorded
21   // before QuicConnection switched send algorithm to BBRv2.
22   ++sender_->connection_stats_->slowstart_count;
23   if (!sender_->connection_stats_->slowstart_duration.IsRunning()) {
24     sender_->connection_stats_->slowstart_duration.Start(now);
25   }
26   // Enter() is never called for Startup, so the gains needs to be set here.
27   model_->set_pacing_gain(Params().startup_pacing_gain);
28   model_->set_cwnd_gain(Params().startup_cwnd_gain);
29 }
30 
Enter(QuicTime,const Bbr2CongestionEvent *)31 void Bbr2StartupMode::Enter(QuicTime /*now*/,
32                             const Bbr2CongestionEvent* /*congestion_event*/) {
33   QUIC_BUG(quic_bug_10463_1) << "Bbr2StartupMode::Enter should not be called";
34 }
35 
Leave(QuicTime now,const Bbr2CongestionEvent *)36 void Bbr2StartupMode::Leave(QuicTime now,
37                             const Bbr2CongestionEvent* /*congestion_event*/) {
38   sender_->connection_stats_->slowstart_duration.Stop(now);
39   // Clear bandwidth_lo if it's set during STARTUP.
40   model_->clear_bandwidth_lo();
41 }
42 
OnCongestionEvent(QuicByteCount,QuicTime,const AckedPacketVector &,const LostPacketVector &,const Bbr2CongestionEvent & congestion_event)43 Bbr2Mode Bbr2StartupMode::OnCongestionEvent(
44     QuicByteCount /*prior_in_flight*/, QuicTime /*event_time*/,
45     const AckedPacketVector& /*acked_packets*/,
46     const LostPacketVector& /*lost_packets*/,
47     const Bbr2CongestionEvent& congestion_event) {
48   if (model_->full_bandwidth_reached()) {
49     QUIC_BUG() << "In STARTUP, but full_bandwidth_reached is true.";
50     return Bbr2Mode::DRAIN;
51   }
52   if (!congestion_event.end_of_round_trip) {
53     return Bbr2Mode::STARTUP;
54   }
55   bool has_bandwidth_growth = model_->HasBandwidthGrowth(congestion_event);
56   if (Params().max_startup_queue_rounds > 0 && !has_bandwidth_growth) {
57     // 1.75 is less than the 2x CWND gain, but substantially more than 1.25x,
58     // the minimum bandwidth increase expected during STARTUP.
59     model_->CheckPersistentQueue(congestion_event, 1.75);
60   }
61   // TCP BBR always exits upon excessive losses. QUIC BBRv1 does not exit
62   // upon excessive losses, if enough bandwidth growth is observed or if the
63   // sample was app limited.
64   if (Params().always_exit_startup_on_excess_loss ||
65       (!congestion_event.last_packet_send_state.is_app_limited &&
66        !has_bandwidth_growth)) {
67     CheckExcessiveLosses(congestion_event);
68   }
69 
70   if (Params().decrease_startup_pacing_at_end_of_round) {
71     QUICHE_DCHECK_GT(model_->pacing_gain(), 0);
72     if (!congestion_event.last_packet_send_state.is_app_limited) {
73       // Multiply by startup_pacing_gain, so if the bandwidth doubles,
74       // the pacing gain will be the full startup_pacing_gain.
75       if (max_bw_at_round_beginning_ > QuicBandwidth::Zero()) {
76         const float bandwidth_ratio =
77             std::max(1., model_->MaxBandwidth().ToBitsPerSecond() /
78                              static_cast<double>(
79                                  max_bw_at_round_beginning_.ToBitsPerSecond()));
80         // Even when bandwidth isn't increasing, use a gain large enough to
81         // cause a full_bw_threshold increase.
82         const float new_gain =
83             ((bandwidth_ratio - 1) *
84              (Params().startup_pacing_gain - Params().full_bw_threshold)) +
85             Params().full_bw_threshold;
86         // Allow the pacing gain to decrease.
87         model_->set_pacing_gain(
88             std::min(Params().startup_pacing_gain, new_gain));
89         // Clear bandwidth_lo if it's less than the pacing rate.
90         // This avoids a constantly app-limited flow from having it's pacing
91         // gain effectively decreased below 1.25.
92         if (model_->bandwidth_lo() <
93             model_->MaxBandwidth() * model_->pacing_gain()) {
94           model_->clear_bandwidth_lo();
95         }
96       }
97       max_bw_at_round_beginning_ = model_->MaxBandwidth();
98     }
99   }
100 
101   // TODO(wub): Maybe implement STARTUP => PROBE_RTT.
102   return model_->full_bandwidth_reached() ? Bbr2Mode::DRAIN : Bbr2Mode::STARTUP;
103 }
104 
CheckExcessiveLosses(const Bbr2CongestionEvent & congestion_event)105 void Bbr2StartupMode::CheckExcessiveLosses(
106     const Bbr2CongestionEvent& congestion_event) {
107   QUICHE_DCHECK(congestion_event.end_of_round_trip);
108 
109   if (model_->full_bandwidth_reached()) {
110     return;
111   }
112 
113   // At the end of a round trip. Check if loss is too high in this round.
114   if (model_->IsInflightTooHigh(congestion_event,
115                                 Params().startup_full_loss_count)) {
116     QuicByteCount new_inflight_hi = model_->BDP();
117     if (Params().startup_loss_exit_use_max_delivered_for_inflight_hi) {
118       if (new_inflight_hi < model_->max_bytes_delivered_in_round()) {
119         new_inflight_hi = model_->max_bytes_delivered_in_round();
120       }
121     }
122     QUIC_DVLOG(3) << sender_ << " Exiting STARTUP due to loss at round "
123                   << model_->RoundTripCount()
124                   << ". inflight_hi:" << new_inflight_hi;
125     // TODO(ianswett): Add a shared method to set inflight_hi in the model.
126     model_->set_inflight_hi(new_inflight_hi);
127     model_->set_full_bandwidth_reached();
128     sender_->connection_stats_->bbr_exit_startup_due_to_loss = true;
129   }
130 }
131 
ExportDebugState() const132 Bbr2StartupMode::DebugState Bbr2StartupMode::ExportDebugState() const {
133   DebugState s;
134   s.full_bandwidth_reached = model_->full_bandwidth_reached();
135   s.full_bandwidth_baseline = model_->full_bandwidth_baseline();
136   s.round_trips_without_bandwidth_growth =
137       model_->rounds_without_bandwidth_growth();
138   return s;
139 }
140 
operator <<(std::ostream & os,const Bbr2StartupMode::DebugState & state)141 std::ostream& operator<<(std::ostream& os,
142                          const Bbr2StartupMode::DebugState& state) {
143   os << "[STARTUP] full_bandwidth_reached: " << state.full_bandwidth_reached
144      << "\n";
145   os << "[STARTUP] full_bandwidth_baseline: " << state.full_bandwidth_baseline
146      << "\n";
147   os << "[STARTUP] round_trips_without_bandwidth_growth: "
148      << state.round_trips_without_bandwidth_growth << "\n";
149   return os;
150 }
151 
Params() const152 const Bbr2Params& Bbr2StartupMode::Params() const { return sender_->Params(); }
153 
154 }  // namespace quic
155