OLD | NEW |
1 // Copyright (c) 2015 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2015 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/congestion_control/tcp_cubic_bytes_sender.h" | 5 #include "net/quic/congestion_control/tcp_cubic_bytes_sender.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "net/quic/congestion_control/prr_sender.h" | 9 #include "net/quic/congestion_control/prr_sender.h" |
10 #include "net/quic/congestion_control/rtt_stats.h" | 10 #include "net/quic/congestion_control/rtt_stats.h" |
11 #include "net/quic/crypto/crypto_protocol.h" | 11 #include "net/quic/crypto/crypto_protocol.h" |
12 #include "net/quic/proto/cached_network_parameters.pb.h" | 12 #include "net/quic/proto/cached_network_parameters.pb.h" |
13 #include "net/quic/quic_flags.h" | 13 #include "net/quic/quic_flags.h" |
14 | 14 |
15 using std::max; | 15 using std::max; |
16 using std::min; | 16 using std::min; |
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 // The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a | 22 // The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a |
23 // fast retransmission. | 23 // fast retransmission. |
24 const QuicByteCount kDefaultMinimumCongestionWindow = 2 * kDefaultTCPMSS; | 24 const QuicByteCount kDefaultMinimumCongestionWindow = 2 * kDefaultTCPMSS; |
25 const QuicByteCount kMaxSegmentSize = kDefaultTCPMSS; | 25 const QuicByteCount kMaxBurstBytes = 3 * kDefaultTCPMSS; |
26 const QuicByteCount kMaxBurstBytes = 3 * kMaxSegmentSize; | |
27 const float kRenoBeta = 0.7f; // Reno backoff factor. | 26 const float kRenoBeta = 0.7f; // Reno backoff factor. |
28 const uint32 kDefaultNumConnections = 2; // N-connection emulation. | 27 const uint32 kDefaultNumConnections = 2; // N-connection emulation. |
29 } // namespace | 28 } // namespace |
30 | 29 |
31 TcpCubicBytesSender::TcpCubicBytesSender( | 30 TcpCubicBytesSender::TcpCubicBytesSender( |
32 const QuicClock* clock, | 31 const QuicClock* clock, |
33 const RttStats* rtt_stats, | 32 const RttStats* rtt_stats, |
34 bool reno, | 33 bool reno, |
35 QuicPacketCount initial_tcp_congestion_window, | 34 QuicPacketCount initial_tcp_congestion_window, |
36 QuicPacketCount max_congestion_window, | 35 QuicPacketCount max_congestion_window, |
37 QuicConnectionStats* stats) | 36 QuicConnectionStats* stats) |
38 : cubic_(clock), | 37 : cubic_(clock), |
39 rtt_stats_(rtt_stats), | 38 rtt_stats_(rtt_stats), |
40 stats_(stats), | 39 stats_(stats), |
41 reno_(reno), | 40 reno_(reno), |
42 num_connections_(kDefaultNumConnections), | 41 num_connections_(kDefaultNumConnections), |
43 num_acked_packets_(0), | 42 num_acked_packets_(0), |
44 largest_sent_packet_number_(0), | 43 largest_sent_packet_number_(0), |
45 largest_acked_packet_number_(0), | 44 largest_acked_packet_number_(0), |
46 largest_sent_at_last_cutback_(0), | 45 largest_sent_at_last_cutback_(0), |
47 congestion_window_(initial_tcp_congestion_window * kMaxSegmentSize), | 46 congestion_window_(initial_tcp_congestion_window * kDefaultTCPMSS), |
48 min_congestion_window_(kDefaultMinimumCongestionWindow), | 47 min_congestion_window_(kDefaultMinimumCongestionWindow), |
49 min4_mode_(false), | 48 min4_mode_(false), |
50 max_congestion_window_(max_congestion_window * kMaxSegmentSize), | 49 max_congestion_window_(max_congestion_window * kDefaultTCPMSS), |
51 slowstart_threshold_(max_congestion_window * kMaxSegmentSize), | 50 slowstart_threshold_(max_congestion_window * kDefaultTCPMSS), |
52 last_cutback_exited_slowstart_(false), | 51 last_cutback_exited_slowstart_(false) {} |
53 clock_(clock) {} | |
54 | 52 |
55 TcpCubicBytesSender::~TcpCubicBytesSender() { | 53 TcpCubicBytesSender::~TcpCubicBytesSender() { |
56 } | 54 } |
57 | 55 |
58 void TcpCubicBytesSender::SetFromConfig(const QuicConfig& config, | 56 void TcpCubicBytesSender::SetFromConfig(const QuicConfig& config, |
59 Perspective perspective) { | 57 Perspective perspective) { |
60 if (perspective == Perspective::IS_SERVER) { | 58 if (perspective == Perspective::IS_SERVER) { |
61 if (config.HasReceivedConnectionOptions() && | 59 if (config.HasReceivedConnectionOptions() && |
62 ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) { | 60 ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) { |
63 // Initial window experiment. | 61 // Initial window experiment. |
64 congestion_window_ = 10 * kMaxSegmentSize; | 62 congestion_window_ = 10 * kDefaultTCPMSS; |
65 } | 63 } |
66 if (config.HasReceivedConnectionOptions() && | 64 if (config.HasReceivedConnectionOptions() && |
67 ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN1)) { | 65 ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN1)) { |
68 // Min CWND experiment. | 66 // Min CWND experiment. |
69 min_congestion_window_ = kMaxSegmentSize; | 67 min_congestion_window_ = kDefaultTCPMSS; |
70 } | 68 } |
71 if (config.HasReceivedConnectionOptions() && | 69 if (config.HasReceivedConnectionOptions() && |
72 ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN4)) { | 70 ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN4)) { |
73 // Min CWND of 4 experiment. | 71 // Min CWND of 4 experiment. |
74 min4_mode_ = true; | 72 min4_mode_ = true; |
75 min_congestion_window_ = kMaxSegmentSize; | 73 min_congestion_window_ = kDefaultTCPMSS; |
76 } | 74 } |
77 } | 75 } |
78 } | 76 } |
79 | 77 |
80 void TcpCubicBytesSender::ResumeConnectionState( | 78 void TcpCubicBytesSender::ResumeConnectionState( |
81 const CachedNetworkParameters& cached_network_params, | 79 const CachedNetworkParameters& cached_network_params, |
82 bool max_bandwidth_resumption) { | 80 bool max_bandwidth_resumption) { |
83 QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond( | 81 QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond( |
84 max_bandwidth_resumption | 82 max_bandwidth_resumption |
85 ? cached_network_params.max_bandwidth_estimate_bytes_per_second() | 83 ? cached_network_params.max_bandwidth_estimate_bytes_per_second() |
86 : cached_network_params.bandwidth_estimate_bytes_per_second()); | 84 : cached_network_params.bandwidth_estimate_bytes_per_second()); |
87 QuicTime::Delta rtt_ms = | 85 QuicTime::Delta rtt_ms = |
88 QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); | 86 QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); |
89 | 87 |
90 // Make sure CWND is in appropriate range (in case of bad data). | 88 // Make sure CWND is in appropriate range (in case of bad data). |
91 QuicByteCount new_congestion_window = bandwidth.ToBytesPerPeriod(rtt_ms); | 89 QuicByteCount new_congestion_window = bandwidth.ToBytesPerPeriod(rtt_ms); |
92 congestion_window_ = | 90 congestion_window_ = |
93 max(min(new_congestion_window, kMaxCongestionWindow * kMaxSegmentSize), | 91 max(min(new_congestion_window, kMaxCongestionWindow * kDefaultTCPMSS), |
94 kMinCongestionWindowForBandwidthResumption * kMaxSegmentSize); | 92 kMinCongestionWindowForBandwidthResumption * kDefaultTCPMSS); |
95 } | 93 } |
96 | 94 |
97 void TcpCubicBytesSender::SetNumEmulatedConnections(int num_connections) { | 95 void TcpCubicBytesSender::SetNumEmulatedConnections(int num_connections) { |
98 num_connections_ = max(1, num_connections); | 96 num_connections_ = max(1, num_connections); |
99 cubic_.SetNumConnections(num_connections_); | 97 cubic_.SetNumConnections(num_connections_); |
100 } | 98 } |
101 | 99 |
102 void TcpCubicBytesSender::SetMaxCongestionWindow( | 100 void TcpCubicBytesSender::SetMaxCongestionWindow( |
103 QuicByteCount max_congestion_window) { | 101 QuicByteCount max_congestion_window) { |
104 max_congestion_window_ = max_congestion_window; | 102 max_congestion_window_ = max_congestion_window; |
105 } | 103 } |
106 | 104 |
107 float TcpCubicBytesSender::RenoBeta() const { | 105 float TcpCubicBytesSender::RenoBeta() const { |
108 // kNConnectionBeta is the backoff factor after loss for our N-connection | 106 // kNConnectionBeta is the backoff factor after loss for our N-connection |
109 // emulation, which emulates the effective backoff of an ensemble of N | 107 // emulation, which emulates the effective backoff of an ensemble of N |
110 // TCP-Reno connections on a single loss event. The effective multiplier is | 108 // TCP-Reno connections on a single loss event. The effective multiplier is |
111 // computed as: | 109 // computed as: |
112 return (num_connections_ - 1 + kRenoBeta) / num_connections_; | 110 return (num_connections_ - 1 + kRenoBeta) / num_connections_; |
113 } | 111 } |
114 | 112 |
115 void TcpCubicBytesSender::OnCongestionEvent( | 113 void TcpCubicBytesSender::OnCongestionEvent( |
116 bool rtt_updated, | 114 bool rtt_updated, |
117 QuicByteCount bytes_in_flight, | 115 QuicByteCount bytes_in_flight, |
118 const CongestionVector& acked_packets, | 116 const CongestionVector& acked_packets, |
119 const CongestionVector& lost_packets) { | 117 const CongestionVector& lost_packets) { |
120 if (rtt_updated && InSlowStart() && | 118 if (rtt_updated && InSlowStart() && |
121 hybrid_slow_start_.ShouldExitSlowStart( | 119 hybrid_slow_start_.ShouldExitSlowStart( |
122 rtt_stats_->latest_rtt(), rtt_stats_->min_rtt(), | 120 rtt_stats_->latest_rtt(), rtt_stats_->min_rtt(), |
123 congestion_window_ / kMaxSegmentSize)) { | 121 congestion_window_ / kDefaultTCPMSS)) { |
124 slowstart_threshold_ = congestion_window_; | 122 slowstart_threshold_ = congestion_window_; |
125 } | 123 } |
126 for (CongestionVector::const_iterator it = lost_packets.begin(); | 124 for (CongestionVector::const_iterator it = lost_packets.begin(); |
127 it != lost_packets.end(); ++it) { | 125 it != lost_packets.end(); ++it) { |
128 OnPacketLost(it->first, bytes_in_flight); | 126 OnPacketLost(it->first, bytes_in_flight); |
129 } | 127 } |
130 for (CongestionVector::const_iterator it = acked_packets.begin(); | 128 for (CongestionVector::const_iterator it = acked_packets.begin(); |
131 it != acked_packets.end(); ++it) { | 129 it != acked_packets.end(); ++it) { |
132 OnPacketAcked(it->first, it->second, bytes_in_flight); | 130 OnPacketAcked(it->first, it->second, bytes_in_flight); |
133 } | 131 } |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 return QuicTime::Delta::Zero(); | 218 return QuicTime::Delta::Zero(); |
221 } | 219 } |
222 if (InRecovery()) { | 220 if (InRecovery()) { |
223 // PRR is used when in recovery. | 221 // PRR is used when in recovery. |
224 return prr_.TimeUntilSend(GetCongestionWindow(), bytes_in_flight, | 222 return prr_.TimeUntilSend(GetCongestionWindow(), bytes_in_flight, |
225 slowstart_threshold_); | 223 slowstart_threshold_); |
226 } | 224 } |
227 if (GetCongestionWindow() > bytes_in_flight) { | 225 if (GetCongestionWindow() > bytes_in_flight) { |
228 return QuicTime::Delta::Zero(); | 226 return QuicTime::Delta::Zero(); |
229 } | 227 } |
230 if (min4_mode_ && bytes_in_flight < 4 * kMaxSegmentSize) { | 228 if (min4_mode_ && bytes_in_flight < 4 * kDefaultTCPMSS) { |
231 return QuicTime::Delta::Zero(); | 229 return QuicTime::Delta::Zero(); |
232 } | 230 } |
233 return QuicTime::Delta::Infinite(); | 231 return QuicTime::Delta::Infinite(); |
234 } | 232 } |
235 | 233 |
236 QuicBandwidth TcpCubicBytesSender::PacingRate() const { | 234 QuicBandwidth TcpCubicBytesSender::PacingRate() const { |
237 // We pace at twice the rate of the underlying sender's bandwidth estimate | 235 // We pace at twice the rate of the underlying sender's bandwidth estimate |
238 // during slow start and 1.25x during congestion avoidance to ensure pacing | 236 // during slow start and 1.25x during congestion avoidance to ensure pacing |
239 // doesn't prevent us from filling the window. | 237 // doesn't prevent us from filling the window. |
240 QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); | 238 QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
303 if (FLAGS_reset_cubic_epoch_when_app_limited) { | 301 if (FLAGS_reset_cubic_epoch_when_app_limited) { |
304 cubic_.OnApplicationLimited(); | 302 cubic_.OnApplicationLimited(); |
305 } | 303 } |
306 return; | 304 return; |
307 } | 305 } |
308 if (congestion_window_ >= max_congestion_window_) { | 306 if (congestion_window_ >= max_congestion_window_) { |
309 return; | 307 return; |
310 } | 308 } |
311 if (InSlowStart()) { | 309 if (InSlowStart()) { |
312 // TCP slow start, exponential growth, increase by one for each ACK. | 310 // TCP slow start, exponential growth, increase by one for each ACK. |
313 congestion_window_ += kMaxSegmentSize; | 311 congestion_window_ += kDefaultTCPMSS; |
314 DVLOG(1) << "Slow start; congestion window: " << congestion_window_ | 312 DVLOG(1) << "Slow start; congestion window: " << congestion_window_ |
315 << " slowstart threshold: " << slowstart_threshold_; | 313 << " slowstart threshold: " << slowstart_threshold_; |
316 return; | 314 return; |
317 } | 315 } |
318 // Congestion avoidance. | 316 // Congestion avoidance. |
319 if (reno_) { | 317 if (reno_) { |
320 // Classic Reno congestion avoidance. | 318 // Classic Reno congestion avoidance. |
321 ++num_acked_packets_; | 319 ++num_acked_packets_; |
322 // Divide by num_connections to smoothly increase the CWND at a faster rate | 320 // Divide by num_connections to smoothly increase the CWND at a faster rate |
323 // than conventional Reno. | 321 // than conventional Reno. |
324 if (num_acked_packets_ * num_connections_ >= | 322 if (num_acked_packets_ * num_connections_ >= |
325 congestion_window_ / kMaxSegmentSize) { | 323 congestion_window_ / kDefaultTCPMSS) { |
326 congestion_window_ += kMaxSegmentSize; | 324 congestion_window_ += kDefaultTCPMSS; |
327 num_acked_packets_ = 0; | 325 num_acked_packets_ = 0; |
328 } | 326 } |
329 | 327 |
330 DVLOG(1) << "Reno; congestion window: " << congestion_window_ | 328 DVLOG(1) << "Reno; congestion window: " << congestion_window_ |
331 << " slowstart threshold: " << slowstart_threshold_ | 329 << " slowstart threshold: " << slowstart_threshold_ |
332 << " congestion window count: " << num_acked_packets_; | 330 << " congestion window count: " << num_acked_packets_; |
333 } else { | 331 } else { |
334 congestion_window_ = | 332 congestion_window_ = |
335 min(max_congestion_window_, | 333 min(max_congestion_window_, |
336 cubic_.CongestionWindowAfterAck(acked_bytes, congestion_window_, | 334 cubic_.CongestionWindowAfterAck(acked_bytes, congestion_window_, |
(...skipping 12 matching lines...) Expand all Loading... |
349 hybrid_slow_start_.Restart(); | 347 hybrid_slow_start_.Restart(); |
350 slowstart_threshold_ = congestion_window_ / 2; | 348 slowstart_threshold_ = congestion_window_ / 2; |
351 congestion_window_ = min_congestion_window_; | 349 congestion_window_ = min_congestion_window_; |
352 } | 350 } |
353 | 351 |
354 CongestionControlType TcpCubicBytesSender::GetCongestionControlType() const { | 352 CongestionControlType TcpCubicBytesSender::GetCongestionControlType() const { |
355 return reno_ ? kRenoBytes : kCubicBytes; | 353 return reno_ ? kRenoBytes : kCubicBytes; |
356 } | 354 } |
357 | 355 |
358 } // namespace net | 356 } // namespace net |
OLD | NEW |