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 |