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