OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_sender.h" | 5 #include "net/quic/congestion_control/tcp_cubic_sender.h" |
6 | 6 |
7 namespace net { | 7 namespace net { |
8 | 8 |
9 namespace { | 9 namespace { |
10 // Constants based on TCP defaults. | 10 // Constants based on TCP defaults. |
11 const int64 kHybridStartLowWindow = 16; | 11 const int64 kHybridStartLowWindow = 16; |
12 const QuicByteCount kMaxSegmentSize = kMaxPacketSize; | 12 const QuicByteCount kMaxSegmentSize = kMaxPacketSize; |
13 const QuicByteCount kDefaultReceiveWindow = 64000; | 13 const QuicByteCount kDefaultReceiveWindow = 64000; |
14 const int64 kInitialCongestionWindow = 10; | 14 const int64 kInitialCongestionWindow = 10; |
15 const int64 kMaxCongestionWindow = 10000; | 15 const int64 kMaxCongestionWindow = 10000; |
16 const int kMaxBurstLength = 3; | 16 const int kMaxBurstLength = 3; |
| 17 const int kInitialRttMs = 60; // At a typical RTT 60 ms. |
17 }; | 18 }; |
18 | 19 |
19 TcpCubicSender::TcpCubicSender(const QuicClock* clock, bool reno) | 20 TcpCubicSender::TcpCubicSender(const QuicClock* clock, bool reno) |
20 : hybrid_slow_start_(clock), | 21 : hybrid_slow_start_(clock), |
21 cubic_(clock), | 22 cubic_(clock), |
22 reno_(reno), | 23 reno_(reno), |
23 congestion_window_count_(0), | 24 congestion_window_count_(0), |
24 receiver_congestion_window_(kDefaultReceiveWindow), | 25 receiver_congestion_window_(kDefaultReceiveWindow), |
25 last_received_accumulated_number_of_lost_packets_(0), | 26 last_received_accumulated_number_of_lost_packets_(0), |
26 bytes_in_flight_(0), | 27 bytes_in_flight_(0), |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
77 // Sanity, make sure that we don't end up with an empty window. | 78 // Sanity, make sure that we don't end up with an empty window. |
78 if (congestion_window_ == 0) { | 79 if (congestion_window_ == 0) { |
79 congestion_window_ = 1; | 80 congestion_window_ = 1; |
80 } | 81 } |
81 DLOG(INFO) << "Incoming loss; congestion window:" << congestion_window_; | 82 DLOG(INFO) << "Incoming loss; congestion window:" << congestion_window_; |
82 } | 83 } |
83 | 84 |
84 void TcpCubicSender::SentPacket(QuicTime /*sent_time*/, | 85 void TcpCubicSender::SentPacket(QuicTime /*sent_time*/, |
85 QuicPacketSequenceNumber sequence_number, | 86 QuicPacketSequenceNumber sequence_number, |
86 QuicByteCount bytes, | 87 QuicByteCount bytes, |
87 bool is_retransmission, | 88 bool is_retransmission) { |
88 bool has_retransmittable_data) { | 89 bytes_in_flight_ += bytes; |
89 if (!is_retransmission && has_retransmittable_data) { | |
90 bytes_in_flight_ += bytes; | |
91 } | |
92 if (!is_retransmission && update_end_sequence_number_) { | 90 if (!is_retransmission && update_end_sequence_number_) { |
93 end_sequence_number_ = sequence_number; | 91 end_sequence_number_ = sequence_number; |
94 if (AvailableCongestionWindow() == 0) { | 92 if (AvailableCongestionWindow() == 0) { |
95 update_end_sequence_number_ = false; | 93 update_end_sequence_number_ = false; |
96 DLOG(INFO) << "Stop update end sequence number @" << sequence_number; | 94 DLOG(INFO) << "Stop update end sequence number @" << sequence_number; |
97 } | 95 } |
98 } | 96 } |
99 } | 97 } |
100 | 98 |
| 99 void TcpCubicSender::AbandoningPacket(QuicPacketSequenceNumber sequence_number, |
| 100 QuicByteCount abandoned_bytes) { |
| 101 bytes_in_flight_ -= abandoned_bytes; |
| 102 } |
| 103 |
101 QuicTime::Delta TcpCubicSender::TimeUntilSend(QuicTime now, | 104 QuicTime::Delta TcpCubicSender::TimeUntilSend(QuicTime now, |
102 bool is_retransmission) { | 105 bool is_retransmission, |
103 if (is_retransmission) { | 106 bool has_retransmittable_data) { |
104 // For TCP we can always send a retransmission immediately. | 107 if (is_retransmission || !has_retransmittable_data) { |
| 108 // For TCP we can always send a retransmission and/or an ACK immediately. |
105 return QuicTime::Delta::Zero(); | 109 return QuicTime::Delta::Zero(); |
106 } | 110 } |
107 if (AvailableCongestionWindow() == 0) { | 111 if (AvailableCongestionWindow() == 0) { |
108 return QuicTime::Delta::Infinite(); | 112 return QuicTime::Delta::Infinite(); |
109 } | 113 } |
110 return QuicTime::Delta::Zero(); | 114 return QuicTime::Delta::Zero(); |
111 } | 115 } |
112 | 116 |
113 QuicByteCount TcpCubicSender::AvailableCongestionWindow() { | 117 QuicByteCount TcpCubicSender::AvailableCongestionWindow() { |
114 if (bytes_in_flight_ > CongestionWindow()) { | 118 if (bytes_in_flight_ > CongestionWindow()) { |
115 return 0; | 119 return 0; |
116 } | 120 } |
117 return CongestionWindow() - bytes_in_flight_; | 121 return CongestionWindow() - bytes_in_flight_; |
118 } | 122 } |
119 | 123 |
120 QuicByteCount TcpCubicSender::CongestionWindow() { | 124 QuicByteCount TcpCubicSender::CongestionWindow() { |
121 // What's the current congestion window in bytes. | 125 // What's the current congestion window in bytes. |
122 return std::min(receiver_congestion_window_, | 126 return std::min(receiver_congestion_window_, |
123 congestion_window_ * kMaxSegmentSize); | 127 congestion_window_ * kMaxSegmentSize); |
124 } | 128 } |
125 | 129 |
126 QuicBandwidth TcpCubicSender::BandwidthEstimate() { | 130 QuicBandwidth TcpCubicSender::BandwidthEstimate() { |
127 // TODO(pwestin): make a long term estimate, based on RTT and loss rate? or | 131 // TODO(pwestin): make a long term estimate, based on RTT and loss rate? or |
128 // instantaneous estimate? | 132 // instantaneous estimate? |
129 // Throughput ~= (1/RTT)*sqrt(3/2p) | 133 // Throughput ~= (1/RTT)*sqrt(3/2p) |
130 return QuicBandwidth::Zero(); | 134 return QuicBandwidth::Zero(); |
131 } | 135 } |
132 | 136 |
| 137 QuicTime::Delta TcpCubicSender::SmoothedRtt() { |
| 138 // TODO(satyamshekhar): Return the smoothed averaged RTT. |
| 139 if (delay_min_.IsZero()) { |
| 140 return QuicTime::Delta::FromMilliseconds(kInitialRttMs); |
| 141 } |
| 142 return delay_min_; |
| 143 } |
| 144 |
133 void TcpCubicSender::Reset() { | 145 void TcpCubicSender::Reset() { |
134 delay_min_ = QuicTime::Delta::Zero(); | 146 delay_min_ = QuicTime::Delta::Zero(); |
135 hybrid_slow_start_.Restart(); | 147 hybrid_slow_start_.Restart(); |
136 } | 148 } |
137 | 149 |
138 bool TcpCubicSender::IsCwndLimited() const { | 150 bool TcpCubicSender::IsCwndLimited() const { |
139 const QuicByteCount congestion_window_bytes = congestion_window_ * | 151 const QuicByteCount congestion_window_bytes = congestion_window_ * |
140 kMaxSegmentSize; | 152 kMaxSegmentSize; |
141 if (bytes_in_flight_ >= congestion_window_bytes) { | 153 if (bytes_in_flight_ >= congestion_window_bytes) { |
142 return true; | 154 return true; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 } | 197 } |
186 } | 198 } |
187 | 199 |
188 // TODO(pwestin): what is the timout value? | 200 // TODO(pwestin): what is the timout value? |
189 void TcpCubicSender::OnTimeOut() { | 201 void TcpCubicSender::OnTimeOut() { |
190 cubic_.Reset(); | 202 cubic_.Reset(); |
191 congestion_window_ = 1; | 203 congestion_window_ = 1; |
192 } | 204 } |
193 | 205 |
194 void TcpCubicSender::AckAccounting(QuicTime::Delta rtt) { | 206 void TcpCubicSender::AckAccounting(QuicTime::Delta rtt) { |
195 if (rtt.ToMicroseconds() <= 0) { | 207 if (rtt.IsInfinite() || rtt.IsZero()) { |
196 // RTT can't be 0 or negative. | |
197 return; | 208 return; |
198 } | 209 } |
| 210 // RTT can't be negative. |
| 211 DCHECK_LT(0, rtt.ToMicroseconds()); |
| 212 |
199 // TODO(pwestin): Discard delay samples right after fast recovery, | 213 // TODO(pwestin): Discard delay samples right after fast recovery, |
200 // during 1 second?. | 214 // during 1 second?. |
201 | 215 |
202 // First time call or link delay decreases. | 216 // First time call or link delay decreases. |
203 if (delay_min_.IsZero() || delay_min_ > rtt) { | 217 if (delay_min_.IsZero() || delay_min_ > rtt) { |
204 delay_min_ = rtt; | 218 delay_min_ = rtt; |
205 } | 219 } |
206 // Hybrid start triggers when cwnd is larger than some threshold. | 220 // Hybrid start triggers when cwnd is larger than some threshold. |
207 if (congestion_window_ <= slowstart_threshold_ && | 221 if (congestion_window_ <= slowstart_threshold_ && |
208 congestion_window_ >= kHybridStartLowWindow) { | 222 congestion_window_ >= kHybridStartLowWindow) { |
209 if (!hybrid_slow_start_.started()) { | 223 if (!hybrid_slow_start_.started()) { |
210 // Time to start the hybrid slow start. | 224 // Time to start the hybrid slow start. |
211 hybrid_slow_start_.Reset(end_sequence_number_); | 225 hybrid_slow_start_.Reset(end_sequence_number_); |
212 } | 226 } |
213 hybrid_slow_start_.Update(rtt, delay_min_); | 227 hybrid_slow_start_.Update(rtt, delay_min_); |
214 if (hybrid_slow_start_.Exit()) { | 228 if (hybrid_slow_start_.Exit()) { |
215 slowstart_threshold_ = congestion_window_; | 229 slowstart_threshold_ = congestion_window_; |
216 } | 230 } |
217 } | 231 } |
218 } | 232 } |
219 | 233 |
220 } // namespace net | 234 } // namespace net |
OLD | NEW |