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_sender.h"
6
7 #include <cstddef>
8
9 #include "quiche/quic/core/congestion_control/bandwidth_sampler.h"
10 #include "quiche/quic/core/congestion_control/bbr2_drain.h"
11 #include "quiche/quic/core/congestion_control/bbr2_misc.h"
12 #include "quiche/quic/core/crypto/crypto_protocol.h"
13 #include "quiche/quic/core/quic_bandwidth.h"
14 #include "quiche/quic/core/quic_tag.h"
15 #include "quiche/quic/core/quic_types.h"
16 #include "quiche/quic/platform/api/quic_flag_utils.h"
17 #include "quiche/quic/platform/api/quic_flags.h"
18 #include "quiche/quic/platform/api/quic_logging.h"
19 #include "quiche/common/platform/api/quiche_logging.h"
20 #include "quiche/common/print_elements.h"
21
22 namespace quic {
23
24 namespace {
25 // Constants based on TCP defaults.
26 // The minimum CWND to ensure delayed acks don't reduce bandwidth measurements.
27 // Does not inflate the pacing rate.
28 const QuicByteCount kDefaultMinimumCongestionWindow = 4 * kMaxSegmentSize;
29
30 const float kInitialPacingGain = 2.885f;
31
32 const int kMaxModeChangesPerCongestionEvent = 4;
33 } // namespace
34
35 // Call |member_function_call| based on the current Bbr2Mode we are in. e.g.
36 //
37 // auto result = BBR2_MODE_DISPATCH(Foo());
38 //
39 // is equivalent to:
40 //
41 // Bbr2ModeBase& Bbr2Sender::GetCurrentMode() {
42 // if (mode_ == Bbr2Mode::STARTUP) { return startup_; }
43 // if (mode_ == Bbr2Mode::DRAIN) { return drain_; }
44 // ...
45 // }
46 // auto result = GetCurrentMode().Foo();
47 //
48 // Except that BBR2_MODE_DISPATCH guarantees the call to Foo() is non-virtual.
49 //
50 #define BBR2_MODE_DISPATCH(member_function_call) \
51 (mode_ == Bbr2Mode::STARTUP \
52 ? (startup_.member_function_call) \
53 : (mode_ == Bbr2Mode::PROBE_BW \
54 ? (probe_bw_.member_function_call) \
55 : (mode_ == Bbr2Mode::DRAIN \
56 ? (drain_.member_function_call) \
57 : (probe_rtt_or_die().member_function_call))))
58
Bbr2Sender(QuicTime now,const RttStats * rtt_stats,const QuicUnackedPacketMap * unacked_packets,QuicPacketCount initial_cwnd_in_packets,QuicPacketCount max_cwnd_in_packets,QuicRandom * random,QuicConnectionStats * stats,BbrSender * old_sender)59 Bbr2Sender::Bbr2Sender(QuicTime now, const RttStats* rtt_stats,
60 const QuicUnackedPacketMap* unacked_packets,
61 QuicPacketCount initial_cwnd_in_packets,
62 QuicPacketCount max_cwnd_in_packets, QuicRandom* random,
63 QuicConnectionStats* stats, BbrSender* old_sender)
64 : mode_(Bbr2Mode::STARTUP),
65 rtt_stats_(rtt_stats),
66 unacked_packets_(unacked_packets),
67 random_(random),
68 connection_stats_(stats),
69 params_(kDefaultMinimumCongestionWindow,
70 max_cwnd_in_packets * kDefaultTCPMSS),
71 model_(¶ms_, rtt_stats->SmoothedOrInitialRtt(),
72 rtt_stats->last_update_time(),
73 /*cwnd_gain=*/1.0,
74 /*pacing_gain=*/kInitialPacingGain,
75 old_sender ? &old_sender->sampler_ : nullptr),
76 initial_cwnd_(cwnd_limits().ApplyLimits(
77 (old_sender) ? old_sender->GetCongestionWindow()
78 : (initial_cwnd_in_packets * kDefaultTCPMSS))),
79 cwnd_(initial_cwnd_),
80 pacing_rate_(kInitialPacingGain *
81 QuicBandwidth::FromBytesAndTimeDelta(
82 cwnd_, rtt_stats->SmoothedOrInitialRtt())),
83 startup_(this, &model_, now),
84 drain_(this, &model_),
85 probe_bw_(this, &model_),
86 probe_rtt_(this, &model_),
87 last_sample_is_app_limited_(false) {
88 QUIC_DVLOG(2) << this << " Initializing Bbr2Sender. mode:" << mode_
89 << ", PacingRate:" << pacing_rate_ << ", Cwnd:" << cwnd_
90 << ", CwndLimits:" << cwnd_limits() << " @ " << now;
91 QUICHE_DCHECK_EQ(mode_, Bbr2Mode::STARTUP);
92 }
93
SetFromConfig(const QuicConfig & config,Perspective perspective)94 void Bbr2Sender::SetFromConfig(const QuicConfig& config,
95 Perspective perspective) {
96 if (config.HasClientRequestedIndependentOption(kB2NA, perspective)) {
97 params_.add_ack_height_to_queueing_threshold = false;
98 }
99 if (config.HasClientRequestedIndependentOption(kB2RP, perspective)) {
100 params_.avoid_unnecessary_probe_rtt = false;
101 }
102 if (config.HasClientRequestedIndependentOption(k1RTT, perspective)) {
103 params_.startup_full_bw_rounds = 1;
104 }
105 if (config.HasClientRequestedIndependentOption(k2RTT, perspective)) {
106 params_.startup_full_bw_rounds = 2;
107 }
108 if (config.HasClientRequestedIndependentOption(kB2HR, perspective)) {
109 params_.inflight_hi_headroom = 0.15;
110 }
111 if (config.HasClientRequestedIndependentOption(kICW1, perspective)) {
112 max_cwnd_when_network_parameters_adjusted_ = 100 * kDefaultTCPMSS;
113 }
114
115 ApplyConnectionOptions(config.ClientRequestedIndependentOptions(perspective));
116 }
117
ApplyConnectionOptions(const QuicTagVector & connection_options)118 void Bbr2Sender::ApplyConnectionOptions(
119 const QuicTagVector& connection_options) {
120 if (GetQuicReloadableFlag(quic_bbr2_extra_acked_window) &&
121 ContainsQuicTag(connection_options, kBBR4)) {
122 QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_extra_acked_window, 1, 2);
123 model_.SetMaxAckHeightTrackerWindowLength(20);
124 }
125 if (GetQuicReloadableFlag(quic_bbr2_extra_acked_window) &&
126 ContainsQuicTag(connection_options, kBBR5)) {
127 QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_extra_acked_window, 2, 2);
128 model_.SetMaxAckHeightTrackerWindowLength(40);
129 }
130 if (ContainsQuicTag(connection_options, kBBQ1)) {
131 params_.startup_pacing_gain = 2.773;
132 params_.drain_pacing_gain = 1.0 / params_.drain_cwnd_gain;
133 }
134 if (ContainsQuicTag(connection_options, kBBQ2)) {
135 params_.startup_cwnd_gain = 2.885;
136 params_.drain_cwnd_gain = 2.885;
137 model_.set_cwnd_gain(params_.startup_cwnd_gain);
138 }
139 if (ContainsQuicTag(connection_options, kB2LO)) {
140 params_.ignore_inflight_lo = true;
141 }
142 if (ContainsQuicTag(connection_options, kB2NE)) {
143 params_.always_exit_startup_on_excess_loss = true;
144 }
145 if (ContainsQuicTag(connection_options, kB2SL)) {
146 params_.startup_loss_exit_use_max_delivered_for_inflight_hi = false;
147 }
148 if (ContainsQuicTag(connection_options, kB2H2)) {
149 params_.limit_inflight_hi_by_max_delivered = true;
150 }
151 if (ContainsQuicTag(connection_options, kB2DL)) {
152 params_.use_bytes_delivered_for_inflight_hi = true;
153 }
154 if (ContainsQuicTag(connection_options, kB2RC)) {
155 params_.enable_reno_coexistence = false;
156 }
157 if (ContainsQuicTag(connection_options, kBSAO)) {
158 model_.EnableOverestimateAvoidance();
159 }
160 if (ContainsQuicTag(connection_options, kBBQ6)) {
161 params_.decrease_startup_pacing_at_end_of_round = true;
162 }
163 if (ContainsQuicTag(connection_options, kBBQ7)) {
164 params_.bw_lo_mode_ = Bbr2Params::QuicBandwidthLoMode::MIN_RTT_REDUCTION;
165 }
166 if (ContainsQuicTag(connection_options, kBBQ8)) {
167 params_.bw_lo_mode_ = Bbr2Params::QuicBandwidthLoMode::INFLIGHT_REDUCTION;
168 }
169 if (ContainsQuicTag(connection_options, kBBQ9)) {
170 params_.bw_lo_mode_ = Bbr2Params::QuicBandwidthLoMode::CWND_REDUCTION;
171 }
172 if (ContainsQuicTag(connection_options, kB202)) {
173 params_.max_probe_up_queue_rounds = 1;
174 }
175 if (ContainsQuicTag(connection_options, kB203)) {
176 params_.probe_up_ignore_inflight_hi = false;
177 }
178 if (ContainsQuicTag(connection_options, kB204)) {
179 model_.SetReduceExtraAckedOnBandwidthIncrease(true);
180 }
181 if (ContainsQuicTag(connection_options, kB205)) {
182 params_.startup_include_extra_acked = true;
183 }
184 if (ContainsQuicTag(connection_options, kB207)) {
185 params_.max_startup_queue_rounds = 1;
186 }
187 if (ContainsQuicTag(connection_options, kBBRA)) {
188 model_.SetStartNewAggregationEpochAfterFullRound(true);
189 }
190 if (ContainsQuicTag(connection_options, kBBRB)) {
191 model_.SetLimitMaxAckHeightTrackerBySendRate(true);
192 }
193 if (ContainsQuicTag(connection_options, kB206)) {
194 params_.startup_full_loss_count = params_.probe_bw_full_loss_count;
195 }
196 if (ContainsQuicTag(connection_options, kBBPD)) {
197 // Derived constant to ensure fairness.
198 params_.probe_bw_probe_down_pacing_gain = 0.91;
199 }
200 if (GetQuicReloadableFlag(quic_bbr2_simplify_inflight_hi) &&
201 ContainsQuicTag(connection_options, kBBHI)) {
202 QUIC_RELOADABLE_FLAG_COUNT(quic_bbr2_simplify_inflight_hi);
203 params_.probe_up_simplify_inflight_hi = true;
204 // Simplify inflight_hi is intended as an alternative to ignoring it,
205 // so ensure we're not ignoring it.
206 params_.probe_up_ignore_inflight_hi = false;
207 }
208 if (GetQuicReloadableFlag(quic_bbr2_probe_two_rounds) &&
209 ContainsQuicTag(connection_options, kBB2U)) {
210 QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_probe_two_rounds, 1, 3);
211 params_.max_probe_up_queue_rounds = 2;
212 }
213 if (GetQuicReloadableFlag(quic_bbr2_probe_two_rounds) &&
214 ContainsQuicTag(connection_options, kBB2S)) {
215 QUIC_RELOADABLE_FLAG_COUNT_N(quic_bbr2_probe_two_rounds, 2, 3);
216 params_.max_startup_queue_rounds = 2;
217 }
218 }
219
GetCwndLimitsByMode() const220 Limits<QuicByteCount> Bbr2Sender::GetCwndLimitsByMode() const {
221 switch (mode_) {
222 case Bbr2Mode::STARTUP:
223 return startup_.GetCwndLimits();
224 case Bbr2Mode::PROBE_BW:
225 return probe_bw_.GetCwndLimits();
226 case Bbr2Mode::DRAIN:
227 return drain_.GetCwndLimits();
228 case Bbr2Mode::PROBE_RTT:
229 return probe_rtt_.GetCwndLimits();
230 default:
231 QUICHE_NOTREACHED();
232 return Unlimited<QuicByteCount>();
233 }
234 }
235
cwnd_limits() const236 const Limits<QuicByteCount>& Bbr2Sender::cwnd_limits() const {
237 return params().cwnd_limits;
238 }
239
AdjustNetworkParameters(const NetworkParams & params)240 void Bbr2Sender::AdjustNetworkParameters(const NetworkParams& params) {
241 model_.UpdateNetworkParameters(params.rtt);
242
243 if (mode_ == Bbr2Mode::STARTUP) {
244 const QuicByteCount prior_cwnd = cwnd_;
245
246 QuicBandwidth effective_bandwidth =
247 std::max(params.bandwidth, model_.BandwidthEstimate());
248 connection_stats_->cwnd_bootstrapping_rtt_us =
249 model_.MinRtt().ToMicroseconds();
250
251 if (params.max_initial_congestion_window > 0) {
252 max_cwnd_when_network_parameters_adjusted_ =
253 params.max_initial_congestion_window * kDefaultTCPMSS;
254 }
255 cwnd_ = cwnd_limits().ApplyLimits(
256 std::min(max_cwnd_when_network_parameters_adjusted_,
257 model_.BDP(effective_bandwidth)));
258
259 if (!params.allow_cwnd_to_decrease) {
260 cwnd_ = std::max(cwnd_, prior_cwnd);
261 }
262
263 pacing_rate_ = std::max(pacing_rate_, QuicBandwidth::FromBytesAndTimeDelta(
264 cwnd_, model_.MinRtt()));
265 }
266 }
267
SetInitialCongestionWindowInPackets(QuicPacketCount congestion_window)268 void Bbr2Sender::SetInitialCongestionWindowInPackets(
269 QuicPacketCount congestion_window) {
270 if (mode_ == Bbr2Mode::STARTUP) {
271 // The cwnd limits is unchanged and still applies to the new cwnd.
272 cwnd_ = cwnd_limits().ApplyLimits(congestion_window * kDefaultTCPMSS);
273 }
274 }
275
OnCongestionEvent(bool,QuicByteCount prior_in_flight,QuicTime event_time,const AckedPacketVector & acked_packets,const LostPacketVector & lost_packets,QuicPacketCount,QuicPacketCount)276 void Bbr2Sender::OnCongestionEvent(bool /*rtt_updated*/,
277 QuicByteCount prior_in_flight,
278 QuicTime event_time,
279 const AckedPacketVector& acked_packets,
280 const LostPacketVector& lost_packets,
281 QuicPacketCount /*num_ect*/,
282 QuicPacketCount /*num_ce*/) {
283 QUIC_DVLOG(3) << this
284 << " OnCongestionEvent. prior_in_flight:" << prior_in_flight
285 << " prior_cwnd:" << cwnd_ << " @ " << event_time;
286 Bbr2CongestionEvent congestion_event;
287 congestion_event.prior_cwnd = cwnd_;
288 congestion_event.prior_bytes_in_flight = prior_in_flight;
289 congestion_event.is_probing_for_bandwidth =
290 BBR2_MODE_DISPATCH(IsProbingForBandwidth());
291
292 model_.OnCongestionEventStart(event_time, acked_packets, lost_packets,
293 &congestion_event);
294
295 if (InSlowStart()) {
296 if (!lost_packets.empty()) {
297 connection_stats_->slowstart_packets_lost += lost_packets.size();
298 connection_stats_->slowstart_bytes_lost += congestion_event.bytes_lost;
299 }
300 if (congestion_event.end_of_round_trip) {
301 ++connection_stats_->slowstart_num_rtts;
302 }
303 }
304
305 // Number of mode changes allowed for this congestion event.
306 int mode_changes_allowed = kMaxModeChangesPerCongestionEvent;
307 while (true) {
308 Bbr2Mode next_mode = BBR2_MODE_DISPATCH(
309 OnCongestionEvent(prior_in_flight, event_time, acked_packets,
310 lost_packets, congestion_event));
311
312 if (next_mode == mode_) {
313 break;
314 }
315
316 QUIC_DVLOG(2) << this << " Mode change: " << mode_ << " ==> " << next_mode
317 << " @ " << event_time;
318 BBR2_MODE_DISPATCH(Leave(event_time, &congestion_event));
319 mode_ = next_mode;
320 BBR2_MODE_DISPATCH(Enter(event_time, &congestion_event));
321 --mode_changes_allowed;
322 if (mode_changes_allowed < 0) {
323 QUIC_BUG(quic_bug_10443_1)
324 << "Exceeded max number of mode changes per congestion event.";
325 break;
326 }
327 }
328
329 UpdatePacingRate(congestion_event.bytes_acked);
330 QUIC_BUG_IF(quic_bug_10443_2, pacing_rate_.IsZero())
331 << "Pacing rate must not be zero!";
332
333 UpdateCongestionWindow(congestion_event.bytes_acked);
334 QUIC_BUG_IF(quic_bug_10443_3, cwnd_ == 0u)
335 << "Congestion window must not be zero!";
336
337 model_.OnCongestionEventFinish(unacked_packets_->GetLeastUnacked(),
338 congestion_event);
339 last_sample_is_app_limited_ =
340 congestion_event.last_packet_send_state.is_app_limited;
341 if (!last_sample_is_app_limited_) {
342 has_non_app_limited_sample_ = true;
343 }
344 if (congestion_event.bytes_in_flight == 0 &&
345 params().avoid_unnecessary_probe_rtt) {
346 OnEnterQuiescence(event_time);
347 }
348
349 QUIC_DVLOG(3)
350 << this
351 << " END CongestionEvent(acked:" << quiche::PrintElements(acked_packets)
352 << ", lost:" << lost_packets.size() << ") "
353 << ", Mode:" << mode_ << ", RttCount:" << model_.RoundTripCount()
354 << ", BytesInFlight:" << congestion_event.bytes_in_flight
355 << ", PacingRate:" << PacingRate(0) << ", CWND:" << GetCongestionWindow()
356 << ", PacingGain:" << model_.pacing_gain()
357 << ", CwndGain:" << model_.cwnd_gain()
358 << ", BandwidthEstimate(kbps):" << BandwidthEstimate().ToKBitsPerSecond()
359 << ", MinRTT(us):" << model_.MinRtt().ToMicroseconds()
360 << ", BDP:" << model_.BDP(BandwidthEstimate())
361 << ", BandwidthLatest(kbps):"
362 << model_.bandwidth_latest().ToKBitsPerSecond()
363 << ", BandwidthLow(kbps):" << model_.bandwidth_lo().ToKBitsPerSecond()
364 << ", BandwidthHigh(kbps):" << model_.MaxBandwidth().ToKBitsPerSecond()
365 << ", InflightLatest:" << model_.inflight_latest()
366 << ", InflightLow:" << model_.inflight_lo()
367 << ", InflightHigh:" << model_.inflight_hi()
368 << ", TotalAcked:" << model_.total_bytes_acked()
369 << ", TotalLost:" << model_.total_bytes_lost()
370 << ", TotalSent:" << model_.total_bytes_sent() << " @ " << event_time;
371 }
372
UpdatePacingRate(QuicByteCount bytes_acked)373 void Bbr2Sender::UpdatePacingRate(QuicByteCount bytes_acked) {
374 if (BandwidthEstimate().IsZero()) {
375 return;
376 }
377
378 if (model_.total_bytes_acked() == bytes_acked) {
379 // After the first ACK, cwnd_ is still the initial congestion window.
380 pacing_rate_ = QuicBandwidth::FromBytesAndTimeDelta(cwnd_, model_.MinRtt());
381 return;
382 }
383
384 QuicBandwidth target_rate = model_.pacing_gain() * model_.BandwidthEstimate();
385 if (model_.full_bandwidth_reached()) {
386 pacing_rate_ = target_rate;
387 return;
388 }
389 if (params_.decrease_startup_pacing_at_end_of_round &&
390 model_.pacing_gain() < Params().startup_pacing_gain) {
391 pacing_rate_ = target_rate;
392 return;
393 }
394 if (params_.bw_lo_mode_ != Bbr2Params::DEFAULT &&
395 model_.loss_events_in_round() > 0) {
396 pacing_rate_ = target_rate;
397 return;
398 }
399
400 // By default, the pacing rate never decreases in STARTUP.
401 if (target_rate > pacing_rate_) {
402 pacing_rate_ = target_rate;
403 }
404 }
405
UpdateCongestionWindow(QuicByteCount bytes_acked)406 void Bbr2Sender::UpdateCongestionWindow(QuicByteCount bytes_acked) {
407 QuicByteCount target_cwnd = GetTargetCongestionWindow(model_.cwnd_gain());
408
409 const QuicByteCount prior_cwnd = cwnd_;
410 if (model_.full_bandwidth_reached() || Params().startup_include_extra_acked) {
411 target_cwnd += model_.MaxAckHeight();
412 cwnd_ = std::min(prior_cwnd + bytes_acked, target_cwnd);
413 } else if (prior_cwnd < target_cwnd || prior_cwnd < 2 * initial_cwnd_) {
414 cwnd_ = prior_cwnd + bytes_acked;
415 }
416 const QuicByteCount desired_cwnd = cwnd_;
417
418 cwnd_ = GetCwndLimitsByMode().ApplyLimits(cwnd_);
419 const QuicByteCount model_limited_cwnd = cwnd_;
420
421 cwnd_ = cwnd_limits().ApplyLimits(cwnd_);
422
423 QUIC_DVLOG(3) << this << " Updating CWND. target_cwnd:" << target_cwnd
424 << ", max_ack_height:" << model_.MaxAckHeight()
425 << ", full_bw:" << model_.full_bandwidth_reached()
426 << ", bytes_acked:" << bytes_acked
427 << ", inflight_lo:" << model_.inflight_lo()
428 << ", inflight_hi:" << model_.inflight_hi() << ". (prior_cwnd) "
429 << prior_cwnd << " => (desired_cwnd) " << desired_cwnd
430 << " => (model_limited_cwnd) " << model_limited_cwnd
431 << " => (final_cwnd) " << cwnd_;
432 }
433
GetTargetCongestionWindow(float gain) const434 QuicByteCount Bbr2Sender::GetTargetCongestionWindow(float gain) const {
435 return std::max(model_.BDP(model_.BandwidthEstimate(), gain),
436 cwnd_limits().Min());
437 }
438
OnPacketSent(QuicTime sent_time,QuicByteCount bytes_in_flight,QuicPacketNumber packet_number,QuicByteCount bytes,HasRetransmittableData is_retransmittable)439 void Bbr2Sender::OnPacketSent(QuicTime sent_time, QuicByteCount bytes_in_flight,
440 QuicPacketNumber packet_number,
441 QuicByteCount bytes,
442 HasRetransmittableData is_retransmittable) {
443 QUIC_DVLOG(3) << this << " OnPacketSent: pkn:" << packet_number
444 << ", bytes:" << bytes << ", cwnd:" << cwnd_
445 << ", inflight:" << bytes_in_flight + bytes
446 << ", total_sent:" << model_.total_bytes_sent() + bytes
447 << ", total_acked:" << model_.total_bytes_acked()
448 << ", total_lost:" << model_.total_bytes_lost() << " @ "
449 << sent_time;
450 if (InSlowStart()) {
451 ++connection_stats_->slowstart_packets_sent;
452 connection_stats_->slowstart_bytes_sent += bytes;
453 }
454 if (bytes_in_flight == 0 && params().avoid_unnecessary_probe_rtt) {
455 OnExitQuiescence(sent_time);
456 }
457 model_.OnPacketSent(sent_time, bytes_in_flight, packet_number, bytes,
458 is_retransmittable);
459 }
460
OnPacketNeutered(QuicPacketNumber packet_number)461 void Bbr2Sender::OnPacketNeutered(QuicPacketNumber packet_number) {
462 model_.OnPacketNeutered(packet_number);
463 }
464
CanSend(QuicByteCount bytes_in_flight)465 bool Bbr2Sender::CanSend(QuicByteCount bytes_in_flight) {
466 const bool result = bytes_in_flight < GetCongestionWindow();
467 return result;
468 }
469
GetCongestionWindow() const470 QuicByteCount Bbr2Sender::GetCongestionWindow() const {
471 // TODO(wub): Implement Recovery?
472 return cwnd_;
473 }
474
PacingRate(QuicByteCount) const475 QuicBandwidth Bbr2Sender::PacingRate(QuicByteCount /*bytes_in_flight*/) const {
476 return pacing_rate_;
477 }
478
OnApplicationLimited(QuicByteCount bytes_in_flight)479 void Bbr2Sender::OnApplicationLimited(QuicByteCount bytes_in_flight) {
480 if (bytes_in_flight >= GetCongestionWindow()) {
481 return;
482 }
483
484 model_.OnApplicationLimited();
485 QUIC_DVLOG(2) << this << " Becoming application limited. Last sent packet: "
486 << model_.last_sent_packet()
487 << ", CWND: " << GetCongestionWindow();
488 }
489
GetTargetBytesInflight() const490 QuicByteCount Bbr2Sender::GetTargetBytesInflight() const {
491 QuicByteCount bdp = model_.BDP(model_.BandwidthEstimate());
492 return std::min(bdp, GetCongestionWindow());
493 }
494
PopulateConnectionStats(QuicConnectionStats * stats) const495 void Bbr2Sender::PopulateConnectionStats(QuicConnectionStats* stats) const {
496 stats->num_ack_aggregation_epochs = model_.num_ack_aggregation_epochs();
497 }
498
OnEnterQuiescence(QuicTime now)499 void Bbr2Sender::OnEnterQuiescence(QuicTime now) {
500 last_quiescence_start_ = now;
501 }
502
OnExitQuiescence(QuicTime now)503 void Bbr2Sender::OnExitQuiescence(QuicTime now) {
504 if (last_quiescence_start_ != QuicTime::Zero()) {
505 Bbr2Mode next_mode = BBR2_MODE_DISPATCH(
506 OnExitQuiescence(now, std::min(now, last_quiescence_start_)));
507 if (next_mode != mode_) {
508 BBR2_MODE_DISPATCH(Leave(now, nullptr));
509 mode_ = next_mode;
510 BBR2_MODE_DISPATCH(Enter(now, nullptr));
511 }
512 last_quiescence_start_ = QuicTime::Zero();
513 }
514 }
515
GetDebugState() const516 std::string Bbr2Sender::GetDebugState() const {
517 std::ostringstream stream;
518 stream << ExportDebugState();
519 return stream.str();
520 }
521
ExportDebugState() const522 Bbr2Sender::DebugState Bbr2Sender::ExportDebugState() const {
523 DebugState s;
524 s.mode = mode_;
525 s.round_trip_count = model_.RoundTripCount();
526 s.bandwidth_hi = model_.MaxBandwidth();
527 s.bandwidth_lo = model_.bandwidth_lo();
528 s.bandwidth_est = BandwidthEstimate();
529 s.inflight_hi = model_.inflight_hi();
530 s.inflight_lo = model_.inflight_lo();
531 s.max_ack_height = model_.MaxAckHeight();
532 s.min_rtt = model_.MinRtt();
533 s.min_rtt_timestamp = model_.MinRttTimestamp();
534 s.congestion_window = cwnd_;
535 s.pacing_rate = pacing_rate_;
536 s.last_sample_is_app_limited = last_sample_is_app_limited_;
537 s.end_of_app_limited_phase = model_.end_of_app_limited_phase();
538
539 s.startup = startup_.ExportDebugState();
540 s.drain = drain_.ExportDebugState();
541 s.probe_bw = probe_bw_.ExportDebugState();
542 s.probe_rtt = probe_rtt_.ExportDebugState();
543
544 return s;
545 }
546
operator <<(std::ostream & os,const Bbr2Sender::DebugState & s)547 std::ostream& operator<<(std::ostream& os, const Bbr2Sender::DebugState& s) {
548 os << "mode: " << s.mode << "\n";
549 os << "round_trip_count: " << s.round_trip_count << "\n";
550 os << "bandwidth_hi ~ lo ~ est: " << s.bandwidth_hi << " ~ " << s.bandwidth_lo
551 << " ~ " << s.bandwidth_est << "\n";
552 os << "min_rtt: " << s.min_rtt << "\n";
553 os << "min_rtt_timestamp: " << s.min_rtt_timestamp << "\n";
554 os << "congestion_window: " << s.congestion_window << "\n";
555 os << "pacing_rate: " << s.pacing_rate << "\n";
556 os << "last_sample_is_app_limited: " << s.last_sample_is_app_limited << "\n";
557
558 if (s.mode == Bbr2Mode::STARTUP) {
559 os << s.startup;
560 }
561
562 if (s.mode == Bbr2Mode::DRAIN) {
563 os << s.drain;
564 }
565
566 if (s.mode == Bbr2Mode::PROBE_BW) {
567 os << s.probe_bw;
568 }
569
570 if (s.mode == Bbr2Mode::PROBE_RTT) {
571 os << s.probe_rtt;
572 }
573
574 return os;
575 }
576
577 } // namespace quic
578