| 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 |