mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-15 06:40:43 +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}
337 lines
11 KiB
C++
337 lines
11 KiB
C++
/*
|
|
* Copyright 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 "test/gtest.h"
|
|
|
|
namespace webrtc {
|
|
namespace bbr {
|
|
namespace test {
|
|
|
|
class BandwidthSamplerPeer {
|
|
public:
|
|
static size_t GetNumberOfTrackedPackets(const BandwidthSampler& sampler) {
|
|
return sampler.connection_state_map_.number_of_present_entries();
|
|
}
|
|
|
|
static DataSize GetPacketSize(const BandwidthSampler& sampler,
|
|
int64_t packet_number) {
|
|
return sampler.connection_state_map_.GetEntry(packet_number)->size;
|
|
}
|
|
};
|
|
|
|
const int64_t kRegularPacketSizeBytes = 1280;
|
|
// Enforce divisibility for some of the tests.
|
|
static_assert((kRegularPacketSizeBytes & 31) == 0,
|
|
"kRegularPacketSizeBytes has to be five times divisible by 2");
|
|
|
|
const DataSize kRegularPacketSize = DataSize::bytes(kRegularPacketSizeBytes);
|
|
|
|
// A test fixture with utility methods for BandwidthSampler tests.
|
|
class BandwidthSamplerTest : public ::testing::Test {
|
|
protected:
|
|
BandwidthSamplerTest()
|
|
: clock_(Timestamp::seconds(100)), bytes_in_flight_(DataSize::Zero()) {}
|
|
|
|
Timestamp clock_;
|
|
BandwidthSampler sampler_;
|
|
DataSize bytes_in_flight_;
|
|
|
|
void SendPacketInner(int64_t packet_number, DataSize bytes) {
|
|
sampler_.OnPacketSent(clock_, packet_number, bytes, bytes_in_flight_);
|
|
bytes_in_flight_ += bytes;
|
|
}
|
|
|
|
void SendPacket(int64_t packet_number) {
|
|
SendPacketInner(packet_number, kRegularPacketSize);
|
|
}
|
|
|
|
BandwidthSample AckPacketInner(int64_t packet_number) {
|
|
DataSize size =
|
|
BandwidthSamplerPeer::GetPacketSize(sampler_, packet_number);
|
|
bytes_in_flight_ -= size;
|
|
return sampler_.OnPacketAcknowledged(clock_, packet_number);
|
|
}
|
|
|
|
// Acknowledge receipt of a packet and expect it to be not app-limited.
|
|
DataRate AckPacket(int64_t packet_number) {
|
|
BandwidthSample sample = AckPacketInner(packet_number);
|
|
EXPECT_FALSE(sample.is_app_limited);
|
|
return sample.bandwidth;
|
|
}
|
|
|
|
void LosePacket(int64_t packet_number) {
|
|
DataSize size =
|
|
BandwidthSamplerPeer::GetPacketSize(sampler_, packet_number);
|
|
bytes_in_flight_ -= size;
|
|
sampler_.OnPacketLost(packet_number);
|
|
}
|
|
|
|
// Sends one packet and acks it. Then, send 20 packets. Finally, send
|
|
// another 20 packets while acknowledging previous 20.
|
|
void Send40PacketsAndAckFirst20(TimeDelta time_between_packets) {
|
|
// Send 20 packets at a constant inter-packet time.
|
|
for (int64_t i = 1; i <= 20; i++) {
|
|
SendPacket(i);
|
|
clock_ += time_between_packets;
|
|
}
|
|
|
|
// Ack packets 1 to 20, while sending new packets at the same rate as
|
|
// before.
|
|
for (int64_t i = 1; i <= 20; i++) {
|
|
AckPacket(i);
|
|
SendPacket(i + 20);
|
|
clock_ += time_between_packets;
|
|
}
|
|
}
|
|
};
|
|
|
|
// Test the sampler in a simple stop-and-wait sender setting.
|
|
TEST_F(BandwidthSamplerTest, SendAndWait) {
|
|
TimeDelta time_between_packets = TimeDelta::ms(10);
|
|
DataRate expected_bandwidth =
|
|
kRegularPacketSize * 100 / TimeDelta::seconds(1);
|
|
|
|
// Send packets at the constant bandwidth.
|
|
for (int64_t i = 1; i < 20; i++) {
|
|
SendPacket(i);
|
|
clock_ += time_between_packets;
|
|
DataRate current_sample = AckPacket(i);
|
|
EXPECT_EQ(expected_bandwidth, current_sample);
|
|
}
|
|
|
|
// Send packets at the exponentially decreasing bandwidth.
|
|
for (int64_t i = 20; i < 25; i++) {
|
|
time_between_packets = time_between_packets * 2;
|
|
expected_bandwidth = expected_bandwidth * 0.5;
|
|
|
|
SendPacket(i);
|
|
clock_ += time_between_packets;
|
|
DataRate current_sample = AckPacket(i);
|
|
EXPECT_EQ(expected_bandwidth, current_sample);
|
|
}
|
|
EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
|
|
EXPECT_TRUE(bytes_in_flight_.IsZero());
|
|
}
|
|
|
|
// Test the sampler during regular windowed sender scenario with fixed
|
|
// CWND of 20.
|
|
TEST_F(BandwidthSamplerTest, SendPaced) {
|
|
const TimeDelta time_between_packets = TimeDelta::ms(1);
|
|
DataRate expected_bandwidth = kRegularPacketSize / time_between_packets;
|
|
|
|
Send40PacketsAndAckFirst20(time_between_packets);
|
|
|
|
// Ack the packets 21 to 40, arriving at the correct bandwidth.
|
|
DataRate last_bandwidth = DataRate::Zero();
|
|
for (int64_t i = 21; i <= 40; i++) {
|
|
last_bandwidth = AckPacket(i);
|
|
EXPECT_EQ(expected_bandwidth, last_bandwidth);
|
|
clock_ += time_between_packets;
|
|
}
|
|
EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
|
|
EXPECT_TRUE(bytes_in_flight_.IsZero());
|
|
}
|
|
|
|
// Test the sampler in a scenario where 50% of packets is consistently lost.
|
|
TEST_F(BandwidthSamplerTest, SendWithLosses) {
|
|
const TimeDelta time_between_packets = TimeDelta::ms(1);
|
|
DataRate expected_bandwidth = kRegularPacketSize / time_between_packets * 0.5;
|
|
|
|
// Send 20 packets, each 1 ms apart.
|
|
for (int64_t i = 1; i <= 20; i++) {
|
|
SendPacket(i);
|
|
clock_ += time_between_packets;
|
|
}
|
|
|
|
// Ack packets 1 to 20, losing every even-numbered packet, while sending new
|
|
// packets at the same rate as before.
|
|
for (int64_t i = 1; i <= 20; i++) {
|
|
if (i % 2 == 0) {
|
|
AckPacket(i);
|
|
} else {
|
|
LosePacket(i);
|
|
}
|
|
SendPacket(i + 20);
|
|
clock_ += time_between_packets;
|
|
}
|
|
|
|
// Ack the packets 21 to 40 with the same loss pattern.
|
|
DataRate last_bandwidth = DataRate::Zero();
|
|
for (int64_t i = 21; i <= 40; i++) {
|
|
if (i % 2 == 0) {
|
|
last_bandwidth = AckPacket(i);
|
|
EXPECT_EQ(expected_bandwidth, last_bandwidth);
|
|
} else {
|
|
LosePacket(i);
|
|
}
|
|
clock_ += time_between_packets;
|
|
}
|
|
EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
|
|
EXPECT_TRUE(bytes_in_flight_.IsZero());
|
|
}
|
|
|
|
// Simulate a situation where ACKs arrive in burst and earlier than usual, thus
|
|
// producing an ACK rate which is higher than the original send rate.
|
|
TEST_F(BandwidthSamplerTest, CompressedAck) {
|
|
const TimeDelta time_between_packets = TimeDelta::ms(1);
|
|
DataRate expected_bandwidth = kRegularPacketSize / time_between_packets;
|
|
|
|
Send40PacketsAndAckFirst20(time_between_packets);
|
|
|
|
// Simulate an RTT somewhat lower than the one for 1-to-21 transmission.
|
|
clock_ += time_between_packets * 15;
|
|
|
|
// Ack the packets 21 to 40 almost immediately at once.
|
|
DataRate last_bandwidth = DataRate::Zero();
|
|
TimeDelta ridiculously_small_time_delta = TimeDelta::us(20);
|
|
for (int64_t i = 21; i <= 40; i++) {
|
|
last_bandwidth = AckPacket(i);
|
|
clock_ += ridiculously_small_time_delta;
|
|
}
|
|
EXPECT_EQ(expected_bandwidth, last_bandwidth);
|
|
EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
|
|
EXPECT_TRUE(bytes_in_flight_.IsZero());
|
|
}
|
|
|
|
// Tests receiving ACK packets in the reverse order.
|
|
TEST_F(BandwidthSamplerTest, ReorderedAck) {
|
|
const TimeDelta time_between_packets = TimeDelta::ms(1);
|
|
DataRate expected_bandwidth = kRegularPacketSize / time_between_packets;
|
|
|
|
Send40PacketsAndAckFirst20(time_between_packets);
|
|
|
|
// Ack the packets 21 to 40 in the reverse order, while sending packets 41 to
|
|
// 60.
|
|
DataRate last_bandwidth = DataRate::Zero();
|
|
for (int64_t i = 0; i < 20; i++) {
|
|
last_bandwidth = AckPacket(40 - i);
|
|
EXPECT_EQ(expected_bandwidth, last_bandwidth);
|
|
SendPacket(41 + i);
|
|
clock_ += time_between_packets;
|
|
}
|
|
|
|
// Ack the packets 41 to 60, now in the regular order.
|
|
for (int64_t i = 41; i <= 60; i++) {
|
|
last_bandwidth = AckPacket(i);
|
|
EXPECT_EQ(expected_bandwidth, last_bandwidth);
|
|
clock_ += time_between_packets;
|
|
}
|
|
EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
|
|
EXPECT_TRUE(bytes_in_flight_.IsZero());
|
|
}
|
|
|
|
// Test the app-limited logic.
|
|
TEST_F(BandwidthSamplerTest, AppLimited) {
|
|
const TimeDelta time_between_packets = TimeDelta::ms(1);
|
|
DataRate expected_bandwidth = kRegularPacketSize / time_between_packets;
|
|
|
|
Send40PacketsAndAckFirst20(time_between_packets);
|
|
|
|
// We are now app-limited. Ack 21 to 40 as usual, but do not send anything for
|
|
// now.
|
|
sampler_.OnAppLimited();
|
|
for (int64_t i = 21; i <= 40; i++) {
|
|
DataRate current_sample = AckPacket(i);
|
|
EXPECT_EQ(expected_bandwidth, current_sample);
|
|
clock_ += time_between_packets;
|
|
}
|
|
|
|
// Enter quiescence.
|
|
clock_ += TimeDelta::seconds(1);
|
|
|
|
// Send packets 41 to 60, all of which would be marked as app-limited.
|
|
for (int64_t i = 41; i <= 60; i++) {
|
|
SendPacket(i);
|
|
clock_ += time_between_packets;
|
|
}
|
|
|
|
// Ack packets 41 to 60, while sending packets 61 to 80. 41 to 60 should be
|
|
// app-limited and underestimate the bandwidth due to that.
|
|
for (int64_t i = 41; i <= 60; i++) {
|
|
BandwidthSample sample = AckPacketInner(i);
|
|
EXPECT_TRUE(sample.is_app_limited);
|
|
EXPECT_LT(sample.bandwidth, 0.7f * expected_bandwidth);
|
|
|
|
SendPacket(i + 20);
|
|
clock_ += time_between_packets;
|
|
}
|
|
|
|
// Run out of packets, and then ack packet 61 to 80, all of which should have
|
|
// correct non-app-limited samples.
|
|
for (int64_t i = 61; i <= 80; i++) {
|
|
DataRate last_bandwidth = AckPacket(i);
|
|
EXPECT_EQ(expected_bandwidth, last_bandwidth);
|
|
clock_ += time_between_packets;
|
|
}
|
|
|
|
EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
|
|
EXPECT_TRUE(bytes_in_flight_.IsZero());
|
|
}
|
|
|
|
// Test the samples taken at the first flight of packets sent.
|
|
TEST_F(BandwidthSamplerTest, FirstRoundTrip) {
|
|
const TimeDelta time_between_packets = TimeDelta::ms(1);
|
|
const TimeDelta rtt = TimeDelta::ms(800);
|
|
const int num_packets = 10;
|
|
const DataSize num_bytes = kRegularPacketSize * num_packets;
|
|
const DataRate real_bandwidth = num_bytes / rtt;
|
|
|
|
for (int64_t i = 1; i <= 10; i++) {
|
|
SendPacket(i);
|
|
clock_ += time_between_packets;
|
|
}
|
|
|
|
clock_ += rtt - num_packets * time_between_packets;
|
|
|
|
DataRate last_sample = DataRate::Zero();
|
|
for (int64_t i = 1; i <= 10; i++) {
|
|
DataRate sample = AckPacket(i);
|
|
EXPECT_GT(sample, last_sample);
|
|
last_sample = sample;
|
|
clock_ += time_between_packets;
|
|
}
|
|
|
|
// The final measured sample for the first flight of sample is expected to be
|
|
// smaller than the real bandwidth, yet it should not lose more than 10%. The
|
|
// specific value of the error depends on the difference between the RTT and
|
|
// the time it takes to exhaust the congestion window (i.e. in the limit when
|
|
// all packets are sent simultaneously, last sample would indicate the real
|
|
// bandwidth).
|
|
EXPECT_LT(last_sample, real_bandwidth);
|
|
EXPECT_GT(last_sample, 0.9f * real_bandwidth);
|
|
}
|
|
|
|
// Test sampler's ability to remove obsolete packets.
|
|
TEST_F(BandwidthSamplerTest, RemoveObsoletePackets) {
|
|
SendPacket(1);
|
|
SendPacket(2);
|
|
SendPacket(3);
|
|
SendPacket(4);
|
|
SendPacket(5);
|
|
|
|
clock_ += TimeDelta::ms(100);
|
|
|
|
EXPECT_EQ(5u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
|
|
sampler_.RemoveObsoletePackets(4);
|
|
EXPECT_EQ(2u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
|
|
sampler_.OnPacketLost(4);
|
|
EXPECT_EQ(1u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
|
|
AckPacket(5);
|
|
EXPECT_EQ(0u, BandwidthSamplerPeer::GetNumberOfTrackedPackets(sampler_));
|
|
}
|
|
|
|
} // namespace test
|
|
} // namespace bbr
|
|
} // namespace webrtc
|