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/core/congestion_control/cubic.h" | 5 #include "net/quic/core/congestion_control/cubic.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 #include <algorithm> | 8 #include <algorithm> |
9 #include <cmath> | 9 #include <cmath> |
10 | 10 |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "net/quic/core/quic_flags.h" | 12 #include "net/quic/core/quic_flags.h" |
13 #include "net/quic/core/quic_protocol.h" | 13 #include "net/quic/core/quic_protocol.h" |
14 #include "net/quic/core/quic_time.h" | 14 #include "net/quic/core/quic_time.h" |
15 | 15 |
16 using std::max; | 16 using std::max; |
| 17 using std::min; |
17 | 18 |
18 namespace net { | 19 namespace net { |
19 | 20 |
20 namespace { | 21 namespace { |
21 | 22 |
22 // Constants based on TCP defaults. | 23 // Constants based on TCP defaults. |
23 // The following constants are in 2^10 fractions of a second instead of ms to | 24 // The following constants are in 2^10 fractions of a second instead of ms to |
24 // allow a 10 shift right to divide. | 25 // allow a 10 shift right to divide. |
25 const int kCubeScale = 40; // 1024*1024^3 (first 1024 is from 0.100^3) | 26 const int kCubeScale = 40; // 1024*1024^3 (first 1024 is from 0.100^3) |
26 // where 0.100 is 100 ms which is the scaling | 27 // where 0.100 is 100 ms which is the scaling |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 return (num_connections_ - 1 + kBeta) / num_connections_; | 68 return (num_connections_ - 1 + kBeta) / num_connections_; |
68 } | 69 } |
69 | 70 |
70 void Cubic::Reset() { | 71 void Cubic::Reset() { |
71 epoch_ = QuicTime::Zero(); // Reset time. | 72 epoch_ = QuicTime::Zero(); // Reset time. |
72 app_limited_start_time_ = QuicTime::Zero(); | 73 app_limited_start_time_ = QuicTime::Zero(); |
73 last_update_time_ = QuicTime::Zero(); // Reset time. | 74 last_update_time_ = QuicTime::Zero(); // Reset time. |
74 last_congestion_window_ = 0; | 75 last_congestion_window_ = 0; |
75 last_max_congestion_window_ = 0; | 76 last_max_congestion_window_ = 0; |
76 acked_packets_count_ = 0; | 77 acked_packets_count_ = 0; |
| 78 epoch_packets_count_ = 0; |
77 estimated_tcp_congestion_window_ = 0; | 79 estimated_tcp_congestion_window_ = 0; |
78 origin_point_congestion_window_ = 0; | 80 origin_point_congestion_window_ = 0; |
79 time_to_origin_point_ = 0; | 81 time_to_origin_point_ = 0; |
80 last_target_congestion_window_ = 0; | 82 last_target_congestion_window_ = 0; |
81 } | 83 } |
82 | 84 |
83 void Cubic::OnApplicationLimited() { | 85 void Cubic::OnApplicationLimited() { |
84 // When sender is not using the available congestion window, Cubic's epoch | 86 // When sender is not using the available congestion window, Cubic's epoch |
85 // should not continue growing. Reset the epoch when in such a period. | 87 // should not continue growing. Reset the epoch when in such a period. |
86 epoch_ = QuicTime::Zero(); | 88 epoch_ = QuicTime::Zero(); |
(...skipping 10 matching lines...) Expand all Loading... |
97 last_max_congestion_window_ = current_congestion_window; | 99 last_max_congestion_window_ = current_congestion_window; |
98 } | 100 } |
99 epoch_ = QuicTime::Zero(); // Reset time. | 101 epoch_ = QuicTime::Zero(); // Reset time. |
100 return static_cast<int>(current_congestion_window * Beta()); | 102 return static_cast<int>(current_congestion_window * Beta()); |
101 } | 103 } |
102 | 104 |
103 QuicPacketCount Cubic::CongestionWindowAfterAck( | 105 QuicPacketCount Cubic::CongestionWindowAfterAck( |
104 QuicPacketCount current_congestion_window, | 106 QuicPacketCount current_congestion_window, |
105 QuicTime::Delta delay_min) { | 107 QuicTime::Delta delay_min) { |
106 acked_packets_count_ += 1; // Packets acked. | 108 acked_packets_count_ += 1; // Packets acked. |
| 109 epoch_packets_count_ += 1; |
107 QuicTime current_time = clock_->ApproximateNow(); | 110 QuicTime current_time = clock_->ApproximateNow(); |
108 | 111 |
109 // Cubic is "independent" of RTT, the update is limited by the time elapsed. | 112 // Cubic is "independent" of RTT, the update is limited by the time elapsed. |
110 if (last_congestion_window_ == current_congestion_window && | 113 if (last_congestion_window_ == current_congestion_window && |
111 (current_time - last_update_time_ <= MaxCubicTimeInterval())) { | 114 (current_time - last_update_time_ <= MaxCubicTimeInterval())) { |
112 return max(last_target_congestion_window_, | 115 return max(last_target_congestion_window_, |
113 estimated_tcp_congestion_window_); | 116 estimated_tcp_congestion_window_); |
114 } | 117 } |
115 last_congestion_window_ = current_congestion_window; | 118 last_congestion_window_ = current_congestion_window; |
116 last_update_time_ = current_time; | 119 last_update_time_ = current_time; |
117 | 120 |
118 if (!epoch_.IsInitialized()) { | 121 if (!epoch_.IsInitialized()) { |
119 // First ACK after a loss event. | 122 // First ACK after a loss event. |
120 epoch_ = current_time; // Start of epoch. | 123 epoch_ = current_time; // Start of epoch. |
121 acked_packets_count_ = 1; // Reset count. | 124 acked_packets_count_ = 1; // Reset count. |
| 125 epoch_packets_count_ = 1; |
122 // Reset estimated_tcp_congestion_window_ to be in sync with cubic. | 126 // Reset estimated_tcp_congestion_window_ to be in sync with cubic. |
123 estimated_tcp_congestion_window_ = current_congestion_window; | 127 estimated_tcp_congestion_window_ = current_congestion_window; |
124 if (last_max_congestion_window_ <= current_congestion_window) { | 128 if (last_max_congestion_window_ <= current_congestion_window) { |
125 time_to_origin_point_ = 0; | 129 time_to_origin_point_ = 0; |
126 origin_point_congestion_window_ = current_congestion_window; | 130 origin_point_congestion_window_ = current_congestion_window; |
127 } else { | 131 } else { |
128 time_to_origin_point_ = static_cast<uint32_t>( | 132 time_to_origin_point_ = static_cast<uint32_t>( |
129 cbrt(kCubeFactor * | 133 cbrt(kCubeFactor * |
130 (last_max_congestion_window_ - current_congestion_window))); | 134 (last_max_congestion_window_ - current_congestion_window))); |
131 origin_point_congestion_window_ = last_max_congestion_window_; | 135 origin_point_congestion_window_ = last_max_congestion_window_; |
132 } | 136 } |
133 } | 137 } |
134 | 138 |
135 // Change the time unit from microseconds to 2^10 fractions per second. Take | 139 // Change the time unit from microseconds to 2^10 fractions per second. Take |
136 // the round trip time in account. This is done to allow us to use shift as a | 140 // the round trip time in account. This is done to allow us to use shift as a |
137 // divide operator. | 141 // divide operator. |
138 int64_t elapsed_time = | 142 int64_t elapsed_time = |
139 ((current_time + delay_min - epoch_).ToMicroseconds() << 10) / | 143 ((current_time + delay_min - epoch_).ToMicroseconds() << 10) / |
140 kNumMicrosPerSecond; | 144 kNumMicrosPerSecond; |
141 | 145 |
142 int64_t offset = time_to_origin_point_ - elapsed_time; | 146 int64_t offset = time_to_origin_point_ - elapsed_time; |
143 QuicPacketCount delta_congestion_window = | 147 QuicPacketCount delta_congestion_window = |
144 (kCubeCongestionWindowScale * offset * offset * offset) >> kCubeScale; | 148 (kCubeCongestionWindowScale * offset * offset * offset) >> kCubeScale; |
145 | 149 |
146 QuicPacketCount target_congestion_window = | 150 QuicPacketCount target_congestion_window = |
147 origin_point_congestion_window_ - delta_congestion_window; | 151 origin_point_congestion_window_ - delta_congestion_window; |
148 | 152 |
| 153 if (FLAGS_quic_limit_cubic_cwnd_increase) { |
| 154 // Limit the CWND increase to half the acked packets rounded up to the |
| 155 // nearest packet. |
| 156 target_congestion_window = |
| 157 min(target_congestion_window, |
| 158 current_congestion_window + (epoch_packets_count_ + 1) / 2); |
| 159 } |
| 160 |
149 DCHECK_LT(0u, estimated_tcp_congestion_window_); | 161 DCHECK_LT(0u, estimated_tcp_congestion_window_); |
150 // With dynamic beta/alpha based on number of active streams, it is possible | 162 // With dynamic beta/alpha based on number of active streams, it is possible |
151 // for the required_ack_count to become much lower than acked_packets_count_ | 163 // for the required_ack_count to become much lower than acked_packets_count_ |
152 // suddenly, leading to more than one iteration through the following loop. | 164 // suddenly, leading to more than one iteration through the following loop. |
153 while (true) { | 165 while (true) { |
154 // Update estimated TCP congestion_window. | 166 // Update estimated TCP congestion_window. |
155 QuicPacketCount required_ack_count = static_cast<QuicPacketCount>( | 167 QuicPacketCount required_ack_count = static_cast<QuicPacketCount>( |
156 estimated_tcp_congestion_window_ / Alpha()); | 168 estimated_tcp_congestion_window_ / Alpha()); |
157 if (acked_packets_count_ < required_ack_count) { | 169 if (acked_packets_count_ < required_ack_count) { |
158 break; | 170 break; |
159 } | 171 } |
160 acked_packets_count_ -= required_ack_count; | 172 acked_packets_count_ -= required_ack_count; |
161 estimated_tcp_congestion_window_++; | 173 estimated_tcp_congestion_window_++; |
162 } | 174 } |
| 175 epoch_packets_count_ = 0; |
163 | 176 |
164 // We have a new cubic congestion window. | 177 // We have a new cubic congestion window. |
165 last_target_congestion_window_ = target_congestion_window; | 178 last_target_congestion_window_ = target_congestion_window; |
166 | 179 |
167 // Compute target congestion_window based on cubic target and estimated TCP | 180 // Compute target congestion_window based on cubic target and estimated TCP |
168 // congestion_window, use highest (fastest). | 181 // congestion_window, use highest (fastest). |
169 if (target_congestion_window < estimated_tcp_congestion_window_) { | 182 if (target_congestion_window < estimated_tcp_congestion_window_) { |
170 target_congestion_window = estimated_tcp_congestion_window_; | 183 target_congestion_window = estimated_tcp_congestion_window_; |
171 } | 184 } |
172 | 185 |
173 DVLOG(1) << "Final target congestion_window: " << target_congestion_window; | 186 DVLOG(1) << "Final target congestion_window: " << target_congestion_window; |
174 return target_congestion_window; | 187 return target_congestion_window; |
175 } | 188 } |
176 | 189 |
177 } // namespace net | 190 } // namespace net |
OLD | NEW |