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_bitrate_ramp_up.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/basictypes.h"
     10 #include "base/logging.h"
     11 #include "net/quic/congestion_control/cube_root.h"
     12 #include "net/quic/quic_protocol.h"
     13 
     14 namespace {
     15 // The following constants are in 2^10 fractions of a second instead of ms to
     16 // allow a 10 shift right to divide.
     17 const int kCubeScale = 40;  // 1024*1024^3 (first 1024 is from 0.100^3)
     18                             // where 0.100 is 100 ms which is the scaling
     19                             // round trip time.
     20 // TODO(pwestin): Tuning parameter, currently close to TCP cubic at 100ms RTT.
     21 const int kPacedCubeScale = 6000;
     22 const uint64 kCubeFactor = (GG_UINT64_C(1) << kCubeScale) / kPacedCubeScale;
     23 }  // namespace
     24 
     25 namespace net {
     26 
     27 InterArrivalBitrateRampUp::InterArrivalBitrateRampUp(const QuicClock* clock)
     28     : clock_(clock),
     29       current_rate_(QuicBandwidth::Zero()),
     30       channel_estimate_(QuicBandwidth::Zero()),
     31       available_channel_estimate_(QuicBandwidth::Zero()),
     32       halfway_point_(QuicBandwidth::Zero()),
     33       epoch_(QuicTime::Zero()),
     34       last_update_time_(QuicTime::Zero()) {
     35 }
     36 
     37 void InterArrivalBitrateRampUp::Reset(QuicBandwidth new_rate,
     38                                       QuicBandwidth available_channel_estimate,
     39                                       QuicBandwidth channel_estimate) {
     40   epoch_ = clock_->ApproximateNow();
     41   last_update_time_ = epoch_;
     42   available_channel_estimate_ = std::max(new_rate, available_channel_estimate);
     43   channel_estimate_ = std::max(channel_estimate, available_channel_estimate_);
     44 
     45   halfway_point_ = available_channel_estimate_.Add(
     46       (channel_estimate_.Subtract(available_channel_estimate_)).Scale(0.5f));
     47 
     48   if (new_rate < available_channel_estimate_) {
     49     time_to_origin_point_ = CalcuateTimeToOriginPoint(
     50         available_channel_estimate_.Subtract(new_rate));
     51   } else if (new_rate >= channel_estimate_) {
     52     time_to_origin_point_ = 0;
     53   } else if (new_rate >= halfway_point_) {
     54     time_to_origin_point_ =
     55         CalcuateTimeToOriginPoint(channel_estimate_.Subtract(new_rate));
     56   } else {
     57     time_to_origin_point_ = CalcuateTimeToOriginPoint(
     58         new_rate.Subtract(available_channel_estimate_));
     59   }
     60   current_rate_ = new_rate;
     61   DVLOG(1) << "Reset; time to origin point:" << time_to_origin_point_;
     62 }
     63 
     64 void InterArrivalBitrateRampUp::UpdateChannelEstimate(
     65     QuicBandwidth channel_estimate) {
     66   if (available_channel_estimate_ > channel_estimate ||
     67       current_rate_ > channel_estimate ||
     68       channel_estimate_ == channel_estimate) {
     69     // Ignore, because one of the following reasons:
     70     // 1) channel estimate is bellow our current available estimate which we
     71     //    value higher that this estimate.
     72     // 2) channel estimate is bellow our current send rate.
     73     // 3) channel estimate has not changed.
     74     return;
     75   }
     76   if (available_channel_estimate_ == halfway_point_ &&
     77       channel_estimate_  == halfway_point_) {
     78     // First time we get a usable channel estimate.
     79     channel_estimate_ = channel_estimate;
     80     halfway_point_ = available_channel_estimate_.Add(
     81         (channel_estimate_.Subtract(available_channel_estimate_).Scale(0.5f)));
     82     DVLOG(1) << "UpdateChannelEstimate; first usable value:"
     83                << channel_estimate.ToKBitsPerSecond() << " Kbits/s";
     84     return;
     85   }
     86   if (current_rate_ < halfway_point_) {
     87     // Update channel estimate without recalculating if we are bellow the
     88     // halfway point.
     89     channel_estimate_ = channel_estimate;
     90     return;
     91   }
     92   // We are between halfway point and our channel_estimate.
     93   epoch_ = clock_->ApproximateNow();
     94   last_update_time_ = epoch_;
     95   channel_estimate_ = channel_estimate;
     96 
     97   time_to_origin_point_ =
     98       CalcuateTimeToOriginPoint(channel_estimate_.Subtract(current_rate_));
     99 
    100   DVLOG(1) << "UpdateChannelEstimate; time to origin point:"
    101              << time_to_origin_point_;
    102 }
    103 
    104 QuicBandwidth InterArrivalBitrateRampUp::GetNewBitrate(
    105     QuicBandwidth sent_bitrate) {
    106   DCHECK(epoch_.IsInitialized());
    107   QuicTime current_time = clock_->ApproximateNow();
    108   // Cubic is "independent" of RTT, the update is limited by the time elapsed.
    109   if (current_time.Subtract(last_update_time_) <= MaxCubicTimeInterval()) {
    110     return current_rate_;
    111   }
    112   QuicTime::Delta time_from_last_update =
    113       current_time.Subtract(last_update_time_);
    114 
    115   last_update_time_ = current_time;
    116 
    117   if (!sent_bitrate.IsZero() &&
    118       sent_bitrate.Add(sent_bitrate) < current_rate_) {
    119     // Don't go up in bitrate when we are not sending.
    120     // We need to update the epoch to reflect this state.
    121     epoch_ = epoch_.Add(time_from_last_update);
    122     DVLOG(1) << "Don't increase; our sent bitrate is:"
    123                << sent_bitrate.ToKBitsPerSecond() << " Kbits/s"
    124                << " current target rate is:"
    125                << current_rate_.ToKBitsPerSecond() << " Kbits/s";
    126     return current_rate_;
    127   }
    128   QuicTime::Delta time_from_epoch = current_time.Subtract(epoch_);
    129 
    130   // Change the time unit from microseconds to 2^10 fractions per second. This
    131   // is done to allow us to use shift as a divide operator.
    132   int64 elapsed_time = (time_from_epoch.ToMicroseconds() << 10) /
    133       kNumMicrosPerSecond;
    134 
    135   int64 offset = time_to_origin_point_ - elapsed_time;
    136   // Note: using int64 since QuicBandwidth can't be negative
    137   int64 delta_pace_kbps = (kPacedCubeScale * offset * offset * offset) >>
    138         kCubeScale;
    139 
    140   bool start_bellow_halfway_point = false;
    141   if (current_rate_ < halfway_point_) {
    142     start_bellow_halfway_point = true;
    143 
    144     // available_channel_estimate_ is the orgin of the cubic function.
    145     QuicBandwidth current_rate = QuicBandwidth::FromBytesPerSecond(
    146         available_channel_estimate_.ToBytesPerSecond() -
    147             (delta_pace_kbps << 10));
    148 
    149     if (start_bellow_halfway_point && current_rate >= halfway_point_) {
    150       // We passed the halfway point, recalculate with new orgin.
    151       epoch_ = clock_->ApproximateNow();
    152       // channel_estimate_ is the new orgin of the cubic function.
    153       if (current_rate >= channel_estimate_) {
    154         time_to_origin_point_ = 0;
    155       } else {
    156         time_to_origin_point_ =
    157             CalcuateTimeToOriginPoint(channel_estimate_.Subtract(current_rate));
    158       }
    159       DVLOG(1) << "Passed the halfway point; time to origin point:"
    160                  << time_to_origin_point_;
    161     }
    162     current_rate_ = current_rate;
    163   } else {
    164     // channel_estimate_ is the orgin of the cubic function.
    165     current_rate_ = QuicBandwidth::FromBytesPerSecond(
    166         channel_estimate_.ToBytesPerSecond() - (delta_pace_kbps << 10));
    167   }
    168   return current_rate_;
    169 }
    170 
    171 uint32 InterArrivalBitrateRampUp::CalcuateTimeToOriginPoint(
    172     QuicBandwidth rate_difference) const {
    173   return CubeRoot::Root(kCubeFactor * rate_difference.ToKBytesPerSecond());
    174 }
    175 
    176 }  // namespace net
    177