1 // Copyright (c) 2013 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/inter_arrival_sender.h"
6
7 namespace net {
8
9 namespace {
10 const int64 kProbeBitrateKBytesPerSecond = 1200; // 9.6 Mbit/s
11 const float kPacketLossBitrateReduction = 0.7f;
12 const float kUncertainSafetyMargin = 0.7f;
13 const float kMaxBitrateReduction = 0.9f;
14 const float kMinBitrateReduction = 0.05f;
15 const uint64 kMinBitrateKbit = 10;
16 const int kInitialRttMs = 60; // At a typical RTT 60 ms.
17 const float kAlpha = 0.125f;
18 const float kOneMinusAlpha = 1 - kAlpha;
19
20 static const int kBitrateSmoothingPeriodMs = 1000;
21 static const int kMinBitrateSmoothingPeriodMs = 500;
22
23 } // namespace
24
InterArrivalSender(const QuicClock * clock)25 InterArrivalSender::InterArrivalSender(const QuicClock* clock)
26 : probing_(true),
27 max_segment_size_(kDefaultMaxPacketSize),
28 current_bandwidth_(QuicBandwidth::Zero()),
29 smoothed_rtt_(QuicTime::Delta::Zero()),
30 channel_estimator_(new ChannelEstimator()),
31 bitrate_ramp_up_(new InterArrivalBitrateRampUp(clock)),
32 overuse_detector_(new InterArrivalOveruseDetector()),
33 probe_(new InterArrivalProbe(max_segment_size_)),
34 state_machine_(new InterArrivalStateMachine(clock)),
35 paced_sender_(new PacedSender(QuicBandwidth::FromKBytesPerSecond(
36 kProbeBitrateKBytesPerSecond), max_segment_size_)),
37 accumulated_number_of_lost_packets_(0),
38 bandwidth_usage_state_(kBandwidthSteady),
39 back_down_time_(QuicTime::Zero()),
40 back_down_bandwidth_(QuicBandwidth::Zero()),
41 back_down_congestion_delay_(QuicTime::Delta::Zero()) {
42 }
43
~InterArrivalSender()44 InterArrivalSender::~InterArrivalSender() {
45 }
46
SetFromConfig(const QuicConfig & config,bool is_server)47 void InterArrivalSender::SetFromConfig(const QuicConfig& config,
48 bool is_server) {
49 }
50
SetMaxPacketSize(QuicByteCount max_packet_size)51 void InterArrivalSender::SetMaxPacketSize(QuicByteCount max_packet_size) {
52 max_segment_size_ = max_packet_size;
53 paced_sender_->set_max_segment_size(max_segment_size_);
54 probe_->set_max_segment_size(max_segment_size_);
55 }
56
57 // TODO(pwestin): this is really inefficient (4% CPU on the GFE loadtest).
58 // static
CalculateSentBandwidth(const SendAlgorithmInterface::SentPacketsMap & sent_packets_map,QuicTime feedback_receive_time)59 QuicBandwidth InterArrivalSender::CalculateSentBandwidth(
60 const SendAlgorithmInterface::SentPacketsMap& sent_packets_map,
61 QuicTime feedback_receive_time) {
62 const QuicTime::Delta kBitrateSmoothingPeriod =
63 QuicTime::Delta::FromMilliseconds(kBitrateSmoothingPeriodMs);
64 const QuicTime::Delta kMinBitrateSmoothingPeriod =
65 QuicTime::Delta::FromMilliseconds(kMinBitrateSmoothingPeriodMs);
66
67 QuicByteCount sum_bytes_sent = 0;
68
69 // Sum packet from new until they are kBitrateSmoothingPeriod old.
70 SendAlgorithmInterface::SentPacketsMap::const_reverse_iterator history_rit =
71 sent_packets_map.rbegin();
72
73 QuicTime::Delta max_diff = QuicTime::Delta::Zero();
74 for (; history_rit != sent_packets_map.rend(); ++history_rit) {
75 QuicTime::Delta diff =
76 feedback_receive_time.Subtract(history_rit->second->send_timestamp());
77 if (diff > kBitrateSmoothingPeriod) {
78 break;
79 }
80 sum_bytes_sent += history_rit->second->bytes_sent();
81 max_diff = diff;
82 }
83 if (max_diff < kMinBitrateSmoothingPeriod) {
84 // No estimate.
85 return QuicBandwidth::Zero();
86 }
87 return QuicBandwidth::FromBytesAndTimeDelta(sum_bytes_sent, max_diff);
88 }
89
OnIncomingQuicCongestionFeedbackFrame(const QuicCongestionFeedbackFrame & feedback,QuicTime feedback_receive_time,const SentPacketsMap & sent_packets)90 void InterArrivalSender::OnIncomingQuicCongestionFeedbackFrame(
91 const QuicCongestionFeedbackFrame& feedback,
92 QuicTime feedback_receive_time,
93 const SentPacketsMap& sent_packets) {
94 DCHECK(feedback.type == kInterArrival);
95
96 if (feedback.type != kInterArrival) {
97 return;
98 }
99
100 QuicBandwidth sent_bandwidth = CalculateSentBandwidth(sent_packets,
101 feedback_receive_time);
102
103 TimeMap::const_iterator received_it;
104 for (received_it = feedback.inter_arrival.received_packet_times.begin();
105 received_it != feedback.inter_arrival.received_packet_times.end();
106 ++received_it) {
107 QuicPacketSequenceNumber sequence_number = received_it->first;
108
109 SentPacketsMap::const_iterator sent_it = sent_packets.find(sequence_number);
110 if (sent_it == sent_packets.end()) {
111 // Too old data; ignore and move forward.
112 DVLOG(1) << "Too old feedback move forward, sequence_number:"
113 << sequence_number;
114 continue;
115 }
116 QuicTime time_received = received_it->second;
117 QuicTime time_sent = sent_it->second->send_timestamp();
118 QuicByteCount bytes_sent = sent_it->second->bytes_sent();
119
120 channel_estimator_->OnAcknowledgedPacket(
121 sequence_number, bytes_sent, time_sent, time_received);
122 if (probing_) {
123 probe_->OnIncomingFeedback(
124 sequence_number, bytes_sent, time_sent, time_received);
125 } else {
126 bool last_of_send_time = false;
127 SentPacketsMap::const_iterator next_sent_it = ++sent_it;
128 if (next_sent_it == sent_packets.end()) {
129 // No more sent packets; hence this must be the last.
130 last_of_send_time = true;
131 } else {
132 if (time_sent != next_sent_it->second->send_timestamp()) {
133 // Next sent packet have a different send time.
134 last_of_send_time = true;
135 }
136 }
137 overuse_detector_->OnAcknowledgedPacket(
138 sequence_number, time_sent, last_of_send_time, time_received);
139 }
140 }
141 if (probing_) {
142 probing_ = ProbingPhase(feedback_receive_time);
143 return;
144 }
145
146 bool packet_loss_event = false;
147 if (accumulated_number_of_lost_packets_ !=
148 feedback.inter_arrival.accumulated_number_of_lost_packets) {
149 accumulated_number_of_lost_packets_ =
150 feedback.inter_arrival.accumulated_number_of_lost_packets;
151 packet_loss_event = true;
152 }
153 InterArrivalState state = state_machine_->GetInterArrivalState();
154
155 if (state == kInterArrivalStatePacketLoss ||
156 state == kInterArrivalStateCompetingTcpFLow) {
157 if (packet_loss_event) {
158 if (!state_machine_->PacketLossEvent()) {
159 // Less than one RTT since last PacketLossEvent.
160 return;
161 }
162 EstimateBandwidthAfterLossEvent(feedback_receive_time);
163 } else {
164 EstimateNewBandwidth(feedback_receive_time, sent_bandwidth);
165 }
166 return;
167 }
168 EstimateDelayBandwidth(feedback_receive_time, sent_bandwidth);
169 }
170
ProbingPhase(QuicTime feedback_receive_time)171 bool InterArrivalSender::ProbingPhase(QuicTime feedback_receive_time) {
172 QuicBandwidth available_channel_estimate = QuicBandwidth::Zero();
173 if (!probe_->GetEstimate(&available_channel_estimate)) {
174 // Continue probing phase.
175 return true;
176 }
177 QuicBandwidth channel_estimate = QuicBandwidth::Zero();
178 ChannelEstimateState channel_estimator_state =
179 channel_estimator_->GetChannelEstimate(&channel_estimate);
180
181 QuicBandwidth new_rate =
182 available_channel_estimate.Scale(kUncertainSafetyMargin);
183
184 switch (channel_estimator_state) {
185 case kChannelEstimateUnknown:
186 channel_estimate = available_channel_estimate;
187 break;
188 case kChannelEstimateUncertain:
189 channel_estimate = channel_estimate.Scale(kUncertainSafetyMargin);
190 break;
191 case kChannelEstimateGood:
192 // Do nothing.
193 break;
194 }
195 new_rate = std::max(new_rate,
196 QuicBandwidth::FromKBitsPerSecond(kMinBitrateKbit));
197
198 bitrate_ramp_up_->Reset(new_rate, available_channel_estimate,
199 channel_estimate);
200
201 current_bandwidth_ = new_rate;
202 paced_sender_->UpdateBandwidthEstimate(feedback_receive_time, new_rate);
203 DVLOG(1) << "Probe result; new rate:"
204 << new_rate.ToKBitsPerSecond() << " Kbits/s "
205 << " available estimate:"
206 << available_channel_estimate.ToKBitsPerSecond() << " Kbits/s "
207 << " channel estimate:"
208 << channel_estimate.ToKBitsPerSecond() << " Kbits/s ";
209 return false;
210 }
211
OnPacketAcked(QuicPacketSequenceNumber,QuicByteCount acked_bytes,QuicTime::Delta rtt)212 void InterArrivalSender::OnPacketAcked(
213 QuicPacketSequenceNumber /*acked_sequence_number*/,
214 QuicByteCount acked_bytes,
215 QuicTime::Delta rtt) {
216 // RTT can't be negative.
217 DCHECK_LE(0, rtt.ToMicroseconds());
218
219 if (probing_) {
220 probe_->OnAcknowledgedPacket(acked_bytes);
221 }
222
223 if (rtt.IsInfinite()) {
224 return;
225 }
226
227 if (smoothed_rtt_.IsZero()) {
228 smoothed_rtt_ = rtt;
229 } else {
230 smoothed_rtt_ = QuicTime::Delta::FromMicroseconds(
231 kOneMinusAlpha * smoothed_rtt_.ToMicroseconds() +
232 kAlpha * rtt.ToMicroseconds());
233 }
234 state_machine_->set_rtt(smoothed_rtt_);
235 }
236
OnPacketLost(QuicPacketSequenceNumber,QuicTime ack_receive_time)237 void InterArrivalSender::OnPacketLost(
238 QuicPacketSequenceNumber /*sequence_number*/,
239 QuicTime ack_receive_time) {
240 // Packet loss was reported.
241 if (!probing_) {
242 if (!state_machine_->PacketLossEvent()) {
243 // Less than one RTT since last PacketLossEvent.
244 return;
245 }
246 // Calculate new pace rate.
247 EstimateBandwidthAfterLossEvent(ack_receive_time);
248 }
249 }
250
OnPacketSent(QuicTime sent_time,QuicPacketSequenceNumber sequence_number,QuicByteCount bytes,TransmissionType,HasRetransmittableData)251 bool InterArrivalSender::OnPacketSent(
252 QuicTime sent_time,
253 QuicPacketSequenceNumber sequence_number,
254 QuicByteCount bytes,
255 TransmissionType /*transmission_type*/,
256 HasRetransmittableData /*has_retransmittable_data*/) {
257 if (probing_) {
258 probe_->OnPacketSent(bytes);
259 }
260 paced_sender_->OnPacketSent(sent_time, bytes);
261 return true;
262 }
263
OnRetransmissionTimeout()264 void InterArrivalSender::OnRetransmissionTimeout() {
265 // TODO(ianswett): Decrease the available bandwidth.
266 }
267
OnPacketAbandoned(QuicPacketSequenceNumber,QuicByteCount abandoned_bytes)268 void InterArrivalSender::OnPacketAbandoned(
269 QuicPacketSequenceNumber /*sequence_number*/,
270 QuicByteCount abandoned_bytes) {
271 // TODO(pwestin): use for out outer_congestion_window_ logic.
272 if (probing_) {
273 probe_->OnAcknowledgedPacket(abandoned_bytes);
274 }
275 }
276
TimeUntilSend(QuicTime now,TransmissionType,HasRetransmittableData has_retransmittable_data,IsHandshake)277 QuicTime::Delta InterArrivalSender::TimeUntilSend(
278 QuicTime now,
279 TransmissionType /*transmission_type*/,
280 HasRetransmittableData has_retransmittable_data,
281 IsHandshake /*handshake*/) {
282 // TODO(pwestin): implement outer_congestion_window_ logic.
283 QuicTime::Delta outer_window = QuicTime::Delta::Zero();
284
285 if (probing_) {
286 if (has_retransmittable_data == HAS_RETRANSMITTABLE_DATA &&
287 probe_->GetAvailableCongestionWindow() == 0) {
288 outer_window = QuicTime::Delta::Infinite();
289 }
290 }
291 return paced_sender_->TimeUntilSend(now, outer_window);
292 }
293
EstimateDelayBandwidth(QuicTime feedback_receive_time,QuicBandwidth sent_bandwidth)294 void InterArrivalSender::EstimateDelayBandwidth(QuicTime feedback_receive_time,
295 QuicBandwidth sent_bandwidth) {
296 QuicTime::Delta estimated_congestion_delay = QuicTime::Delta::Zero();
297 BandwidthUsage new_bandwidth_usage_state =
298 overuse_detector_->GetState(&estimated_congestion_delay);
299
300 switch (new_bandwidth_usage_state) {
301 case kBandwidthDraining:
302 case kBandwidthUnderUsing:
303 // Hold our current bitrate.
304 break;
305 case kBandwidthOverUsing:
306 if (!state_machine_->IncreasingDelayEvent()) {
307 // Less than one RTT since last IncreasingDelayEvent.
308 return;
309 }
310 EstimateBandwidthAfterDelayEvent(feedback_receive_time,
311 estimated_congestion_delay);
312 break;
313 case kBandwidthSteady:
314 // Calculate new pace rate.
315 if (bandwidth_usage_state_ == kBandwidthDraining ||
316 bandwidth_usage_state_ == kBandwidthOverUsing) {
317 EstimateNewBandwidthAfterDraining(feedback_receive_time,
318 estimated_congestion_delay);
319 } else {
320 EstimateNewBandwidth(feedback_receive_time, sent_bandwidth);
321 }
322 break;
323 }
324 bandwidth_usage_state_ = new_bandwidth_usage_state;
325 }
326
BandwidthEstimate() const327 QuicBandwidth InterArrivalSender::BandwidthEstimate() const {
328 return current_bandwidth_;
329 }
330
SmoothedRtt() const331 QuicTime::Delta InterArrivalSender::SmoothedRtt() const {
332 if (smoothed_rtt_.IsZero()) {
333 return QuicTime::Delta::FromMilliseconds(kInitialRttMs);
334 }
335 return smoothed_rtt_;
336 }
337
RetransmissionDelay() const338 QuicTime::Delta InterArrivalSender::RetransmissionDelay() const {
339 // TODO(pwestin): Calculate and return retransmission delay.
340 // Use 2 * the smoothed RTT for now.
341 return smoothed_rtt_.Add(smoothed_rtt_);
342 }
343
GetCongestionWindow() const344 QuicByteCount InterArrivalSender::GetCongestionWindow() const {
345 return 0;
346 }
347
EstimateNewBandwidth(QuicTime feedback_receive_time,QuicBandwidth sent_bandwidth)348 void InterArrivalSender::EstimateNewBandwidth(QuicTime feedback_receive_time,
349 QuicBandwidth sent_bandwidth) {
350 QuicBandwidth new_bandwidth = bitrate_ramp_up_->GetNewBitrate(sent_bandwidth);
351 if (current_bandwidth_ == new_bandwidth) {
352 return;
353 }
354 current_bandwidth_ = new_bandwidth;
355 state_machine_->IncreaseBitrateDecision();
356
357 QuicBandwidth channel_estimate = QuicBandwidth::Zero();
358 ChannelEstimateState channel_estimator_state =
359 channel_estimator_->GetChannelEstimate(&channel_estimate);
360
361 if (channel_estimator_state == kChannelEstimateGood) {
362 bitrate_ramp_up_->UpdateChannelEstimate(channel_estimate);
363 }
364 paced_sender_->UpdateBandwidthEstimate(feedback_receive_time,
365 current_bandwidth_);
366 DVLOG(1) << "New bandwidth estimate in steady state:"
367 << current_bandwidth_.ToKBitsPerSecond()
368 << " Kbits/s";
369 }
370
371 // Did we drain the network buffers in our expected pace?
EstimateNewBandwidthAfterDraining(QuicTime feedback_receive_time,QuicTime::Delta estimated_congestion_delay)372 void InterArrivalSender::EstimateNewBandwidthAfterDraining(
373 QuicTime feedback_receive_time,
374 QuicTime::Delta estimated_congestion_delay) {
375 if (current_bandwidth_ > back_down_bandwidth_) {
376 // Do nothing, our current bandwidth is higher than our bandwidth at the
377 // previous back down.
378 DVLOG(1) << "Current bandwidth estimate is higher than before draining";
379 return;
380 }
381 if (estimated_congestion_delay >= back_down_congestion_delay_) {
382 // Do nothing, our estimated delay have increased.
383 DVLOG(1) << "Current delay estimate is higher than before draining";
384 return;
385 }
386 DCHECK(back_down_time_.IsInitialized());
387 QuicTime::Delta buffer_reduction =
388 back_down_congestion_delay_.Subtract(estimated_congestion_delay);
389 QuicTime::Delta elapsed_time =
390 feedback_receive_time.Subtract(back_down_time_).Subtract(SmoothedRtt());
391
392 QuicBandwidth new_estimate = QuicBandwidth::Zero();
393 if (buffer_reduction >= elapsed_time) {
394 // We have drained more than the elapsed time... go back to our old rate.
395 new_estimate = back_down_bandwidth_;
396 } else {
397 float fraction_of_rate =
398 static_cast<float>(buffer_reduction.ToMicroseconds()) /
399 elapsed_time.ToMicroseconds(); // < 1.0
400
401 QuicBandwidth draining_rate = back_down_bandwidth_.Scale(fraction_of_rate);
402 QuicBandwidth max_estimated_draining_rate =
403 back_down_bandwidth_.Subtract(current_bandwidth_);
404 if (draining_rate > max_estimated_draining_rate) {
405 // We drained faster than our old send rate, go back to our old rate.
406 new_estimate = back_down_bandwidth_;
407 } else {
408 // Use our drain rate and our kMinBitrateReduction to go to our
409 // new estimate.
410 new_estimate = std::max(current_bandwidth_,
411 current_bandwidth_.Add(draining_rate).Scale(
412 1.0f - kMinBitrateReduction));
413 DVLOG(1) << "Draining calculation; current rate:"
414 << current_bandwidth_.ToKBitsPerSecond() << " Kbits/s "
415 << "draining rate:"
416 << draining_rate.ToKBitsPerSecond() << " Kbits/s "
417 << "new estimate:"
418 << new_estimate.ToKBitsPerSecond() << " Kbits/s "
419 << " buffer reduction:"
420 << buffer_reduction.ToMicroseconds() << " us "
421 << " elapsed time:"
422 << elapsed_time.ToMicroseconds() << " us ";
423 }
424 }
425 if (new_estimate == current_bandwidth_) {
426 return;
427 }
428
429 QuicBandwidth channel_estimate = QuicBandwidth::Zero();
430 ChannelEstimateState channel_estimator_state =
431 channel_estimator_->GetChannelEstimate(&channel_estimate);
432
433 // TODO(pwestin): we need to analyze channel_estimate too.
434 switch (channel_estimator_state) {
435 case kChannelEstimateUnknown:
436 channel_estimate = current_bandwidth_;
437 break;
438 case kChannelEstimateUncertain:
439 channel_estimate = channel_estimate.Scale(kUncertainSafetyMargin);
440 break;
441 case kChannelEstimateGood:
442 // Do nothing, estimate is accurate.
443 break;
444 }
445 bitrate_ramp_up_->Reset(new_estimate, back_down_bandwidth_, channel_estimate);
446 state_machine_->IncreaseBitrateDecision();
447 paced_sender_->UpdateBandwidthEstimate(feedback_receive_time, new_estimate);
448 current_bandwidth_ = new_estimate;
449 DVLOG(1) << "New bandwidth estimate after draining:"
450 << new_estimate.ToKBitsPerSecond() << " Kbits/s";
451 }
452
EstimateBandwidthAfterDelayEvent(QuicTime feedback_receive_time,QuicTime::Delta estimated_congestion_delay)453 void InterArrivalSender::EstimateBandwidthAfterDelayEvent(
454 QuicTime feedback_receive_time,
455 QuicTime::Delta estimated_congestion_delay) {
456 QuicByteCount estimated_byte_buildup =
457 current_bandwidth_.ToBytesPerPeriod(estimated_congestion_delay);
458
459 // To drain all build up buffer within one RTT we need to reduce the
460 // bitrate with the following.
461 // TODO(pwestin): this is a crude first implementation.
462 int64 draining_rate_per_rtt = (estimated_byte_buildup *
463 kNumMicrosPerSecond) / SmoothedRtt().ToMicroseconds();
464
465 float decrease_factor =
466 draining_rate_per_rtt / current_bandwidth_.ToBytesPerSecond();
467
468 decrease_factor = std::max(decrease_factor, kMinBitrateReduction);
469 decrease_factor = std::min(decrease_factor, kMaxBitrateReduction);
470 back_down_congestion_delay_ = estimated_congestion_delay;
471 QuicBandwidth new_target_bitrate =
472 current_bandwidth_.Scale(1.0f - decrease_factor);
473
474 // While in delay sensing mode send at least one packet per RTT.
475 QuicBandwidth min_delay_bitrate =
476 QuicBandwidth::FromBytesAndTimeDelta(max_segment_size_, SmoothedRtt());
477 new_target_bitrate = std::max(new_target_bitrate, min_delay_bitrate);
478
479 ResetCurrentBandwidth(feedback_receive_time, new_target_bitrate);
480
481 DVLOG(1) << "New bandwidth estimate after delay event:"
482 << current_bandwidth_.ToKBitsPerSecond()
483 << " Kbits/s min delay bitrate:"
484 << min_delay_bitrate.ToKBitsPerSecond()
485 << " Kbits/s RTT:"
486 << SmoothedRtt().ToMicroseconds()
487 << " us";
488 }
489
EstimateBandwidthAfterLossEvent(QuicTime feedback_receive_time)490 void InterArrivalSender::EstimateBandwidthAfterLossEvent(
491 QuicTime feedback_receive_time) {
492 ResetCurrentBandwidth(feedback_receive_time,
493 current_bandwidth_.Scale(kPacketLossBitrateReduction));
494 DVLOG(1) << "New bandwidth estimate after loss event:"
495 << current_bandwidth_.ToKBitsPerSecond()
496 << " Kbits/s";
497 }
498
ResetCurrentBandwidth(QuicTime feedback_receive_time,QuicBandwidth new_rate)499 void InterArrivalSender::ResetCurrentBandwidth(QuicTime feedback_receive_time,
500 QuicBandwidth new_rate) {
501 new_rate = std::max(new_rate,
502 QuicBandwidth::FromKBitsPerSecond(kMinBitrateKbit));
503 QuicBandwidth channel_estimate = QuicBandwidth::Zero();
504 ChannelEstimateState channel_estimator_state =
505 channel_estimator_->GetChannelEstimate(&channel_estimate);
506
507 switch (channel_estimator_state) {
508 case kChannelEstimateUnknown:
509 channel_estimate = current_bandwidth_;
510 break;
511 case kChannelEstimateUncertain:
512 channel_estimate = channel_estimate.Scale(kUncertainSafetyMargin);
513 break;
514 case kChannelEstimateGood:
515 // Do nothing.
516 break;
517 }
518 back_down_time_ = feedback_receive_time;
519 back_down_bandwidth_ = current_bandwidth_;
520 bitrate_ramp_up_->Reset(new_rate, current_bandwidth_, channel_estimate);
521 if (new_rate != current_bandwidth_) {
522 current_bandwidth_ = new_rate;
523 paced_sender_->UpdateBandwidthEstimate(feedback_receive_time,
524 current_bandwidth_);
525 state_machine_->DecreaseBitrateDecision();
526 }
527 }
528
529 } // namespace net
530