mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-19 08:37:54 +01:00

This prepares for making the BBR implementation more identical to the implementation in Quic, this is to ensure that results are comparable. Bug: webrtc:8415 Change-Id: Ic2dc4394dc9923e5109ffa5f146c23b527f0c395 Reviewed-on: https://webrtc-review.googlesource.com/76582 Commit-Queue: Sebastian Jansson <srte@webrtc.org> Reviewed-by: Björn Terelius <terelius@webrtc.org> Cr-Commit-Position: refs/heads/master@{#23262}
204 lines
7.6 KiB
C++
204 lines
7.6 KiB
C++
/*
|
|
* Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
// Based on the Quic implementation in Chromium.
|
|
|
|
#include <algorithm>
|
|
|
|
#include "modules/congestion_controller/bbr/bandwidth_sampler.h"
|
|
#include "rtc_base/logging.h"
|
|
|
|
namespace webrtc {
|
|
namespace bbr {
|
|
namespace {
|
|
constexpr int64_t kMaxTrackedPackets = 10000;
|
|
}
|
|
|
|
BandwidthSampler::BandwidthSampler()
|
|
: total_data_sent_(DataSize::Zero()),
|
|
total_data_acked_(DataSize::Zero()),
|
|
total_data_sent_at_last_acked_packet_(DataSize::Zero()),
|
|
last_acked_packet_sent_time_(),
|
|
last_acked_packet_ack_time_(),
|
|
last_sent_packet_(0),
|
|
is_app_limited_(false),
|
|
end_of_app_limited_phase_(0),
|
|
connection_state_map_() {}
|
|
|
|
BandwidthSampler::~BandwidthSampler() {}
|
|
|
|
void BandwidthSampler::OnPacketSent(Timestamp sent_time,
|
|
int64_t packet_number,
|
|
DataSize data_size,
|
|
DataSize data_in_flight) {
|
|
last_sent_packet_ = packet_number;
|
|
|
|
total_data_sent_ += data_size;
|
|
|
|
// If there are no packets in flight, the time at which the new transmission
|
|
// opens can be treated as the A_0 point for the purpose of bandwidth
|
|
// sampling. This underestimates bandwidth to some extent, and produces some
|
|
// artificially low samples for most packets in flight, but it provides with
|
|
// samples at important points where we would not have them otherwise, most
|
|
// importantly at the beginning of the connection.
|
|
if (data_in_flight.IsZero()) {
|
|
last_acked_packet_ack_time_ = sent_time;
|
|
total_data_sent_at_last_acked_packet_ = total_data_sent_;
|
|
|
|
// In this situation ack compression is not a concern, set send rate to
|
|
// effectively infinite.
|
|
last_acked_packet_sent_time_ = sent_time;
|
|
}
|
|
|
|
if (!connection_state_map_.IsEmpty() &&
|
|
packet_number >
|
|
connection_state_map_.last_packet() + kMaxTrackedPackets) {
|
|
RTC_LOG(LS_WARNING)
|
|
<< "BandwidthSampler in-flight packet map has exceeded maximum "
|
|
"number "
|
|
"of tracked packets.";
|
|
}
|
|
|
|
bool success =
|
|
connection_state_map_.Emplace(packet_number, sent_time, data_size, *this);
|
|
if (!success)
|
|
RTC_LOG(LS_WARNING) << "BandwidthSampler failed to insert the packet "
|
|
"into the map, most likely because it's already "
|
|
"in it.";
|
|
}
|
|
|
|
BandwidthSample BandwidthSampler::OnPacketAcknowledged(Timestamp ack_time,
|
|
int64_t packet_number) {
|
|
ConnectionStateOnSentPacket* sent_packet_pointer =
|
|
connection_state_map_.GetEntry(packet_number);
|
|
if (sent_packet_pointer == nullptr) {
|
|
return BandwidthSample();
|
|
}
|
|
BandwidthSample sample =
|
|
OnPacketAcknowledgedInner(ack_time, packet_number, *sent_packet_pointer);
|
|
connection_state_map_.Remove(packet_number);
|
|
return sample;
|
|
}
|
|
|
|
BandwidthSample BandwidthSampler::OnPacketAcknowledgedInner(
|
|
Timestamp ack_time,
|
|
int64_t packet_number,
|
|
const ConnectionStateOnSentPacket& sent_packet) {
|
|
total_data_acked_ += sent_packet.size;
|
|
total_data_sent_at_last_acked_packet_ = sent_packet.total_data_sent;
|
|
last_acked_packet_sent_time_ = sent_packet.sent_time;
|
|
last_acked_packet_ack_time_ = ack_time;
|
|
|
|
// Exit app-limited phase once a packet that was sent while the connection is
|
|
// not app-limited is acknowledged.
|
|
if (is_app_limited_ && packet_number > end_of_app_limited_phase_) {
|
|
is_app_limited_ = false;
|
|
}
|
|
|
|
// There might have been no packets acknowledged at the moment when the
|
|
// current packet was sent. In that case, there is no bandwidth sample to
|
|
// make.
|
|
if (!sent_packet.last_acked_packet_sent_time ||
|
|
!sent_packet.last_acked_packet_ack_time) {
|
|
return BandwidthSample();
|
|
}
|
|
|
|
// Infinite rate indicates that the sampler is supposed to discard the
|
|
// current send rate sample and use only the ack rate.
|
|
DataRate send_rate = DataRate::Infinity();
|
|
if (sent_packet.sent_time > *sent_packet.last_acked_packet_sent_time) {
|
|
DataSize sent_delta = sent_packet.total_data_sent -
|
|
sent_packet.total_data_sent_at_last_acked_packet;
|
|
TimeDelta time_delta =
|
|
sent_packet.sent_time - *sent_packet.last_acked_packet_sent_time;
|
|
send_rate = sent_delta / time_delta;
|
|
}
|
|
|
|
// During the slope calculation, ensure that ack time of the current packet is
|
|
// always larger than the time of the previous packet, otherwise division by
|
|
// zero or integer underflow can occur.
|
|
if (ack_time <= *sent_packet.last_acked_packet_ack_time) {
|
|
RTC_LOG(LS_WARNING)
|
|
<< "Time of the previously acked packet is larger than the time "
|
|
"of the current packet.";
|
|
return BandwidthSample();
|
|
}
|
|
DataSize ack_delta =
|
|
total_data_acked_ - sent_packet.total_data_acked_at_the_last_acked_packet;
|
|
TimeDelta time_delta = ack_time - *sent_packet.last_acked_packet_ack_time;
|
|
DataRate ack_rate = ack_delta / time_delta;
|
|
|
|
BandwidthSample sample;
|
|
sample.bandwidth = std::min(send_rate, ack_rate);
|
|
// Note: this sample does not account for delayed acknowledgement time. This
|
|
// means that the RTT measurements here can be artificially high, especially
|
|
// on low bandwidth connections.
|
|
sample.rtt = ack_time - sent_packet.sent_time;
|
|
// A sample is app-limited if the packet was sent during the app-limited
|
|
// phase.
|
|
sample.is_app_limited = sent_packet.is_app_limited;
|
|
return sample;
|
|
}
|
|
|
|
void BandwidthSampler::OnPacketLost(int64_t packet_number) {
|
|
connection_state_map_.Remove(packet_number);
|
|
}
|
|
|
|
void BandwidthSampler::OnAppLimited() {
|
|
is_app_limited_ = true;
|
|
end_of_app_limited_phase_ = last_sent_packet_;
|
|
}
|
|
|
|
void BandwidthSampler::RemoveObsoletePackets(int64_t least_unacked) {
|
|
while (!connection_state_map_.IsEmpty() &&
|
|
connection_state_map_.first_packet() < least_unacked) {
|
|
connection_state_map_.Remove(connection_state_map_.first_packet());
|
|
}
|
|
}
|
|
|
|
DataSize BandwidthSampler::total_data_acked() const {
|
|
return total_data_acked_;
|
|
}
|
|
|
|
bool BandwidthSampler::is_app_limited() const {
|
|
return is_app_limited_;
|
|
}
|
|
|
|
int64_t BandwidthSampler::end_of_app_limited_phase() const {
|
|
return end_of_app_limited_phase_;
|
|
}
|
|
|
|
BandwidthSampler::ConnectionStateOnSentPacket::ConnectionStateOnSentPacket(
|
|
Timestamp sent_time,
|
|
DataSize size,
|
|
const BandwidthSampler& sampler)
|
|
: sent_time(sent_time),
|
|
size(size),
|
|
total_data_sent(sampler.total_data_sent_),
|
|
total_data_sent_at_last_acked_packet(
|
|
sampler.total_data_sent_at_last_acked_packet_),
|
|
last_acked_packet_sent_time(sampler.last_acked_packet_sent_time_),
|
|
last_acked_packet_ack_time(sampler.last_acked_packet_ack_time_),
|
|
total_data_acked_at_the_last_acked_packet(sampler.total_data_acked_),
|
|
is_app_limited(sampler.is_app_limited_) {}
|
|
|
|
BandwidthSampler::ConnectionStateOnSentPacket::ConnectionStateOnSentPacket()
|
|
: sent_time(Timestamp::ms(0)),
|
|
size(DataSize::Zero()),
|
|
total_data_sent(DataSize::Zero()),
|
|
total_data_sent_at_last_acked_packet(DataSize::Zero()),
|
|
last_acked_packet_sent_time(),
|
|
last_acked_packet_ack_time(),
|
|
total_data_acked_at_the_last_acked_packet(DataSize::Zero()),
|
|
is_app_limited(false) {}
|
|
|
|
BandwidthSampler::ConnectionStateOnSentPacket::~ConnectionStateOnSentPacket() {}
|
|
|
|
} // namespace bbr
|
|
} // namespace webrtc
|