| 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" |
| 11 #include "net/quic/core/crypto/crypto_protocol.h" | 11 #include "net/quic/core/crypto/crypto_protocol.h" |
| 12 #include "net/quic/core/proto/cached_network_parameters.pb.h" | 12 #include "net/quic/core/proto/cached_network_parameters.pb.h" |
| 13 #include "net/quic/core/quic_flags.h" | |
| 14 #include "net/quic/platform/api/quic_bug_tracker.h" | 13 #include "net/quic/platform/api/quic_bug_tracker.h" |
| 15 #include "net/quic/platform/api/quic_flag_utils.h" | 14 #include "net/quic/platform/api/quic_flag_utils.h" |
| 15 #include "net/quic/platform/api/quic_flags.h" |
| 16 #include "net/quic/platform/api/quic_logging.h" | 16 #include "net/quic/platform/api/quic_logging.h" |
| 17 | 17 |
| 18 namespace net { | 18 namespace net { |
| 19 | 19 |
| 20 namespace { | 20 namespace { |
| 21 // Constants based on TCP defaults. | 21 // Constants based on TCP defaults. |
| 22 const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS; | 22 const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS; |
| 23 // The minimum CWND to ensure delayed acks don't reduce bandwidth measurements. | 23 // The minimum CWND to ensure delayed acks don't reduce bandwidth measurements. |
| 24 // Does not inflate the pacing rate. | 24 // Does not inflate the pacing rate. |
| 25 const QuicByteCount kMinimumCongestionWindow = 4 * kMaxSegmentSize; | 25 const QuicByteCount kMinimumCongestionWindow = 4 * kMaxSegmentSize; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 73 QuicRandom* random) | 73 QuicRandom* random) |
| 74 : rtt_stats_(rtt_stats), | 74 : rtt_stats_(rtt_stats), |
| 75 unacked_packets_(unacked_packets), | 75 unacked_packets_(unacked_packets), |
| 76 random_(random), | 76 random_(random), |
| 77 mode_(STARTUP), | 77 mode_(STARTUP), |
| 78 sampler_(), | 78 sampler_(), |
| 79 round_trip_count_(0), | 79 round_trip_count_(0), |
| 80 last_sent_packet_(0), | 80 last_sent_packet_(0), |
| 81 current_round_trip_end_(0), | 81 current_round_trip_end_(0), |
| 82 max_bandwidth_(kBandwidthWindowSize, QuicBandwidth::Zero(), 0), | 82 max_bandwidth_(kBandwidthWindowSize, QuicBandwidth::Zero(), 0), |
| 83 max_ack_spacing_(kBandwidthWindowSize, QuicTime::Delta::Zero(), 0), | |
| 84 largest_acked_time_(QuicTime::Zero()), | |
| 85 largest_acked_sent_time_(QuicTime::Zero()), | |
| 86 max_ack_height_(kBandwidthWindowSize, 0, 0), | 83 max_ack_height_(kBandwidthWindowSize, 0, 0), |
| 87 aggregation_epoch_start_time_(QuicTime::Zero()), | 84 aggregation_epoch_start_time_(QuicTime::Zero()), |
| 88 aggregation_epoch_bytes_(0), | 85 aggregation_epoch_bytes_(0), |
| 89 min_rtt_(QuicTime::Delta::Zero()), | 86 min_rtt_(QuicTime::Delta::Zero()), |
| 90 min_rtt_timestamp_(QuicTime::Zero()), | 87 min_rtt_timestamp_(QuicTime::Zero()), |
| 91 congestion_window_(initial_tcp_congestion_window * kDefaultTCPMSS), | 88 congestion_window_(initial_tcp_congestion_window * kDefaultTCPMSS), |
| 92 initial_congestion_window_(initial_tcp_congestion_window * | 89 initial_congestion_window_(initial_tcp_congestion_window * |
| 93 kDefaultTCPMSS), | 90 kDefaultTCPMSS), |
| 94 max_congestion_window_(max_tcp_congestion_window * kDefaultTCPMSS), | 91 max_congestion_window_(max_tcp_congestion_window * kDefaultTCPMSS), |
| 95 pacing_rate_(QuicBandwidth::Zero()), | 92 pacing_rate_(QuicBandwidth::Zero()), |
| 96 pacing_gain_(1), | 93 pacing_gain_(1), |
| 97 congestion_window_gain_(1), | 94 congestion_window_gain_(1), |
| 98 congestion_window_gain_constant_( | 95 congestion_window_gain_constant_( |
| 99 static_cast<float>(base::GetFlag(FLAGS_quic_bbr_cwnd_gain))), | 96 static_cast<float>(GetQuicFlag(FLAGS_quic_bbr_cwnd_gain))), |
| 100 rtt_variance_weight_(static_cast<float>( | 97 rtt_variance_weight_( |
| 101 base::GetFlag(FLAGS_quic_bbr_rtt_variation_weight))), | 98 static_cast<float>(GetQuicFlag(FLAGS_quic_bbr_rtt_variation_weight))), |
| 102 num_startup_rtts_(kRoundTripsWithoutGrowthBeforeExitingStartup), | 99 num_startup_rtts_(kRoundTripsWithoutGrowthBeforeExitingStartup), |
| 103 cycle_current_offset_(0), | 100 cycle_current_offset_(0), |
| 104 last_cycle_start_(QuicTime::Zero()), | 101 last_cycle_start_(QuicTime::Zero()), |
| 105 is_at_full_bandwidth_(false), | 102 is_at_full_bandwidth_(false), |
| 106 rounds_without_bandwidth_gain_(0), | 103 rounds_without_bandwidth_gain_(0), |
| 107 bandwidth_at_last_round_(QuicBandwidth::Zero()), | 104 bandwidth_at_last_round_(QuicBandwidth::Zero()), |
| 108 exiting_quiescence_(false), | 105 exiting_quiescence_(false), |
| 109 exit_probe_rtt_at_(QuicTime::Zero()), | 106 exit_probe_rtt_at_(QuicTime::Zero()), |
| 110 probe_rtt_round_passed_(false), | 107 probe_rtt_round_passed_(false), |
| 111 last_sample_is_app_limited_(false), | 108 last_sample_is_app_limited_(false), |
| (...skipping 26 matching lines...) Expand all Loading... |
| 138 } | 135 } |
| 139 | 136 |
| 140 QuicTime::Delta BbrSender::TimeUntilSend(QuicTime /* now */, | 137 QuicTime::Delta BbrSender::TimeUntilSend(QuicTime /* now */, |
| 141 QuicByteCount bytes_in_flight) const { | 138 QuicByteCount bytes_in_flight) const { |
| 142 if (bytes_in_flight < GetCongestionWindow()) { | 139 if (bytes_in_flight < GetCongestionWindow()) { |
| 143 return QuicTime::Delta::Zero(); | 140 return QuicTime::Delta::Zero(); |
| 144 } | 141 } |
| 145 return QuicTime::Delta::Infinite(); | 142 return QuicTime::Delta::Infinite(); |
| 146 } | 143 } |
| 147 | 144 |
| 148 QuicBandwidth BbrSender::PacingRate(QuicByteCount /*bytes_in_flight*/) const { | 145 QuicBandwidth BbrSender::PacingRate(QuicByteCount bytes_in_flight) const { |
| 149 if (pacing_rate_.IsZero()) { | 146 if (pacing_rate_.IsZero()) { |
| 150 return kHighGain * QuicBandwidth::FromBytesAndTimeDelta( | 147 return kHighGain * QuicBandwidth::FromBytesAndTimeDelta( |
| 151 initial_congestion_window_, GetMinRtt()); | 148 initial_congestion_window_, GetMinRtt()); |
| 152 } | 149 } |
| 150 if (FLAGS_quic_reloadable_flag_quic_bbr_keep_sending_at_recent_rate && |
| 151 mode_ == PROBE_BW && bytes_in_flight > congestion_window_) { |
| 152 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_keep_sending_at_recent_rate, |
| 153 1, 2); |
| 154 if (pacing_gain_ > 1) { |
| 155 return max_bandwidth_.GetBest(); |
| 156 } else { |
| 157 return max_bandwidth_.GetThirdBest(); |
| 158 } |
| 159 } |
| 153 return pacing_rate_; | 160 return pacing_rate_; |
| 154 } | 161 } |
| 155 | 162 |
| 156 QuicBandwidth BbrSender::BandwidthEstimate() const { | 163 QuicBandwidth BbrSender::BandwidthEstimate() const { |
| 157 return max_bandwidth_.GetBest(); | 164 return max_bandwidth_.GetBest(); |
| 158 } | 165 } |
| 159 | 166 |
| 160 QuicByteCount BbrSender::GetCongestionWindow() const { | 167 QuicByteCount BbrSender::GetCongestionWindow() const { |
| 161 if (mode_ == PROBE_RTT) { | 168 if (mode_ == PROBE_RTT) { |
| 162 return kMinimumCongestionWindow; | 169 return kMinimumCongestionWindow; |
| 163 } | 170 } |
| 164 | 171 |
| 165 if (InRecovery()) { | 172 if (InRecovery()) { |
| 166 return std::min(congestion_window_, recovery_window_); | 173 return std::min(congestion_window_, recovery_window_); |
| 167 } | 174 } |
| 168 | 175 |
| 176 if (FLAGS_quic_reloadable_flag_quic_bbr_keep_sending_at_recent_rate && |
| 177 mode_ == PROBE_BW && pacing_gain_ >= 1) { |
| 178 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_keep_sending_at_recent_rate, |
| 179 2, 2); |
| 180 // Send for another SRTT at a more recently measured bandwidth. |
| 181 return congestion_window_ + |
| 182 max_bandwidth_.GetThirdBest() * rtt_stats_->smoothed_rtt(); |
| 183 } |
| 184 |
| 169 return congestion_window_; | 185 return congestion_window_; |
| 170 } | 186 } |
| 171 | 187 |
| 172 QuicByteCount BbrSender::GetSlowStartThreshold() const { | 188 QuicByteCount BbrSender::GetSlowStartThreshold() const { |
| 173 return 0; | 189 return 0; |
| 174 } | 190 } |
| 175 | 191 |
| 176 bool BbrSender::InRecovery() const { | 192 bool BbrSender::InRecovery() const { |
| 177 return recovery_state_ != NOT_IN_RECOVERY; | 193 return recovery_state_ != NOT_IN_RECOVERY; |
| 178 } | 194 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 190 } | 206 } |
| 191 } | 207 } |
| 192 | 208 |
| 193 void BbrSender::ResumeConnectionState( | 209 void BbrSender::ResumeConnectionState( |
| 194 const CachedNetworkParameters& cached_network_params, | 210 const CachedNetworkParameters& cached_network_params, |
| 195 bool max_bandwidth_resumption) { | 211 bool max_bandwidth_resumption) { |
| 196 if (!FLAGS_quic_reloadable_flag_quic_bbr_bandwidth_resumption) { | 212 if (!FLAGS_quic_reloadable_flag_quic_bbr_bandwidth_resumption) { |
| 197 return; | 213 return; |
| 198 } | 214 } |
| 199 | 215 |
| 216 QUIC_FLAG_COUNT(quic_reloadable_flag_quic_bbr_bandwidth_resumption); |
| 217 |
| 200 QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond( | 218 QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond( |
| 201 max_bandwidth_resumption | 219 max_bandwidth_resumption |
| 202 ? cached_network_params.max_bandwidth_estimate_bytes_per_second() | 220 ? cached_network_params.max_bandwidth_estimate_bytes_per_second() |
| 203 : cached_network_params.bandwidth_estimate_bytes_per_second()); | 221 : cached_network_params.bandwidth_estimate_bytes_per_second()); |
| 204 QuicTime::Delta rtt = | 222 QuicTime::Delta rtt = |
| 205 QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); | 223 QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); |
| 206 | 224 |
| 207 max_bandwidth_.Update(bandwidth, round_trip_count_); | 225 max_bandwidth_.Update(bandwidth, round_trip_count_); |
| 208 if (!rtt.IsZero() && (min_rtt_ > rtt || min_rtt_.IsZero())) { | 226 if (!rtt.IsZero() && (min_rtt_ > rtt || min_rtt_.IsZero())) { |
| 209 min_rtt_ = rtt; | 227 min_rtt_ = rtt; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 222 | 240 |
| 223 DiscardLostPackets(lost_packets); | 241 DiscardLostPackets(lost_packets); |
| 224 | 242 |
| 225 // Input the new data into the BBR model of the connection. | 243 // Input the new data into the BBR model of the connection. |
| 226 if (!acked_packets.empty()) { | 244 if (!acked_packets.empty()) { |
| 227 QuicPacketNumber last_acked_packet = acked_packets.rbegin()->first; | 245 QuicPacketNumber last_acked_packet = acked_packets.rbegin()->first; |
| 228 is_round_start = UpdateRoundTripCounter(last_acked_packet); | 246 is_round_start = UpdateRoundTripCounter(last_acked_packet); |
| 229 min_rtt_expired = UpdateBandwidthAndMinRtt(event_time, acked_packets); | 247 min_rtt_expired = UpdateBandwidthAndMinRtt(event_time, acked_packets); |
| 230 UpdateRecoveryState(last_acked_packet, !lost_packets.empty(), | 248 UpdateRecoveryState(last_acked_packet, !lost_packets.empty(), |
| 231 is_round_start); | 249 is_round_start); |
| 232 if (FLAGS_quic_reloadable_flag_quic_bbr_ack_spacing2) { | |
| 233 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_spacing2, 1, 2); | |
| 234 UpdateAckSpacing(event_time, last_acked_packet, acked_packets); | |
| 235 } | |
| 236 if (FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes) { | 250 if (FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes) { |
| 237 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_aggregation_bytes, 1, | 251 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_aggregation_bytes, 1, |
| 238 2); | 252 2); |
| 239 UpdateAckAggregationBytes( | 253 UpdateAckAggregationBytes( |
| 240 event_time, sampler_.total_bytes_acked() - total_bytes_acked_before); | 254 event_time, sampler_.total_bytes_acked() - total_bytes_acked_before); |
| 241 } | 255 } |
| 242 } | 256 } |
| 243 | 257 |
| 244 // Handle logic specific to PROBE_BW mode. | 258 // Handle logic specific to PROBE_BW mode. |
| 245 if (mode_ == PROBE_BW) { | 259 if (mode_ == PROBE_BW) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 272 } | 286 } |
| 273 | 287 |
| 274 QuicTime::Delta BbrSender::GetMinRtt() const { | 288 QuicTime::Delta BbrSender::GetMinRtt() const { |
| 275 return !min_rtt_.IsZero() | 289 return !min_rtt_.IsZero() |
| 276 ? min_rtt_ | 290 ? min_rtt_ |
| 277 : QuicTime::Delta::FromMicroseconds(rtt_stats_->initial_rtt_us()); | 291 : QuicTime::Delta::FromMicroseconds(rtt_stats_->initial_rtt_us()); |
| 278 } | 292 } |
| 279 | 293 |
| 280 QuicByteCount BbrSender::GetTargetCongestionWindow(float gain) const { | 294 QuicByteCount BbrSender::GetTargetCongestionWindow(float gain) const { |
| 281 QuicByteCount bdp = GetMinRtt() * BandwidthEstimate(); | 295 QuicByteCount bdp = GetMinRtt() * BandwidthEstimate(); |
| 296 if (FLAGS_quic_reloadable_flag_quic_bbr_base_cwnd_on_srtt && |
| 297 mode_ == PROBE_BW && gain >= 1 && !rtt_stats_->smoothed_rtt().IsZero()) { |
| 298 bdp = rtt_stats_->smoothed_rtt() * BandwidthEstimate(); |
| 299 } |
| 282 QuicByteCount congestion_window = gain * bdp; | 300 QuicByteCount congestion_window = gain * bdp; |
| 283 | 301 |
| 284 // BDP estimate will be zero if no bandwidth samples are available yet. | 302 // BDP estimate will be zero if no bandwidth samples are available yet. |
| 285 if (congestion_window == 0) { | 303 if (congestion_window == 0) { |
| 286 congestion_window = gain * initial_congestion_window_; | 304 congestion_window = gain * initial_congestion_window_; |
| 287 } | 305 } |
| 288 | 306 |
| 289 return std::max(congestion_window, kMinimumCongestionWindow); | 307 return std::max(congestion_window, kMinimumCongestionWindow); |
| 290 } | 308 } |
| 291 | 309 |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 | 513 |
| 496 case GROWTH: | 514 case GROWTH: |
| 497 // Exit recovery if appropriate. | 515 // Exit recovery if appropriate. |
| 498 if (!has_losses && last_acked_packet > end_recovery_at_) { | 516 if (!has_losses && last_acked_packet > end_recovery_at_) { |
| 499 recovery_state_ = NOT_IN_RECOVERY; | 517 recovery_state_ = NOT_IN_RECOVERY; |
| 500 } | 518 } |
| 501 break; | 519 break; |
| 502 } | 520 } |
| 503 } | 521 } |
| 504 | 522 |
| 505 // TODO(ianswett): Move this logic into BandwidthSampler. | |
| 506 void BbrSender::UpdateAckSpacing(QuicTime ack_time, | |
| 507 QuicPacketNumber largest_newly_acked, | |
| 508 const CongestionVector& acked_packets) { | |
| 509 // Ignore acks of reordered packets. | |
| 510 if (largest_newly_acked < unacked_packets_->largest_observed()) { | |
| 511 return; | |
| 512 } | |
| 513 // Ignore acks of only one packet to filter out delayed acks. | |
| 514 if (acked_packets.size() == 1) { | |
| 515 return; | |
| 516 } | |
| 517 QuicTime largest_newly_acked_sent_time = | |
| 518 unacked_packets_->GetTransmissionInfo(largest_newly_acked).sent_time; | |
| 519 // Initialize on the first ack. | |
| 520 if (!largest_acked_time_.IsInitialized()) { | |
| 521 largest_acked_time_ = ack_time; | |
| 522 largest_acked_sent_time_ = largest_newly_acked_sent_time; | |
| 523 return; | |
| 524 } | |
| 525 QuicTime::Delta ack_delta = ack_time - largest_acked_time_; | |
| 526 QuicTime::Delta send_delta = | |
| 527 largest_newly_acked_sent_time - largest_acked_sent_time_; | |
| 528 largest_acked_time_ = ack_time; | |
| 529 largest_acked_sent_time_ = largest_newly_acked_sent_time; | |
| 530 if (ack_delta <= send_delta) { | |
| 531 return; | |
| 532 } | |
| 533 | |
| 534 // Limit the ack spacing to SRTT to filter outliers. | |
| 535 QuicTime::Delta ack_spacing = | |
| 536 std::min(ack_delta - send_delta, rtt_stats_->smoothed_rtt()); | |
| 537 max_ack_spacing_.Update(ack_spacing, round_trip_count_); | |
| 538 } | |
| 539 | |
| 540 // TODO(ianswett): Move this logic into BandwidthSampler. | |
| 541 void BbrSender::UpdateAckAggregationBytes(QuicTime ack_time, | 523 void BbrSender::UpdateAckAggregationBytes(QuicTime ack_time, |
| 542 QuicByteCount newly_acked_bytes) { | 524 QuicByteCount newly_acked_bytes) { |
| 543 // Compute how many bytes are expected to be delivered, assuming max bandwidth | 525 // Compute how many bytes are expected to be delivered, assuming max bandwidth |
| 544 // is correct. | 526 // is correct. |
| 545 QuicByteCount expected_bytes_acked = | 527 QuicByteCount expected_bytes_acked = |
| 546 max_bandwidth_.GetBest() * (ack_time - aggregation_epoch_start_time_); | 528 max_bandwidth_.GetBest() * (ack_time - aggregation_epoch_start_time_); |
| 547 // Reset the current aggregation epoch as soon as the ack arrival rate is less | 529 // Reset the current aggregation epoch as soon as the ack arrival rate is less |
| 548 // than or equal to the max bandwidth. | 530 // than or equal to the max bandwidth. |
| 549 if (aggregation_epoch_bytes_ <= expected_bytes_acked) { | 531 if (aggregation_epoch_bytes_ <= expected_bytes_acked) { |
| 550 // Reset to start measuring a new aggregation epoch. | 532 // Reset to start measuring a new aggregation epoch. |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 587 if (mode_ == PROBE_RTT) { | 569 if (mode_ == PROBE_RTT) { |
| 588 return; | 570 return; |
| 589 } | 571 } |
| 590 | 572 |
| 591 QuicByteCount target_window = | 573 QuicByteCount target_window = |
| 592 GetTargetCongestionWindow(congestion_window_gain_); | 574 GetTargetCongestionWindow(congestion_window_gain_); |
| 593 | 575 |
| 594 if (rtt_variance_weight_ > 0.f && !BandwidthEstimate().IsZero()) { | 576 if (rtt_variance_weight_ > 0.f && !BandwidthEstimate().IsZero()) { |
| 595 target_window += rtt_variance_weight_ * rtt_stats_->mean_deviation() * | 577 target_window += rtt_variance_weight_ * rtt_stats_->mean_deviation() * |
| 596 BandwidthEstimate(); | 578 BandwidthEstimate(); |
| 597 } else if (FLAGS_quic_reloadable_flag_quic_bbr_ack_spacing2 && | |
| 598 is_at_full_bandwidth_) { | |
| 599 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_spacing2, 2, 2); | |
| 600 // Add CWND for inter-ack spacing once STARTUP has been exited. | |
| 601 target_window += max_ack_spacing_.GetBest() * BandwidthEstimate(); | |
| 602 } else if (FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes && | 579 } else if (FLAGS_quic_reloadable_flag_quic_bbr_ack_aggregation_bytes && |
| 603 is_at_full_bandwidth_) { | 580 is_at_full_bandwidth_) { |
| 604 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_aggregation_bytes, 2, | 581 QUIC_FLAG_COUNT_N(quic_reloadable_flag_quic_bbr_ack_aggregation_bytes, 2, |
| 605 2); | 582 2); |
| 606 target_window += max_ack_height_.GetBest(); | 583 target_window += max_ack_height_.GetBest(); |
| 607 } | 584 } |
| 608 if (FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd) { | 585 if (FLAGS_quic_reloadable_flag_quic_bbr_add_tso_cwnd) { |
| 609 // QUIC doesn't have TSO, but it does have similarly quantized pacing, so | 586 // QUIC doesn't have TSO, but it does have similarly quantized pacing, so |
| 610 // allow extra CWND to make QUIC's BBR CWND identical to TCP's. | 587 // allow extra CWND to make QUIC's BBR CWND identical to TCP's. |
| 611 QuicByteCount tso_segs_goal = 0; | 588 QuicByteCount tso_segs_goal = 0; |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 712 os << "Minimum RTT timestamp: " << state.min_rtt_timestamp.ToDebuggingValue() | 689 os << "Minimum RTT timestamp: " << state.min_rtt_timestamp.ToDebuggingValue() |
| 713 << std::endl; | 690 << std::endl; |
| 714 | 691 |
| 715 os << "Last sample is app-limited: " | 692 os << "Last sample is app-limited: " |
| 716 << (state.last_sample_is_app_limited ? "yes" : "no"); | 693 << (state.last_sample_is_app_limited ? "yes" : "no"); |
| 717 | 694 |
| 718 return os; | 695 return os; |
| 719 } | 696 } |
| 720 | 697 |
| 721 } // namespace net | 698 } // namespace net |
| OLD | NEW |