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_state_machine.h" 6 7 #include "base/logging.h" 8 9 namespace { 10 const int kIncreaseEventsBeforeDowngradingState = 5; 11 const int kDecreaseEventsBeforeUpgradingState = 2; 12 // Note: Can not be higher than kDecreaseEventsBeforeUpgradingState; 13 const int kLossEventsBeforeUpgradingState = 2; 14 // Timeout old loss and delay events after this time. 15 const int kEventTimeoutMs = 10000; 16 // A reasonable arbitrary chosen value for initial round trip time. 17 const int kInitialRttMs = 80; 18 } 19 20 namespace net { 21 22 InterArrivalStateMachine::InterArrivalStateMachine(const QuicClock* clock) 23 : clock_(clock), 24 current_state_(kInterArrivalStateStable), 25 smoothed_rtt_(QuicTime::Delta::FromMilliseconds(kInitialRttMs)), 26 decrease_event_count_(0), 27 last_decrease_event_(QuicTime::Zero()), 28 increase_event_count_(0), 29 last_increase_event_(QuicTime::Zero()), 30 loss_event_count_(0), 31 last_loss_event_(QuicTime::Zero()), 32 delay_event_count_(0), 33 last_delay_event_(QuicTime::Zero()) { 34 } 35 36 InterArrivalState InterArrivalStateMachine::GetInterArrivalState() { 37 return current_state_; 38 } 39 40 void InterArrivalStateMachine::IncreaseBitrateDecision() { 41 // Multiple increase event without packet loss or delay events will drive 42 // state back to stable. 43 QuicTime current_time = clock_->ApproximateNow(); 44 if (current_time.Subtract(last_increase_event_) < smoothed_rtt_) { 45 // Less than one RTT have passed; ignore this event. 46 return; 47 } 48 last_increase_event_ = current_time; 49 increase_event_count_++; 50 decrease_event_count_ = 0; // Reset previous decrease events. 51 52 if (increase_event_count_ < kIncreaseEventsBeforeDowngradingState) { 53 // Not enough increase events to change state. 54 return; 55 } 56 increase_event_count_ = 0; // Reset increase events. 57 58 switch (current_state_) { 59 case kInterArrivalStateStable: 60 // Keep this state. 61 break; 62 case kInterArrivalStatePacketLoss: 63 current_state_ = kInterArrivalStateStable; 64 break; 65 case kInterArrivalStateDelay: 66 current_state_ = kInterArrivalStateStable; 67 break; 68 case kInterArrivalStateCompetingFlow: 69 current_state_ = kInterArrivalStateDelay; 70 break; 71 case kInterArrivalStateCompetingTcpFLow: 72 current_state_ = kInterArrivalStateDelay; 73 break; 74 } 75 } 76 77 void InterArrivalStateMachine::DecreaseBitrateDecision() { 78 DCHECK(kDecreaseEventsBeforeUpgradingState >= 79 kLossEventsBeforeUpgradingState); 80 81 QuicTime current_time = clock_->ApproximateNow(); 82 if (current_time.Subtract(last_decrease_event_) < smoothed_rtt_) { 83 // Less than one RTT have passed; ignore this event. 84 return; 85 } 86 last_decrease_event_ = current_time; 87 decrease_event_count_++; 88 increase_event_count_ = 0; // Reset previous increase events. 89 if (decrease_event_count_ < kDecreaseEventsBeforeUpgradingState) { 90 // Not enough decrease events to change state. 91 return; 92 } 93 decrease_event_count_ = 0; // Reset decrease events. 94 95 switch (current_state_) { 96 case kInterArrivalStateStable: 97 if (delay_event_count_ == 0 && loss_event_count_ > 0) { 98 // No recent delay events; only packet loss events. 99 current_state_ = kInterArrivalStatePacketLoss; 100 } else { 101 current_state_ = kInterArrivalStateDelay; 102 } 103 break; 104 case kInterArrivalStatePacketLoss: 105 // Keep this state. 106 break; 107 case kInterArrivalStateDelay: 108 if (loss_event_count_ >= kLossEventsBeforeUpgradingState) { 109 // We have packet loss events. Assume fighting with TCP. 110 current_state_ = kInterArrivalStateCompetingTcpFLow; 111 } else { 112 current_state_ = kInterArrivalStateCompetingFlow; 113 } 114 break; 115 case kInterArrivalStateCompetingFlow: 116 if (loss_event_count_ >= kLossEventsBeforeUpgradingState) { 117 // We have packet loss events. Assume fighting with TCP. 118 current_state_ = kInterArrivalStateCompetingTcpFLow; 119 } 120 break; 121 case kInterArrivalStateCompetingTcpFLow: 122 // Keep this state. 123 break; 124 } 125 } 126 127 void InterArrivalStateMachine::set_rtt(QuicTime::Delta rtt) { 128 smoothed_rtt_ = rtt; 129 } 130 131 bool InterArrivalStateMachine::PacketLossEvent() { 132 QuicTime current_time = clock_->ApproximateNow(); 133 if (current_time.Subtract(last_loss_event_) < smoothed_rtt_) { 134 // Less than one RTT have passed; ignore this event. 135 return false; 136 } 137 last_loss_event_ = current_time; 138 loss_event_count_++; 139 if (current_time.Subtract(last_delay_event_) > 140 QuicTime::Delta::FromMilliseconds(kEventTimeoutMs)) { 141 // Delay event have timed out. 142 delay_event_count_ = 0; 143 } 144 return true; 145 } 146 147 bool InterArrivalStateMachine::IncreasingDelayEvent() { 148 QuicTime current_time = clock_->ApproximateNow(); 149 if (current_time.Subtract(last_delay_event_) < smoothed_rtt_) { 150 // Less than one RTT have passed; ignore this event. 151 return false; 152 } 153 last_delay_event_ = current_time; 154 delay_event_count_++; 155 if (current_time.Subtract(last_loss_event_) > 156 QuicTime::Delta::FromMilliseconds(kEventTimeoutMs)) { 157 // Loss event have timed out. 158 loss_event_count_ = 0; 159 } 160 return true; 161 } 162 163 } // namespace net 164