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 "net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.h"
6 
7 #include "net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h"
8 #include "net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h"
9 #include "net/third_party/quiche/src/quic/core/quic_bandwidth.h"
10 #include "net/third_party/quiche/src/quic/core/quic_types.h"
11 #include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
12 
13 namespace quic {
14 
Bbr2StartupMode(const Bbr2Sender * sender,Bbr2NetworkModel * model,QuicTime now)15 Bbr2StartupMode::Bbr2StartupMode(const Bbr2Sender* sender,
16                                  Bbr2NetworkModel* model,
17                                  QuicTime now)
18     : Bbr2ModeBase(sender, model),
19       full_bandwidth_reached_(false),
20       full_bandwidth_baseline_(QuicBandwidth::Zero()),
21       rounds_without_bandwidth_growth_(0) {
22   // Clear some startup stats if |sender_->connection_stats_| has been used by
23   // another sender, which happens e.g. when QuicConnection switch send
24   // algorithms.
25   sender_->connection_stats_->slowstart_count = 1;
26   sender_->connection_stats_->slowstart_duration = QuicTimeAccumulator();
27   sender_->connection_stats_->slowstart_duration.Start(now);
28 }
29 
Enter(QuicTime,const Bbr2CongestionEvent *)30 void Bbr2StartupMode::Enter(QuicTime /*now*/,
31                             const Bbr2CongestionEvent* /*congestion_event*/) {
32   QUIC_BUG << "Bbr2StartupMode::Enter should not be called";
33 }
34 
Leave(QuicTime now,const Bbr2CongestionEvent *)35 void Bbr2StartupMode::Leave(QuicTime now,
36                             const Bbr2CongestionEvent* /*congestion_event*/) {
37   sender_->connection_stats_->slowstart_duration.Stop(now);
38 }
39 
OnCongestionEvent(QuicByteCount,QuicTime,const AckedPacketVector &,const LostPacketVector &,const Bbr2CongestionEvent & congestion_event)40 Bbr2Mode Bbr2StartupMode::OnCongestionEvent(
41     QuicByteCount /*prior_in_flight*/,
42     QuicTime /*event_time*/,
43     const AckedPacketVector& /*acked_packets*/,
44     const LostPacketVector& /*lost_packets*/,
45     const Bbr2CongestionEvent& congestion_event) {
46   CheckFullBandwidthReached(congestion_event);
47 
48   CheckExcessiveLosses(congestion_event);
49 
50   model_->set_pacing_gain(Params().startup_gain);
51   model_->set_cwnd_gain(Params().startup_gain);
52 
53   // TODO(wub): Maybe implement STARTUP => PROBE_RTT.
54   return full_bandwidth_reached_ ? Bbr2Mode::DRAIN : Bbr2Mode::STARTUP;
55 }
56 
CheckFullBandwidthReached(const Bbr2CongestionEvent & congestion_event)57 void Bbr2StartupMode::CheckFullBandwidthReached(
58     const Bbr2CongestionEvent& congestion_event) {
59   DCHECK(!full_bandwidth_reached_);
60   if (full_bandwidth_reached_ || !congestion_event.end_of_round_trip ||
61       congestion_event.last_sample_is_app_limited) {
62     return;
63   }
64 
65   QuicBandwidth threshold =
66       full_bandwidth_baseline_ * Params().startup_full_bw_threshold;
67 
68   if (model_->MaxBandwidth() >= threshold) {
69     QUIC_DVLOG(3)
70         << sender_
71         << " CheckFullBandwidthReached at end of round. max_bandwidth:"
72         << model_->MaxBandwidth() << ", threshold:" << threshold
73         << " (Still growing)  @ " << congestion_event.event_time;
74     full_bandwidth_baseline_ = model_->MaxBandwidth();
75     rounds_without_bandwidth_growth_ = 0;
76     return;
77   }
78 
79   ++rounds_without_bandwidth_growth_;
80   full_bandwidth_reached_ =
81       rounds_without_bandwidth_growth_ >= Params().startup_full_bw_rounds;
82   QUIC_DVLOG(3) << sender_
83                 << " CheckFullBandwidthReached at end of round. max_bandwidth:"
84                 << model_->MaxBandwidth() << ", threshold:" << threshold
85                 << " rounds_without_growth:" << rounds_without_bandwidth_growth_
86                 << " full_bw_reached:" << full_bandwidth_reached_ << "  @ "
87                 << congestion_event.event_time;
88 }
89 
CheckExcessiveLosses(const Bbr2CongestionEvent & congestion_event)90 void Bbr2StartupMode::CheckExcessiveLosses(
91     const Bbr2CongestionEvent& congestion_event) {
92   if (full_bandwidth_reached_) {
93     return;
94   }
95 
96   const int64_t loss_events_in_round = model_->loss_events_in_round();
97 
98   // TODO(wub): In TCP, loss based exit only happens at end of a loss round, in
99   // QUIC we use the end of the normal round here. It is possible to exit after
100   // any congestion event, using information of the "rolling round".
101   if (!congestion_event.end_of_round_trip) {
102     return;
103   }
104 
105   QUIC_DVLOG(3)
106       << sender_
107       << " CheckExcessiveLosses at end of round. loss_events_in_round:"
108       << loss_events_in_round
109       << ", threshold:" << Params().startup_full_loss_count << "  @ "
110       << congestion_event.event_time;
111 
112   // At the end of a round trip. Check if loss is too high in this round.
113   if (loss_events_in_round >= Params().startup_full_loss_count &&
114       model_->IsInflightTooHigh(congestion_event)) {
115     const QuicByteCount bdp = model_->BDP(model_->MaxBandwidth());
116     QUIC_DVLOG(3) << sender_
117                   << " Exiting STARTUP due to loss. inflight_hi:" << bdp;
118     model_->set_inflight_hi(bdp);
119 
120     full_bandwidth_reached_ = true;
121     sender_->connection_stats_->bbr_exit_startup_due_to_loss = true;
122   }
123 }
124 
ExportDebugState() const125 Bbr2StartupMode::DebugState Bbr2StartupMode::ExportDebugState() const {
126   DebugState s;
127   s.full_bandwidth_reached = full_bandwidth_reached_;
128   s.full_bandwidth_baseline = full_bandwidth_baseline_;
129   s.round_trips_without_bandwidth_growth = rounds_without_bandwidth_growth_;
130   return s;
131 }
132 
operator <<(std::ostream & os,const Bbr2StartupMode::DebugState & state)133 std::ostream& operator<<(std::ostream& os,
134                          const Bbr2StartupMode::DebugState& state) {
135   os << "[STARTUP] full_bandwidth_reached: " << state.full_bandwidth_reached
136      << "\n";
137   os << "[STARTUP] full_bandwidth_baseline: " << state.full_bandwidth_baseline
138      << "\n";
139   os << "[STARTUP] round_trips_without_bandwidth_growth: "
140      << state.round_trips_without_bandwidth_growth << "\n";
141   return os;
142 }
143 
Params() const144 const Bbr2Params& Bbr2StartupMode::Params() const {
145   return sender_->Params();
146 }
147 
148 }  // namespace quic
149