summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.cc
blob: 1141ca09e05dfd8ea65d369e66d33f1e129eb3d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/third_party/quiche/src/quic/core/congestion_control/bbr2_startup.h"

#include "net/third_party/quiche/src/quic/core/congestion_control/bbr2_misc.h"
#include "net/third_party/quiche/src/quic/core/congestion_control/bbr2_sender.h"
#include "net/third_party/quiche/src/quic/core/quic_bandwidth.h"
#include "net/third_party/quiche/src/quic/core/quic_types.h"
#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"

namespace quic {

Bbr2StartupMode::Bbr2StartupMode(const Bbr2Sender* sender,
                                 Bbr2NetworkModel* model,
                                 QuicTime now)
    : Bbr2ModeBase(sender, model),
      full_bandwidth_reached_(false),
      full_bandwidth_baseline_(QuicBandwidth::Zero()),
      rounds_without_bandwidth_growth_(0) {
  // Clear some startup stats if |sender_->connection_stats_| has been used by
  // another sender, which happens e.g. when QuicConnection switch send
  // algorithms.
  sender_->connection_stats_->slowstart_count = 1;
  sender_->connection_stats_->slowstart_duration = QuicTimeAccumulator();
  sender_->connection_stats_->slowstart_duration.Start(now);
}

void Bbr2StartupMode::Enter(QuicTime /*now*/,
                            const Bbr2CongestionEvent* /*congestion_event*/) {
  QUIC_BUG << "Bbr2StartupMode::Enter should not be called";
}

void Bbr2StartupMode::Leave(QuicTime now,
                            const Bbr2CongestionEvent* /*congestion_event*/) {
  sender_->connection_stats_->slowstart_duration.Stop(now);
}

Bbr2Mode Bbr2StartupMode::OnCongestionEvent(
    QuicByteCount /*prior_in_flight*/,
    QuicTime /*event_time*/,
    const AckedPacketVector& /*acked_packets*/,
    const LostPacketVector& /*lost_packets*/,
    const Bbr2CongestionEvent& congestion_event) {
  CheckFullBandwidthReached(congestion_event);

  CheckExcessiveLosses(congestion_event);

  model_->set_pacing_gain(Params().startup_pacing_gain);
  model_->set_cwnd_gain(Params().startup_cwnd_gain);

  // TODO(wub): Maybe implement STARTUP => PROBE_RTT.
  return full_bandwidth_reached_ ? Bbr2Mode::DRAIN : Bbr2Mode::STARTUP;
}

void Bbr2StartupMode::CheckFullBandwidthReached(
    const Bbr2CongestionEvent& congestion_event) {
  DCHECK(!full_bandwidth_reached_);
  if (full_bandwidth_reached_ || !congestion_event.end_of_round_trip ||
      congestion_event.last_sample_is_app_limited) {
    return;
  }

  QuicBandwidth threshold =
      full_bandwidth_baseline_ * Params().startup_full_bw_threshold;

  if (model_->MaxBandwidth() >= threshold) {
    QUIC_DVLOG(3)
        << sender_
        << " CheckFullBandwidthReached at end of round. max_bandwidth:"
        << model_->MaxBandwidth() << ", threshold:" << threshold
        << " (Still growing)  @ " << congestion_event.event_time;
    full_bandwidth_baseline_ = model_->MaxBandwidth();
    rounds_without_bandwidth_growth_ = 0;
    return;
  }

  ++rounds_without_bandwidth_growth_;
  full_bandwidth_reached_ =
      rounds_without_bandwidth_growth_ >= Params().startup_full_bw_rounds;
  QUIC_DVLOG(3) << sender_
                << " CheckFullBandwidthReached at end of round. max_bandwidth:"
                << model_->MaxBandwidth() << ", threshold:" << threshold
                << " rounds_without_growth:" << rounds_without_bandwidth_growth_
                << " full_bw_reached:" << full_bandwidth_reached_ << "  @ "
                << congestion_event.event_time;
}

void Bbr2StartupMode::CheckExcessiveLosses(
    const Bbr2CongestionEvent& congestion_event) {
  if (full_bandwidth_reached_) {
    return;
  }

  const int64_t loss_events_in_round = model_->loss_events_in_round();

  // TODO(wub): In TCP, loss based exit only happens at end of a loss round, in
  // QUIC we use the end of the normal round here. It is possible to exit after
  // any congestion event, using information of the "rolling round".
  if (!congestion_event.end_of_round_trip) {
    return;
  }

  QUIC_DVLOG(3)
      << sender_
      << " CheckExcessiveLosses at end of round. loss_events_in_round:"
      << loss_events_in_round
      << ", threshold:" << Params().startup_full_loss_count << "  @ "
      << congestion_event.event_time;

  // At the end of a round trip. Check if loss is too high in this round.
  if (loss_events_in_round >= Params().startup_full_loss_count &&
      model_->IsInflightTooHigh(congestion_event)) {
    const QuicByteCount bdp = model_->BDP(model_->MaxBandwidth());
    QUIC_DVLOG(3) << sender_
                  << " Exiting STARTUP due to loss. inflight_hi:" << bdp;
    model_->set_inflight_hi(bdp);

    full_bandwidth_reached_ = true;
    sender_->connection_stats_->bbr_exit_startup_due_to_loss = true;
  }
}

Bbr2StartupMode::DebugState Bbr2StartupMode::ExportDebugState() const {
  DebugState s;
  s.full_bandwidth_reached = full_bandwidth_reached_;
  s.full_bandwidth_baseline = full_bandwidth_baseline_;
  s.round_trips_without_bandwidth_growth = rounds_without_bandwidth_growth_;
  return s;
}

std::ostream& operator<<(std::ostream& os,
                         const Bbr2StartupMode::DebugState& state) {
  os << "[STARTUP] full_bandwidth_reached: " << state.full_bandwidth_reached
     << "\n";
  os << "[STARTUP] full_bandwidth_baseline: " << state.full_bandwidth_baseline
     << "\n";
  os << "[STARTUP] round_trips_without_bandwidth_growth: "
     << state.round_trips_without_bandwidth_growth << "\n";
  return os;
}

const Bbr2Params& Bbr2StartupMode::Params() const {
  return sender_->Params();
}

}  // namespace quic