Home | History | Annotate | Download | only in congestion_control
      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