| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/quic/core/congestion_control/bbr_sender.h" | 5 #include "net/quic/core/congestion_control/bbr_sender.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <sstream> | 8 #include <sstream> |
| 9 | 9 |
| 10 #include "net/quic/core/congestion_control/rtt_stats.h" | 10 #include "net/quic/core/congestion_control/rtt_stats.h" |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 50 : mode(sender.mode_), | 50 : mode(sender.mode_), |
| 51 max_bandwidth(sender.max_bandwidth_.GetBest()), | 51 max_bandwidth(sender.max_bandwidth_.GetBest()), |
| 52 round_trip_count(sender.round_trip_count_), | 52 round_trip_count(sender.round_trip_count_), |
| 53 gain_cycle_index(sender.cycle_current_offset_), | 53 gain_cycle_index(sender.cycle_current_offset_), |
| 54 congestion_window(sender.congestion_window_), | 54 congestion_window(sender.congestion_window_), |
| 55 is_at_full_bandwidth(sender.is_at_full_bandwidth_), | 55 is_at_full_bandwidth(sender.is_at_full_bandwidth_), |
| 56 bandwidth_at_last_round(sender.bandwidth_at_last_round_), | 56 bandwidth_at_last_round(sender.bandwidth_at_last_round_), |
| 57 rounds_without_bandwidth_gain(sender.rounds_without_bandwidth_gain_), | 57 rounds_without_bandwidth_gain(sender.rounds_without_bandwidth_gain_), |
| 58 min_rtt(sender.min_rtt_), | 58 min_rtt(sender.min_rtt_), |
| 59 min_rtt_timestamp(sender.min_rtt_timestamp_), | 59 min_rtt_timestamp(sender.min_rtt_timestamp_), |
| 60 recovery_state(sender.recovery_state_), |
| 61 recovery_window(sender.recovery_window_), |
| 60 last_sample_is_app_limited(sender.last_sample_is_app_limited_) {} | 62 last_sample_is_app_limited(sender.last_sample_is_app_limited_) {} |
| 61 | 63 |
| 62 BbrSender::DebugState::DebugState(const DebugState& state) = default; | 64 BbrSender::DebugState::DebugState(const DebugState& state) = default; |
| 63 | 65 |
| 64 BbrSender::BbrSender(const QuicClock* clock, | 66 BbrSender::BbrSender(const QuicClock* clock, |
| 65 const RttStats* rtt_stats, | 67 const RttStats* rtt_stats, |
| 66 const QuicUnackedPacketMap* unacked_packets, | 68 const QuicUnackedPacketMap* unacked_packets, |
| 67 QuicPacketCount initial_tcp_congestion_window, | 69 QuicPacketCount initial_tcp_congestion_window, |
| 68 QuicPacketCount max_tcp_congestion_window, | 70 QuicPacketCount max_tcp_congestion_window, |
| 69 QuicRandom* random) | 71 QuicRandom* random) |
| (...skipping 17 matching lines...) Expand all Loading... |
| 87 pacing_gain_(1), | 89 pacing_gain_(1), |
| 88 congestion_window_gain_(1), | 90 congestion_window_gain_(1), |
| 89 cycle_current_offset_(0), | 91 cycle_current_offset_(0), |
| 90 last_cycle_start_(QuicTime::Zero()), | 92 last_cycle_start_(QuicTime::Zero()), |
| 91 is_at_full_bandwidth_(false), | 93 is_at_full_bandwidth_(false), |
| 92 rounds_without_bandwidth_gain_(0), | 94 rounds_without_bandwidth_gain_(0), |
| 93 bandwidth_at_last_round_(QuicBandwidth::Zero()), | 95 bandwidth_at_last_round_(QuicBandwidth::Zero()), |
| 94 exiting_quiescence_(false), | 96 exiting_quiescence_(false), |
| 95 exit_probe_rtt_at_(QuicTime::Zero()), | 97 exit_probe_rtt_at_(QuicTime::Zero()), |
| 96 probe_rtt_round_passed_(false), | 98 probe_rtt_round_passed_(false), |
| 97 last_sample_is_app_limited_(false) { | 99 last_sample_is_app_limited_(false), |
| 100 recovery_state_(NOT_IN_RECOVERY), |
| 101 end_recovery_at_(0) { |
| 98 EnterStartupMode(); | 102 EnterStartupMode(); |
| 99 } | 103 } |
| 100 | 104 |
| 101 BbrSender::~BbrSender() {} | 105 BbrSender::~BbrSender() {} |
| 102 | 106 |
| 103 bool BbrSender::InSlowStart() const { | 107 bool BbrSender::InSlowStart() const { |
| 104 return mode_ == STARTUP; | 108 return mode_ == STARTUP; |
| 105 } | 109 } |
| 106 | 110 |
| 107 bool BbrSender::OnPacketSent(QuicTime sent_time, | 111 bool BbrSender::OnPacketSent(QuicTime sent_time, |
| (...skipping 30 matching lines...) Expand all Loading... |
| 138 | 142 |
| 139 QuicBandwidth BbrSender::BandwidthEstimate() const { | 143 QuicBandwidth BbrSender::BandwidthEstimate() const { |
| 140 return max_bandwidth_.GetBest(); | 144 return max_bandwidth_.GetBest(); |
| 141 } | 145 } |
| 142 | 146 |
| 143 QuicByteCount BbrSender::GetCongestionWindow() const { | 147 QuicByteCount BbrSender::GetCongestionWindow() const { |
| 144 if (mode_ == PROBE_RTT) { | 148 if (mode_ == PROBE_RTT) { |
| 145 return kMinimumCongestionWindow; | 149 return kMinimumCongestionWindow; |
| 146 } | 150 } |
| 147 | 151 |
| 152 if (InRecovery()) { |
| 153 return std::min(congestion_window_, recovery_window_); |
| 154 } |
| 155 |
| 148 return congestion_window_; | 156 return congestion_window_; |
| 149 } | 157 } |
| 150 | 158 |
| 151 QuicByteCount BbrSender::GetSlowStartThreshold() const { | 159 QuicByteCount BbrSender::GetSlowStartThreshold() const { |
| 152 return 0; | 160 return 0; |
| 153 } | 161 } |
| 154 | 162 |
| 155 bool BbrSender::InRecovery() const { | 163 bool BbrSender::InRecovery() const { |
| 156 return false; | 164 return recovery_state_ != NOT_IN_RECOVERY; |
| 157 } | 165 } |
| 158 | 166 |
| 159 void BbrSender::OnCongestionEvent(bool /*rtt_updated*/, | 167 void BbrSender::OnCongestionEvent(bool /*rtt_updated*/, |
| 160 QuicByteCount prior_in_flight, | 168 QuicByteCount prior_in_flight, |
| 161 QuicTime event_time, | 169 QuicTime event_time, |
| 162 const CongestionVector& acked_packets, | 170 const CongestionVector& acked_packets, |
| 163 const CongestionVector& lost_packets) { | 171 const CongestionVector& lost_packets) { |
| 164 const QuicByteCount total_bytes_acked_before = sampler_.total_bytes_acked(); | 172 const QuicByteCount total_bytes_acked_before = sampler_.total_bytes_acked(); |
| 165 | 173 |
| 166 bool is_round_start = false; | 174 bool is_round_start = false; |
| 167 bool min_rtt_expired = false; | 175 bool min_rtt_expired = false; |
| 168 | 176 |
| 169 DiscardLostPackets(lost_packets); | 177 DiscardLostPackets(lost_packets); |
| 170 | 178 |
| 171 // Input the new data into the BBR model of the connection. | 179 // Input the new data into the BBR model of the connection. |
| 172 if (!acked_packets.empty()) { | 180 if (!acked_packets.empty()) { |
| 173 QuicPacketNumber last_acked_packet = acked_packets.rbegin()->first; | 181 QuicPacketNumber last_acked_packet = acked_packets.rbegin()->first; |
| 174 is_round_start = UpdateRoundTripCounter(last_acked_packet); | 182 is_round_start = UpdateRoundTripCounter(last_acked_packet); |
| 175 min_rtt_expired = UpdateBandwidthAndMinRtt(event_time, acked_packets); | 183 min_rtt_expired = UpdateBandwidthAndMinRtt(event_time, acked_packets); |
| 184 UpdateRecoveryState(last_acked_packet, !lost_packets.empty(), |
| 185 is_round_start); |
| 176 } | 186 } |
| 177 | 187 |
| 178 // Handle logic specific to PROBE_BW mode. | 188 // Handle logic specific to PROBE_BW mode. |
| 179 if (mode_ == PROBE_BW) { | 189 if (mode_ == PROBE_BW) { |
| 180 UpdateGainCyclePhase(event_time, prior_in_flight, !lost_packets.empty()); | 190 UpdateGainCyclePhase(event_time, prior_in_flight, !lost_packets.empty()); |
| 181 } | 191 } |
| 182 | 192 |
| 183 // Handle logic specific to STARTUP and DRAIN modes. | 193 // Handle logic specific to STARTUP and DRAIN modes. |
| 184 if (is_round_start && !is_at_full_bandwidth_) { | 194 if (is_round_start && !is_at_full_bandwidth_) { |
| 185 CheckIfFullBandwidthReached(); | 195 CheckIfFullBandwidthReached(); |
| 186 } | 196 } |
| 187 MaybeExitStartupOrDrain(event_time); | 197 MaybeExitStartupOrDrain(event_time); |
| 188 | 198 |
| 189 // Handle logic specific to PROBE_RTT. | 199 // Handle logic specific to PROBE_RTT. |
| 190 MaybeEnterOrExitProbeRtt(event_time, is_round_start, min_rtt_expired); | 200 MaybeEnterOrExitProbeRtt(event_time, is_round_start, min_rtt_expired); |
| 191 | 201 |
| 192 // After the model is updated, recalculate the pacing rate and congestion | 202 // After the model is updated, recalculate the pacing rate and congestion |
| 193 // window. | 203 // window. |
| 194 QuicByteCount bytes_acked = | 204 QuicByteCount bytes_acked = |
| 195 sampler_.total_bytes_acked() - total_bytes_acked_before; | 205 sampler_.total_bytes_acked() - total_bytes_acked_before; |
| 196 CalculatePacingRate(); | 206 CalculatePacingRate(); |
| 197 CalculateCongestionWindow(bytes_acked); | 207 CalculateCongestionWindow(bytes_acked); |
| 208 CalculateRecoveryWindow(bytes_acked); |
| 198 | 209 |
| 199 // Cleanup internal state. | 210 // Cleanup internal state. |
| 200 sampler_.RemoveObsoletePackets(unacked_packets_->GetLeastUnacked()); | 211 sampler_.RemoveObsoletePackets(unacked_packets_->GetLeastUnacked()); |
| 201 } | 212 } |
| 202 | 213 |
| 203 CongestionControlType BbrSender::GetCongestionControlType() const { | 214 CongestionControlType BbrSender::GetCongestionControlType() const { |
| 204 return kBBR; | 215 return kBBR; |
| 205 } | 216 } |
| 206 | 217 |
| 207 QuicTime::Delta BbrSender::GetMinRtt() const { | 218 QuicTime::Delta BbrSender::GetMinRtt() const { |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 } else { | 408 } else { |
| 398 EnterProbeBandwidthMode(now); | 409 EnterProbeBandwidthMode(now); |
| 399 } | 410 } |
| 400 } | 411 } |
| 401 } | 412 } |
| 402 } | 413 } |
| 403 | 414 |
| 404 exiting_quiescence_ = false; | 415 exiting_quiescence_ = false; |
| 405 } | 416 } |
| 406 | 417 |
| 418 void BbrSender::UpdateRecoveryState(QuicPacketNumber last_acked_packet, |
| 419 bool has_losses, |
| 420 bool is_round_start) { |
| 421 // Exit recovery when there are no losses for a round. |
| 422 if (has_losses) { |
| 423 end_recovery_at_ = last_sent_packet_; |
| 424 } |
| 425 |
| 426 switch (recovery_state_) { |
| 427 case NOT_IN_RECOVERY: |
| 428 // Enter conservation on the first loss. |
| 429 if (has_losses) { |
| 430 recovery_state_ = CONSERVATION; |
| 431 // Since the conservation phase is meant to be lasting for a whole |
| 432 // round, extend the current round as if it were started right now. |
| 433 current_round_trip_end_ = last_sent_packet_; |
| 434 } |
| 435 break; |
| 436 |
| 437 case CONSERVATION: |
| 438 if (is_round_start) { |
| 439 recovery_state_ = GROWTH; |
| 440 } |
| 441 |
| 442 case GROWTH: |
| 443 // Exit recovery if appropriate. |
| 444 if (!has_losses && last_acked_packet > end_recovery_at_) { |
| 445 recovery_state_ = NOT_IN_RECOVERY; |
| 446 } |
| 447 break; |
| 448 } |
| 449 } |
| 450 |
| 407 void BbrSender::CalculatePacingRate() { | 451 void BbrSender::CalculatePacingRate() { |
| 408 if (BandwidthEstimate().IsZero()) { | 452 if (BandwidthEstimate().IsZero()) { |
| 409 return; | 453 return; |
| 410 } | 454 } |
| 411 | 455 |
| 412 pacing_rate_ = pacing_gain_ * BandwidthEstimate(); | 456 pacing_rate_ = pacing_gain_ * BandwidthEstimate(); |
| 413 } | 457 } |
| 414 | 458 |
| 415 void BbrSender::CalculateCongestionWindow(QuicByteCount bytes_acked) { | 459 void BbrSender::CalculateCongestionWindow(QuicByteCount bytes_acked) { |
| 416 if (mode_ == PROBE_RTT) { | 460 if (mode_ == PROBE_RTT) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 431 } else if (congestion_window_ < target_window || | 475 } else if (congestion_window_ < target_window || |
| 432 sampler_.total_bytes_acked() < initial_congestion_window_) { | 476 sampler_.total_bytes_acked() < initial_congestion_window_) { |
| 433 congestion_window_ = congestion_window_ + bytes_acked; | 477 congestion_window_ = congestion_window_ + bytes_acked; |
| 434 } | 478 } |
| 435 | 479 |
| 436 // Enforce the limits on the congestion window. | 480 // Enforce the limits on the congestion window. |
| 437 congestion_window_ = std::max(congestion_window_, kMinimumCongestionWindow); | 481 congestion_window_ = std::max(congestion_window_, kMinimumCongestionWindow); |
| 438 congestion_window_ = std::min(congestion_window_, max_congestion_window_); | 482 congestion_window_ = std::min(congestion_window_, max_congestion_window_); |
| 439 } | 483 } |
| 440 | 484 |
| 485 void BbrSender::CalculateRecoveryWindow(QuicByteCount bytes_acked) { |
| 486 switch (recovery_state_) { |
| 487 case CONSERVATION: |
| 488 recovery_window_ = unacked_packets_->bytes_in_flight() + bytes_acked; |
| 489 break; |
| 490 case GROWTH: |
| 491 recovery_window_ = unacked_packets_->bytes_in_flight() + 2 * bytes_acked; |
| 492 break; |
| 493 default: |
| 494 break; |
| 495 } |
| 496 recovery_window_ = std::max(kMinimumCongestionWindow, recovery_window_); |
| 497 } |
| 498 |
| 441 std::string BbrSender::GetDebugState() const { | 499 std::string BbrSender::GetDebugState() const { |
| 442 std::ostringstream stream; | 500 std::ostringstream stream; |
| 443 stream << ExportDebugState(); | 501 stream << ExportDebugState(); |
| 444 return stream.str(); | 502 return stream.str(); |
| 445 } | 503 } |
| 446 | 504 |
| 447 void BbrSender::OnApplicationLimited(QuicByteCount bytes_in_flight) { | 505 void BbrSender::OnApplicationLimited(QuicByteCount bytes_in_flight) { |
| 448 if (bytes_in_flight >= GetCongestionWindow()) { | 506 if (bytes_in_flight >= GetCongestionWindow()) { |
| 449 return; | 507 return; |
| 450 } | 508 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 497 os << "Minimum RTT timestamp: " << state.min_rtt_timestamp.ToDebuggingValue() | 555 os << "Minimum RTT timestamp: " << state.min_rtt_timestamp.ToDebuggingValue() |
| 498 << std::endl; | 556 << std::endl; |
| 499 | 557 |
| 500 os << "Last sample is app-limited: " | 558 os << "Last sample is app-limited: " |
| 501 << (state.last_sample_is_app_limited ? "yes" : "no"); | 559 << (state.last_sample_is_app_limited ? "yes" : "no"); |
| 502 | 560 |
| 503 return os; | 561 return os; |
| 504 } | 562 } |
| 505 | 563 |
| 506 } // namespace net | 564 } // namespace net |
| OLD | NEW |