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
InterArrivalStateMachine(const QuicClock * clock)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
GetInterArrivalState()36 InterArrivalState InterArrivalStateMachine::GetInterArrivalState() {
37 return current_state_;
38 }
39
IncreaseBitrateDecision()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
DecreaseBitrateDecision()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
set_rtt(QuicTime::Delta rtt)127 void InterArrivalStateMachine::set_rtt(QuicTime::Delta rtt) {
128 smoothed_rtt_ = rtt;
129 }
130
PacketLossEvent()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
IncreasingDelayEvent()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