root/net/quic/congestion_control/inter_arrival_state_machine.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. last_delay_event_
  2. GetInterArrivalState
  3. IncreaseBitrateDecision
  4. DecreaseBitrateDecision
  5. set_rtt
  6. PacketLossEvent
  7. IncreasingDelayEvent

// 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

/* [<][>][^][v][top][bottom][index][help] */