summaryrefslogtreecommitdiff
path: root/chromium/net/quic/congestion_control/inter_arrival_state_machine.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/quic/congestion_control/inter_arrival_state_machine.cc')
-rw-r--r--chromium/net/quic/congestion_control/inter_arrival_state_machine.cc163
1 files changed, 163 insertions, 0 deletions
diff --git a/chromium/net/quic/congestion_control/inter_arrival_state_machine.cc b/chromium/net/quic/congestion_control/inter_arrival_state_machine.cc
new file mode 100644
index 00000000000..7095e60306b
--- /dev/null
+++ b/chromium/net/quic/congestion_control/inter_arrival_state_machine.cc
@@ -0,0 +1,163 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/congestion_control/inter_arrival_state_machine.h"
+
+#include "base/logging.h"
+
+namespace {
+const int kIncreaseEventsBeforeDowngradingState = 5;
+const int kDecreaseEventsBeforeUpgradingState = 2;
+// Note: Can not be higher than kDecreaseEventsBeforeUpgradingState;
+const int kLossEventsBeforeUpgradingState = 2;
+// Timeout old loss and delay events after this time.
+const int kEventTimeoutMs = 10000;
+// A reasonable arbitrary chosen value for initial round trip time.
+const int kInitialRttMs = 80;
+}
+
+namespace net {
+
+InterArrivalStateMachine::InterArrivalStateMachine(const QuicClock* clock)
+ : clock_(clock),
+ current_state_(kInterArrivalStateStable),
+ smoothed_rtt_(QuicTime::Delta::FromMilliseconds(kInitialRttMs)),
+ decrease_event_count_(0),
+ last_decrease_event_(QuicTime::Zero()),
+ increase_event_count_(0),
+ last_increase_event_(QuicTime::Zero()),
+ loss_event_count_(0),
+ last_loss_event_(QuicTime::Zero()),
+ delay_event_count_(0),
+ last_delay_event_(QuicTime::Zero()) {
+}
+
+InterArrivalState InterArrivalStateMachine::GetInterArrivalState() {
+ return current_state_;
+}
+
+void InterArrivalStateMachine::IncreaseBitrateDecision() {
+ // Multiple increase event without packet loss or delay events will drive
+ // state back to stable.
+ QuicTime current_time = clock_->ApproximateNow();
+ if (current_time.Subtract(last_increase_event_) < smoothed_rtt_) {
+ // Less than one RTT have passed; ignore this event.
+ return;
+ }
+ last_increase_event_ = current_time;
+ increase_event_count_++;
+ decrease_event_count_ = 0; // Reset previous decrease events.
+
+ if (increase_event_count_ < kIncreaseEventsBeforeDowngradingState) {
+ // Not enough increase events to change state.
+ return;
+ }
+ increase_event_count_ = 0; // Reset increase events.
+
+ switch (current_state_) {
+ case kInterArrivalStateStable:
+ // Keep this state.
+ break;
+ case kInterArrivalStatePacketLoss:
+ current_state_ = kInterArrivalStateStable;
+ break;
+ case kInterArrivalStateDelay:
+ current_state_ = kInterArrivalStateStable;
+ break;
+ case kInterArrivalStateCompetingFlow:
+ current_state_ = kInterArrivalStateDelay;
+ break;
+ case kInterArrivalStateCompetingTcpFLow:
+ current_state_ = kInterArrivalStateDelay;
+ break;
+ }
+}
+
+void InterArrivalStateMachine::DecreaseBitrateDecision() {
+ DCHECK(kDecreaseEventsBeforeUpgradingState >=
+ kLossEventsBeforeUpgradingState);
+
+ QuicTime current_time = clock_->ApproximateNow();
+ if (current_time.Subtract(last_decrease_event_) < smoothed_rtt_) {
+ // Less than one RTT have passed; ignore this event.
+ return;
+ }
+ last_decrease_event_ = current_time;
+ decrease_event_count_++;
+ increase_event_count_ = 0; // Reset previous increase events.
+ if (decrease_event_count_ < kDecreaseEventsBeforeUpgradingState) {
+ // Not enough decrease events to change state.
+ return;
+ }
+ decrease_event_count_ = 0; // Reset decrease events.
+
+ switch (current_state_) {
+ case kInterArrivalStateStable:
+ if (delay_event_count_ == 0 && loss_event_count_ > 0) {
+ // No recent delay events; only packet loss events.
+ current_state_ = kInterArrivalStatePacketLoss;
+ } else {
+ current_state_ = kInterArrivalStateDelay;
+ }
+ break;
+ case kInterArrivalStatePacketLoss:
+ // Keep this state.
+ break;
+ case kInterArrivalStateDelay:
+ if (loss_event_count_ >= kLossEventsBeforeUpgradingState) {
+ // We have packet loss events. Assume fighting with TCP.
+ current_state_ = kInterArrivalStateCompetingTcpFLow;
+ } else {
+ current_state_ = kInterArrivalStateCompetingFlow;
+ }
+ break;
+ case kInterArrivalStateCompetingFlow:
+ if (loss_event_count_ >= kLossEventsBeforeUpgradingState) {
+ // We have packet loss events. Assume fighting with TCP.
+ current_state_ = kInterArrivalStateCompetingTcpFLow;
+ }
+ break;
+ case kInterArrivalStateCompetingTcpFLow:
+ // Keep this state.
+ break;
+ }
+}
+
+void InterArrivalStateMachine::set_rtt(QuicTime::Delta rtt) {
+ smoothed_rtt_ = rtt;
+}
+
+bool InterArrivalStateMachine::PacketLossEvent() {
+ QuicTime current_time = clock_->ApproximateNow();
+ if (current_time.Subtract(last_loss_event_) < smoothed_rtt_) {
+ // Less than one RTT have passed; ignore this event.
+ return false;
+ }
+ last_loss_event_ = current_time;
+ loss_event_count_++;
+ if (current_time.Subtract(last_delay_event_) >
+ QuicTime::Delta::FromMilliseconds(kEventTimeoutMs)) {
+ // Delay event have timed out.
+ delay_event_count_ = 0;
+ }
+ return true;
+}
+
+bool InterArrivalStateMachine::IncreasingDelayEvent() {
+ QuicTime current_time = clock_->ApproximateNow();
+ if (current_time.Subtract(last_delay_event_) < smoothed_rtt_) {
+ // Less than one RTT have passed; ignore this event.
+ return false;
+ }
+ last_delay_event_ = current_time;
+ delay_event_count_++;
+ if (current_time.Subtract(last_loss_event_) >
+ QuicTime::Delta::FromMilliseconds(kEventTimeoutMs)) {
+ // Loss event have timed out.
+ loss_event_count_ = 0;
+ }
+ return true;
+}
+
+} // namespace net