Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(67)

Side by Side Diff: net/quic/congestion_control/send_algorithm_simulator.cc

Issue 330333006: Land Recent QUIC Changes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/quic/congestion_control/send_algorithm_simulator.h"
6
7 #include <limits>
8
9 #include "base/logging.h"
10 #include "base/rand_util.h"
11 #include "net/quic/crypto/quic_random.h"
12
13 using std::list;
14 using std::max;
15 using std::min;
16
17 namespace net {
18
19 SendAlgorithmSimulator::SendAlgorithmSimulator(
20 SendAlgorithmInterface* send_algorithm,
21 MockClock* clock,
22 RttStats* rtt_stats,
23 QuicBandwidth bandwidth,
24 QuicTime::Delta rtt)
25 : send_algorithm_(send_algorithm),
26 clock_(clock),
27 rtt_stats_(rtt_stats),
28 next_sent_(1),
29 last_acked_(0),
30 next_acked_(1),
31 lose_next_ack_(false),
32 bytes_in_flight_(0),
33 forward_loss_rate_(0),
34 reverse_loss_rate_(0),
35 loss_correlation_(0),
36 bandwidth_(bandwidth),
37 rtt_(rtt),
38 buffer_size_(1000000),
39 max_cwnd_(0),
40 min_cwnd_(100000),
41 max_cwnd_drop_(0),
42 last_cwnd_(0) {
43 uint32 seed = base::RandInt(0, std::numeric_limits<int32>::max());
44 DVLOG(1) << "Seeding SendAlgorithmSimulator with " << seed;
45 simple_random_.set_seed(seed);
46 }
47
48 SendAlgorithmSimulator::~SendAlgorithmSimulator() {}
49
50 // Sends the specified number of bytes as quickly as possible and returns the
51 // average bandwidth in bytes per second. The time elapsed is based on
52 // waiting for all acks to arrive.
53 QuicBandwidth SendAlgorithmSimulator::SendBytes(size_t num_bytes) {
54 const QuicTime start_time = clock_->Now();
55 size_t bytes_acked = 0;
56 while (bytes_acked < num_bytes) {
57 DVLOG(1) << "bytes_acked:" << bytes_acked << " bytes_in_flight_:"
58 << bytes_in_flight_ << " CWND(bytes):"
59 << send_algorithm_->GetCongestionWindow();
60 // Determine the times of next send and of the next ack arrival.
61 QuicTime::Delta send_delta = send_algorithm_->TimeUntilSend(
62 clock_->Now(), bytes_in_flight_, HAS_RETRANSMITTABLE_DATA);
63 // If we've already sent enough bytes, wait for them to be acked.
64 if (bytes_acked + bytes_in_flight_ >= num_bytes) {
65 send_delta = QuicTime::Delta::Infinite();
66 }
67 QuicTime::Delta ack_delta = NextAckDelta();
68 // If both times are infinite, fire a TLP.
69 if (ack_delta.IsInfinite() && send_delta.IsInfinite()) {
70 DVLOG(1) << "Both times are infinite, simulating a TLP.";
71 // TODO(ianswett): Use a more sophisticated TLP timer.
72 clock_->AdvanceTime(QuicTime::Delta::FromMilliseconds(100));
73 SendDataNow();
74 } else if (ack_delta < send_delta) {
75 DVLOG(1) << "Handling ack, advancing time:"
76 << ack_delta.ToMicroseconds() << "us";
77 // Ack data all the data up to ack time and lose any missing sequence
78 // numbers.
79 clock_->AdvanceTime(ack_delta);
80 bytes_acked += HandlePendingAck();
81 } else {
82 DVLOG(1) << "Sending, advancing time:"
83 << send_delta.ToMicroseconds() << "us";
84 clock_->AdvanceTime(send_delta);
85 SendDataNow();
86 }
87 RecordStats();
88 }
89 return QuicBandwidth::FromBytesAndTimeDelta(
90 num_bytes, clock_->Now().Subtract(start_time));
91 }
92
93 // NextAck takes into account packet loss in both forward and reverse
94 // direction, as well as correlated losses. And it assumes the receiver acks
95 // every other packet when there is no loss.
96 QuicTime::Delta SendAlgorithmSimulator::NextAckDelta() {
97 if (sent_packets_.empty() || AllPacketsLost()) {
98 DVLOG(1) << "No outstanding packets to cause acks. sent_packets_.size():"
99 << sent_packets_.size();
100 return QuicTime::Delta::Infinite();
101 }
102
103 // If necessary, determine next_acked_.
104 // This is only done once to ensure multiple calls return the same time.
105 FindNextAcked();
106
107 // If only one packet is acked, simulate a delayed ack.
108 if (next_acked_ - last_acked_ == 1) {
109 return sent_packets_.front().ack_time.Add(
110 QuicTime::Delta::FromMilliseconds(100)).Subtract(clock_->Now());
111 }
112 for (list<SentPacket>::const_iterator it = sent_packets_.begin();
113 it != sent_packets_.end(); ++it) {
114 if (next_acked_ == it->sequence_number) {
115 return it->ack_time.Subtract(clock_->Now());
116 }
117 }
118 LOG(DFATAL) << "Error, next_acked_: " << next_acked_
119 << " should have been found in sent_packets_";
120 return QuicTime::Delta::Infinite();
121 }
122
123 bool SendAlgorithmSimulator::AllPacketsLost() {
124 for (list<SentPacket>::const_iterator it = sent_packets_.begin();
125 it != sent_packets_.end(); ++it) {
126 if (it->ack_time.IsInitialized()) {
127 return false;
128 }
129 }
130 return true;
131 }
132
133 void SendAlgorithmSimulator::FindNextAcked() {
134 // TODO(ianswett): Add a simpler mode which acks every packet.
135 bool packets_lost = false;
136 if (next_acked_ == last_acked_) {
137 // Determine if the next ack is lost only once, to ensure determinism.
138 lose_next_ack_ =
139 reverse_loss_rate_ * kuint64max > simple_random_.RandUint64();
140 }
141 bool two_acks_remaining = lose_next_ack_;
142 next_acked_ = last_acked_;
143 // Remove any packets that are simulated as lost.
144 for (list<SentPacket>::const_iterator it = sent_packets_.begin();
145 it != sent_packets_.end(); ++it) {
146 // Lost packets don't trigger an ack.
147 if (it->ack_time == QuicTime::Zero()) {
148 packets_lost = true;
149 continue;
150 }
151 // Buffer dropped packets are skipped automatically, but still end up
152 // being lost and cause acks to be sent immediately.
153 if (next_acked_ < it->sequence_number - 1) {
154 packets_lost = true;
155 }
156 next_acked_ = it->sequence_number;
157 if (packets_lost || (next_acked_ - last_acked_) % 2 == 0) {
158 if (two_acks_remaining) {
159 two_acks_remaining = false;
160 } else {
161 break;
162 }
163 }
164 }
165 DVLOG(1) << "FindNextAcked found next_acked_:" << next_acked_
166 << " last_acked:" << last_acked_;
167 }
168
169 int SendAlgorithmSimulator::HandlePendingAck() {
170 DCHECK_LT(last_acked_, next_acked_);
171 SendAlgorithmInterface::CongestionMap acked_packets;
172 SendAlgorithmInterface::CongestionMap lost_packets;
173 // Some entries may be missing from the sent_packets_ array, if they were
174 // dropped due to buffer overruns.
175 SentPacket largest_observed = sent_packets_.front();
176 while (last_acked_ < next_acked_) {
177 ++last_acked_;
178 TransmissionInfo info = TransmissionInfo();
179 info.bytes_sent = kPacketSize;
180 info.in_flight = true;
181 // If it's missing from the array, it's a loss.
182 if (sent_packets_.front().sequence_number > last_acked_) {
183 DVLOG(1) << "Lost packet:" << last_acked_
184 << " dropped by buffer overflow.";
185 lost_packets[last_acked_] = info;
186 continue;
187 }
188 if (sent_packets_.front().ack_time.IsInitialized()) {
189 acked_packets[last_acked_] = info;
190 } else {
191 lost_packets[last_acked_] = info;
192 }
193 // Remove all packets from the front to next_acked_.
194 largest_observed = sent_packets_.front();
195 sent_packets_.pop_front();
196 }
197
198 DCHECK(largest_observed.ack_time.IsInitialized());
199 rtt_stats_->UpdateRtt(
200 largest_observed.ack_time.Subtract(largest_observed.send_time),
201 QuicTime::Delta::Zero(),
202 clock_->Now());
203 send_algorithm_->OnCongestionEvent(
204 true, bytes_in_flight_, acked_packets, lost_packets);
205 DCHECK_LE(kPacketSize * (acked_packets.size() + lost_packets.size()),
206 bytes_in_flight_);
207 bytes_in_flight_ -=
208 kPacketSize * (acked_packets.size() + lost_packets.size());
209 return acked_packets.size() * kPacketSize;
210 }
211
212 void SendAlgorithmSimulator::SendDataNow() {
213 DVLOG(1) << "Sending packet:" << next_sent_ << " bytes_in_flight:"
214 << bytes_in_flight_;
215 send_algorithm_->OnPacketSent(
216 clock_->Now(), bytes_in_flight_,
217 next_sent_, kPacketSize, HAS_RETRANSMITTABLE_DATA);
218 // Lose the packet immediately if the buffer is full.
219 if (sent_packets_.size() * kPacketSize < buffer_size_) {
220 // TODO(ianswett): This buffer simulation is an approximation.
221 // An ack time of zero means loss.
222 bool packet_lost =
223 forward_loss_rate_ * kuint64max > simple_random_.RandUint64();
224 // Handle correlated loss.
225 if (!sent_packets_.empty() &&
226 !sent_packets_.back().ack_time.IsInitialized() &&
227 loss_correlation_ * kuint64max > simple_random_.RandUint64()) {
228 packet_lost = true;
229 }
230
231 QuicTime ack_time = clock_->Now().Add(rtt_);
232 // If the number of bytes in flight are less than the bdp, there's
233 // no buffering delay. Bytes lost from the buffer are not counted.
234 QuicByteCount bdp = bandwidth_.ToBytesPerPeriod(rtt_);
235 if (sent_packets_.size() * kPacketSize > bdp) {
236 QuicByteCount qsize = sent_packets_.size() * kPacketSize - bdp;
237 ack_time = ack_time.Add(bandwidth_.TransferTime(qsize));
238 }
239 // If the packet is lost, give it an ack time of Zero.
240 sent_packets_.push_back(SentPacket(
241 next_sent_, clock_->Now(), packet_lost ? QuicTime::Zero() : ack_time));
242 }
243 ++next_sent_;
244 bytes_in_flight_ += kPacketSize;
245 }
246
247 void SendAlgorithmSimulator::RecordStats() {
248 QuicByteCount cwnd = send_algorithm_->GetCongestionWindow();
249 max_cwnd_ = max(max_cwnd_, cwnd);
250 min_cwnd_ = min(min_cwnd_, cwnd);
251 if (last_cwnd_ > cwnd) {
252 max_cwnd_drop_ = max(max_cwnd_drop_, last_cwnd_ - cwnd);
253 }
254 last_cwnd_ = cwnd;
255 }
256
257 // Advance the time by |delta| without sending anything.
258 void SendAlgorithmSimulator::AdvanceTime(QuicTime::Delta delta) {
259 clock_->AdvanceTime(delta);
260 }
261
262 // Elapsed time from the start of the connection.
263 QuicTime SendAlgorithmSimulator::ElapsedTime() {
264 return clock_->Now();
265 }
266
267 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698