| 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 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 return QuicTime::Delta::Zero(); | 185 return QuicTime::Delta::Zero(); |
| 186 } | 186 } |
| 187 return QuicTime::Delta::Infinite(); | 187 return QuicTime::Delta::Infinite(); |
| 188 } | 188 } |
| 189 | 189 |
| 190 QuicBandwidth BbrSender::PacingRate(QuicByteCount bytes_in_flight) const { | 190 QuicBandwidth BbrSender::PacingRate(QuicByteCount bytes_in_flight) const { |
| 191 if (pacing_rate_.IsZero()) { | 191 if (pacing_rate_.IsZero()) { |
| 192 return kHighGain * QuicBandwidth::FromBytesAndTimeDelta( | 192 return kHighGain * QuicBandwidth::FromBytesAndTimeDelta( |
| 193 initial_congestion_window_, GetMinRtt()); | 193 initial_congestion_window_, GetMinRtt()); |
| 194 } | 194 } |
| 195 if (FLAGS_quic_reloadable_flag_quic_bbr_keep_sending_at_recent_rate && | |
| 196 mode_ == PROBE_BW && bytes_in_flight > congestion_window_) { | |
| 197 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_keep_sending_at_recent_rate, | |
| 198 1, 2); | |
| 199 if (pacing_gain_ > 1) { | |
| 200 return max_bandwidth_.GetBest(); | |
| 201 } else { | |
| 202 return max_bandwidth_.GetThirdBest(); | |
| 203 } | |
| 204 } | |
| 205 return pacing_rate_; | 195 return pacing_rate_; |
| 206 } | 196 } |
| 207 | 197 |
| 208 QuicBandwidth BbrSender::BandwidthEstimate() const { | 198 QuicBandwidth BbrSender::BandwidthEstimate() const { |
| 209 return max_bandwidth_.GetBest(); | 199 return max_bandwidth_.GetBest(); |
| 210 } | 200 } |
| 211 | 201 |
| 212 QuicByteCount BbrSender::GetCongestionWindow() const { | 202 QuicByteCount BbrSender::GetCongestionWindow() const { |
| 213 if (mode_ == PROBE_RTT) { | 203 if (mode_ == PROBE_RTT) { |
| 214 return kMinimumCongestionWindow; | 204 return kMinimumCongestionWindow; |
| 215 } | 205 } |
| 216 | 206 |
| 217 if (InRecovery()) { | 207 if (InRecovery()) { |
| 218 return std::min(congestion_window_, recovery_window_); | 208 return std::min(congestion_window_, recovery_window_); |
| 219 } | 209 } |
| 220 | 210 |
| 221 if (FLAGS_quic_reloadable_flag_quic_bbr_keep_sending_at_recent_rate && | |
| 222 mode_ == PROBE_BW && pacing_gain_ >= 1) { | |
| 223 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_keep_sending_at_recent_rate, | |
| 224 2, 2); | |
| 225 // Send for another SRTT at a more recently measured bandwidth. | |
| 226 return congestion_window_ + | |
| 227 max_bandwidth_.GetThirdBest() * rtt_stats_->smoothed_rtt(); | |
| 228 } | |
| 229 | |
| 230 return congestion_window_; | 211 return congestion_window_; |
| 231 } | 212 } |
| 232 | 213 |
| 233 QuicByteCount BbrSender::GetSlowStartThreshold() const { | 214 QuicByteCount BbrSender::GetSlowStartThreshold() const { |
| 234 return 0; | 215 return 0; |
| 235 } | 216 } |
| 236 | 217 |
| 237 bool BbrSender::InRecovery() const { | 218 bool BbrSender::InRecovery() const { |
| 238 return recovery_state_ != NOT_IN_RECOVERY; | 219 return recovery_state_ != NOT_IN_RECOVERY; |
| 239 } | 220 } |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 | 296 |
| 316 // Handle logic specific to STARTUP and DRAIN modes. | 297 // Handle logic specific to STARTUP and DRAIN modes. |
| 317 if (is_round_start && !is_at_full_bandwidth_) { | 298 if (is_round_start && !is_at_full_bandwidth_) { |
| 318 CheckIfFullBandwidthReached(); | 299 CheckIfFullBandwidthReached(); |
| 319 } | 300 } |
| 320 MaybeExitStartupOrDrain(event_time); | 301 MaybeExitStartupOrDrain(event_time); |
| 321 | 302 |
| 322 // Handle logic specific to PROBE_RTT. | 303 // Handle logic specific to PROBE_RTT. |
| 323 MaybeEnterOrExitProbeRtt(event_time, is_round_start, min_rtt_expired); | 304 MaybeEnterOrExitProbeRtt(event_time, is_round_start, min_rtt_expired); |
| 324 | 305 |
| 306 // Calculate number of packets acked and lost. |
| 307 QuicByteCount bytes_acked = |
| 308 sampler_.total_bytes_acked() - total_bytes_acked_before; |
| 309 QuicByteCount bytes_lost = 0; |
| 310 for (const auto& packet : lost_packets) { |
| 311 bytes_lost += packet.second; |
| 312 } |
| 313 |
| 325 // After the model is updated, recalculate the pacing rate and congestion | 314 // After the model is updated, recalculate the pacing rate and congestion |
| 326 // window. | 315 // window. |
| 327 QuicByteCount bytes_acked = | |
| 328 sampler_.total_bytes_acked() - total_bytes_acked_before; | |
| 329 CalculatePacingRate(); | 316 CalculatePacingRate(); |
| 330 CalculateCongestionWindow(bytes_acked); | 317 CalculateCongestionWindow(bytes_acked); |
| 331 CalculateRecoveryWindow(bytes_acked); | 318 CalculateRecoveryWindow(bytes_acked, bytes_lost); |
| 332 | 319 |
| 333 // Cleanup internal state. | 320 // Cleanup internal state. |
| 334 sampler_.RemoveObsoletePackets(unacked_packets_->GetLeastUnacked()); | 321 sampler_.RemoveObsoletePackets(unacked_packets_->GetLeastUnacked()); |
| 335 } | 322 } |
| 336 | 323 |
| 337 CongestionControlType BbrSender::GetCongestionControlType() const { | 324 CongestionControlType BbrSender::GetCongestionControlType() const { |
| 338 return kBBR; | 325 return kBBR; |
| 339 } | 326 } |
| 340 | 327 |
| 341 QuicTime::Delta BbrSender::GetMinRtt() const { | 328 QuicTime::Delta BbrSender::GetMinRtt() const { |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 546 // Exit recovery when there are no losses for a round. | 533 // Exit recovery when there are no losses for a round. |
| 547 if (has_losses) { | 534 if (has_losses) { |
| 548 end_recovery_at_ = last_sent_packet_; | 535 end_recovery_at_ = last_sent_packet_; |
| 549 } | 536 } |
| 550 | 537 |
| 551 switch (recovery_state_) { | 538 switch (recovery_state_) { |
| 552 case NOT_IN_RECOVERY: | 539 case NOT_IN_RECOVERY: |
| 553 // Enter conservation on the first loss. | 540 // Enter conservation on the first loss. |
| 554 if (has_losses) { | 541 if (has_losses) { |
| 555 recovery_state_ = CONSERVATION; | 542 recovery_state_ = CONSERVATION; |
| 556 if (FLAGS_quic_reloadable_flag_quic_bbr_fix_conservation) { | 543 if (FLAGS_quic_reloadable_flag_quic_bbr_fix_conservation || |
| 544 FLAGS_quic_reloadable_flag_quic_bbr_fix_conservation2) { |
| 557 // This will cause the |recovery_window_| to be set to the correct | 545 // This will cause the |recovery_window_| to be set to the correct |
| 558 // value in CalculateRecoveryWindow(). | 546 // value in CalculateRecoveryWindow(). |
| 559 recovery_window_ = 0; | 547 recovery_window_ = 0; |
| 560 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_fix_conservation, 1, | 548 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_fix_conservation, 1, |
| 561 3); | 549 3); |
| 550 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_fix_conservation2, 1, |
| 551 3); |
| 562 } | 552 } |
| 563 // Since the conservation phase is meant to be lasting for a whole | 553 // Since the conservation phase is meant to be lasting for a whole |
| 564 // round, extend the current round as if it were started right now. | 554 // round, extend the current round as if it were started right now. |
| 565 current_round_trip_end_ = last_sent_packet_; | 555 current_round_trip_end_ = last_sent_packet_; |
| 566 } | 556 } |
| 567 break; | 557 break; |
| 568 | 558 |
| 569 case CONSERVATION: | 559 case CONSERVATION: |
| 570 if (is_round_start) { | 560 if (is_round_start) { |
| 571 recovery_state_ = GROWTH; | 561 recovery_state_ = GROWTH; |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 709 // If the connection is not yet out of startup phase, do not decrease the | 699 // If the connection is not yet out of startup phase, do not decrease the |
| 710 // window. | 700 // window. |
| 711 congestion_window_ = congestion_window_ + bytes_acked; | 701 congestion_window_ = congestion_window_ + bytes_acked; |
| 712 } | 702 } |
| 713 | 703 |
| 714 // Enforce the limits on the congestion window. | 704 // Enforce the limits on the congestion window. |
| 715 congestion_window_ = std::max(congestion_window_, kMinimumCongestionWindow); | 705 congestion_window_ = std::max(congestion_window_, kMinimumCongestionWindow); |
| 716 congestion_window_ = std::min(congestion_window_, max_congestion_window_); | 706 congestion_window_ = std::min(congestion_window_, max_congestion_window_); |
| 717 } | 707 } |
| 718 | 708 |
| 719 void BbrSender::CalculateRecoveryWindow(QuicByteCount bytes_acked) { | 709 void BbrSender::CalculateRecoveryWindow(QuicByteCount bytes_acked, |
| 710 QuicByteCount bytes_lost) { |
| 711 if (FLAGS_quic_reloadable_flag_quic_bbr_fix_conservation2) { |
| 712 if (recovery_state_ == NOT_IN_RECOVERY) { |
| 713 return; |
| 714 } |
| 715 |
| 716 // Set up the initial recovery window. |
| 717 if (recovery_window_ == 0) { |
| 718 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_fix_conservation2, 2, 3); |
| 719 recovery_window_ = unacked_packets_->bytes_in_flight() + bytes_acked; |
| 720 recovery_window_ = std::max(kMinimumCongestionWindow, recovery_window_); |
| 721 return; |
| 722 } |
| 723 |
| 724 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_fix_conservation2, 3, 3); |
| 725 |
| 726 // Remove losses from the recovery window, while accounting for a potential |
| 727 // integer underflow. |
| 728 recovery_window_ = recovery_window_ >= bytes_lost |
| 729 ? recovery_window_ - bytes_lost |
| 730 : kMaxSegmentSize; |
| 731 |
| 732 // In CONSERVATION mode, just subtracting losses is sufficient. In GROWTH, |
| 733 // release additional |bytes_acked| to achieve a slow-start-like behavior. |
| 734 if (recovery_state_ == GROWTH) { |
| 735 recovery_window_ += bytes_acked; |
| 736 } |
| 737 |
| 738 // Sanity checks. Ensure that we always allow to send at least |
| 739 // |bytes_acked| in response. |
| 740 recovery_window_ = std::max( |
| 741 recovery_window_, unacked_packets_->bytes_in_flight() + bytes_acked); |
| 742 recovery_window_ = std::max(kMinimumCongestionWindow, recovery_window_); |
| 743 return; |
| 744 } |
| 745 |
| 720 switch (recovery_state_) { | 746 switch (recovery_state_) { |
| 721 case CONSERVATION: | 747 case CONSERVATION: |
| 722 if (FLAGS_quic_reloadable_flag_quic_bbr_fix_conservation) { | 748 if (FLAGS_quic_reloadable_flag_quic_bbr_fix_conservation) { |
| 723 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_fix_conservation, 2, 3); | 749 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_fix_conservation, 2, 3); |
| 724 recovery_window_ = | 750 recovery_window_ = |
| 725 std::max(unacked_packets_->bytes_in_flight() + bytes_acked, | 751 std::max(unacked_packets_->bytes_in_flight() + bytes_acked, |
| 726 recovery_window_); | 752 recovery_window_); |
| 727 } else { | 753 } else { |
| 728 recovery_window_ = unacked_packets_->bytes_in_flight() + bytes_acked; | 754 recovery_window_ = unacked_packets_->bytes_in_flight() + bytes_acked; |
| 729 } | 755 } |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 804 os << "Minimum RTT timestamp: " << state.min_rtt_timestamp.ToDebuggingValue() | 830 os << "Minimum RTT timestamp: " << state.min_rtt_timestamp.ToDebuggingValue() |
| 805 << std::endl; | 831 << std::endl; |
| 806 | 832 |
| 807 os << "Last sample is app-limited: " | 833 os << "Last sample is app-limited: " |
| 808 << (state.last_sample_is_app_limited ? "yes" : "no"); | 834 << (state.last_sample_is_app_limited ? "yes" : "no"); |
| 809 | 835 |
| 810 return os; | 836 return os; |
| 811 } | 837 } |
| 812 | 838 |
| 813 } // namespace net | 839 } // namespace net |
| OLD | NEW |