| Index: net/quic/core/congestion_control/send_algorithm_test.cc
|
| diff --git a/net/quic/core/congestion_control/send_algorithm_test.cc b/net/quic/core/congestion_control/send_algorithm_test.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..75bacfbb9c460695c08b91a35e9450523d1e0581
|
| --- /dev/null
|
| +++ b/net/quic/core/congestion_control/send_algorithm_test.cc
|
| @@ -0,0 +1,359 @@
|
| +// Copyright 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 <algorithm>
|
| +#include <map>
|
| +#include <memory>
|
| +
|
| +#include "base/logging.h"
|
| +#include "net/quic/core/congestion_control/rtt_stats.h"
|
| +#include "net/quic/core/congestion_control/send_algorithm_interface.h"
|
| +#include "net/quic/core/quic_types.h"
|
| +#include "net/quic/core/quic_utils.h"
|
| +#include "net/quic/test_tools/mock_clock.h"
|
| +#include "net/quic/test_tools/quic_config_peer.h"
|
| +#include "net/quic/test_tools/quic_connection_peer.h"
|
| +#include "net/quic/test_tools/quic_sent_packet_manager_peer.h"
|
| +#include "net/quic/test_tools/quic_test_utils.h"
|
| +#include "net/quic/test_tools/simulator/quic_endpoint.h"
|
| +#include "net/quic/test_tools/simulator/simulator.h"
|
| +#include "net/quic/test_tools/simulator/switch.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +using std::string;
|
| +
|
| +namespace net {
|
| +namespace test {
|
| +namespace {
|
| +
|
| +// Use the initial CWND of 10, as 32 is too much for the test network.
|
| +const uint32_t kInitialCongestionWindowPackets = 10;
|
| +
|
| +// Test network parameters. Here, the topology of the network is:
|
| +//
|
| +// QUIC Sender
|
| +// |
|
| +// | <-- local link
|
| +// |
|
| +// Network switch
|
| +// * <-- the bottleneck queue in the direction
|
| +// | of the receiver
|
| +// |
|
| +// | <-- test link
|
| +// |
|
| +// |
|
| +// Receiver
|
| +//
|
| +// When setting the bandwidth of the local link and test link, choose
|
| +// a bandwidth lower than 20Mbps, as the clock-granularity of the
|
| +// simulator can only handle a granularity of 1us.
|
| +
|
| +// Default settings between the switch and the sender.
|
| +const QuicBandwidth kLocalLinkBandwidth =
|
| + QuicBandwidth::FromKBitsPerSecond(10000);
|
| +const QuicTime::Delta kLocalPropagationDelay =
|
| + QuicTime::Delta::FromMilliseconds(2);
|
| +
|
| +// Wired network settings. A typical desktop network setup, a
|
| +// high-bandwidth, 30ms test link to the receiver.
|
| +const QuicBandwidth kTestLinkWiredBandwidth =
|
| + QuicBandwidth::FromKBitsPerSecond(4000);
|
| +const QuicTime::Delta kTestLinkWiredPropagationDelay =
|
| + QuicTime::Delta::FromMilliseconds(30);
|
| +const QuicTime::Delta kTestWiredTransferTime =
|
| + kTestLinkWiredBandwidth.TransferTime(kMaxPacketSize) +
|
| + kLocalLinkBandwidth.TransferTime(kMaxPacketSize);
|
| +const QuicTime::Delta kTestWiredRtt =
|
| + (kTestLinkWiredPropagationDelay + kLocalPropagationDelay +
|
| + kTestWiredTransferTime) *
|
| + 2;
|
| +const QuicByteCount kTestWiredBdp = kTestWiredRtt * kTestLinkWiredBandwidth;
|
| +
|
| +// Small BDP, Bandwidth-policed network settings. In this scenario,
|
| +// the receiver has a low-bandwidth, short propagation-delay link,
|
| +// resulting in a small BDP. We model the policer by setting the
|
| +// queue size to only one packet.
|
| +const QuicBandwidth kTestLinkLowBdpBandwidth =
|
| + QuicBandwidth::FromKBitsPerSecond(200);
|
| +const QuicTime::Delta kTestLinkLowBdpPropagationDelay =
|
| + QuicTime::Delta::FromMilliseconds(30);
|
| +const QuicByteCount kTestPolicerQueue = kMaxPacketSize;
|
| +
|
| +// Satellite network settings. In a satellite network, the bottleneck
|
| +// buffer is typically sized for non-satellite links , but the
|
| +// propagation delay of the test link to the receiver is as much as a
|
| +// quarter second.
|
| +const QuicTime::Delta kTestSatellitePropagationDelay =
|
| + QuicTime::Delta::FromMilliseconds(250);
|
| +
|
| +// Cellular scenarios. In a cellular network, the bottleneck queue at
|
| +// the edge of the network can be as great as 3MB.
|
| +const QuicBandwidth kTestLink2GBandwidth =
|
| + QuicBandwidth::FromKBitsPerSecond(100);
|
| +const QuicBandwidth kTestLink3GBandwidth =
|
| + QuicBandwidth::FromKBitsPerSecond(1500);
|
| +const QuicByteCount kCellularQueue = 3 * 1024 * 1024;
|
| +const QuicTime::Delta kTestCellularPropagationDelay =
|
| + QuicTime::Delta::FromMilliseconds(40);
|
| +
|
| +const char* CongestionControlTypeToString(CongestionControlType cc_type) {
|
| + switch (cc_type) {
|
| + case kCubic:
|
| + return "CUBIC_PACKETS";
|
| + case kCubicBytes:
|
| + return "CUBIC_BYTES";
|
| + case kReno:
|
| + return "RENO_PACKETS";
|
| + case kRenoBytes:
|
| + return "RENO_BYTES";
|
| + case kBBR:
|
| + return "BBR";
|
| + default:
|
| + DLOG(FATAL) << "Unexpected CongestionControlType";
|
| + return nullptr;
|
| + }
|
| +}
|
| +
|
| +struct TestParams {
|
| + explicit TestParams(CongestionControlType congestion_control_type)
|
| + : congestion_control_type(congestion_control_type) {}
|
| +
|
| + friend std::ostream& operator<<(std::ostream& os, const TestParams& p) {
|
| + os << "{ congestion_control_type: "
|
| + << CongestionControlTypeToString(p.congestion_control_type);
|
| + os << " }";
|
| + return os;
|
| + }
|
| +
|
| + CongestionControlType congestion_control_type;
|
| +};
|
| +
|
| +string TestParamToString(const testing::TestParamInfo<TestParams>& params) {
|
| + return CongestionControlTypeToString(params.param.congestion_control_type);
|
| +}
|
| +
|
| +// Constructs various test permutations.
|
| +std::vector<TestParams> GetTestParams() {
|
| + std::vector<TestParams> params;
|
| + for (const CongestionControlType congestion_control_type :
|
| + {kBBR, kCubic, kCubicBytes, kReno, kRenoBytes}) {
|
| + params.push_back(TestParams(congestion_control_type));
|
| + }
|
| + return params;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +class SendAlgorithmTest : public ::testing::TestWithParam<TestParams> {
|
| + protected:
|
| + SendAlgorithmTest()
|
| + : simulator_(),
|
| + quic_sender_(&simulator_,
|
| + "QUIC sender",
|
| + "Receiver",
|
| + Perspective::IS_CLIENT,
|
| + 42),
|
| + receiver_(&simulator_,
|
| + "Receiver",
|
| + "QUIC sender",
|
| + Perspective::IS_SERVER,
|
| + 42) {
|
| + rtt_stats_ = quic_sender_.connection()->sent_packet_manager().GetRttStats();
|
| + sender_ = SendAlgorithmInterface::Create(
|
| + simulator_.GetClock(), rtt_stats_,
|
| + QuicSentPacketManagerPeer::GetUnackedPacketMap(
|
| + QuicConnectionPeer::GetSentPacketManager(quic_sender_.connection(),
|
| + kDefaultPathId)),
|
| + GetParam().congestion_control_type, &random_, &stats_,
|
| + kInitialCongestionWindowPackets);
|
| +
|
| + if (FLAGS_quic_fix_cubic_convex_mode) {
|
| + QuicConfig client_config;
|
| + QuicTagVector options;
|
| + options.push_back(kCCVX);
|
| + client_config.SetInitialReceivedConnectionOptions(options);
|
| + sender_->SetFromConfig(client_config, Perspective::IS_SERVER);
|
| + }
|
| +
|
| + QuicConnectionPeer::SetSendAlgorithm(quic_sender_.connection(),
|
| + kDefaultPathId, sender_);
|
| +
|
| + clock_ = simulator_.GetClock();
|
| + simulator_.set_random_generator(&random_);
|
| +
|
| + uint64_t seed = QuicRandom::GetInstance()->RandUint64();
|
| + random_.set_seed(seed);
|
| + VLOG(1) << "SendAlgorithmTest simulator set up. Seed: " << seed;
|
| + }
|
| +
|
| + // Creates a simulated network, with default settings between the
|
| + // sender and the switch and the given settings from the switch to
|
| + // the receiver.
|
| + void CreateSetup(const QuicBandwidth& test_bandwidth,
|
| + const QuicTime::Delta& test_link_delay,
|
| + QuicByteCount bottleneck_queue_length) {
|
| + switch_.reset(new simulator::Switch(&simulator_, "Switch", 8,
|
| + bottleneck_queue_length));
|
| + quic_sender_link_.reset(new simulator::SymmetricLink(
|
| + &quic_sender_, switch_->port(1), kLocalLinkBandwidth,
|
| + kLocalPropagationDelay));
|
| + receiver_link_.reset(new simulator::SymmetricLink(
|
| + &receiver_, switch_->port(2), test_bandwidth, test_link_delay));
|
| + }
|
| +
|
| + void DoSimpleTransfer(QuicByteCount transfer_size, QuicTime::Delta deadline) {
|
| + quic_sender_.AddBytesToTransfer(transfer_size);
|
| + bool simulator_result = simulator_.RunUntilOrTimeout(
|
| + [this]() { return quic_sender_.bytes_to_transfer() == 0; }, deadline);
|
| + EXPECT_TRUE(simulator_result)
|
| + << "Simple transfer failed. Bytes remaining: "
|
| + << quic_sender_.bytes_to_transfer();
|
| + }
|
| +
|
| + void SendBursts(size_t number_of_bursts,
|
| + QuicByteCount bytes,
|
| + QuicTime::Delta rtt,
|
| + QuicTime::Delta wait_time) {
|
| + ASSERT_EQ(0u, quic_sender_.bytes_to_transfer());
|
| + for (size_t i = 0; i < number_of_bursts; i++) {
|
| + quic_sender_.AddBytesToTransfer(bytes);
|
| +
|
| + // Transfer data and wait for three seconds between each transfer.
|
| + simulator_.RunFor(wait_time);
|
| +
|
| + // Ensure the connection did not time out.
|
| + ASSERT_TRUE(quic_sender_.connection()->connected());
|
| + ASSERT_TRUE(receiver_.connection()->connected());
|
| + }
|
| +
|
| + simulator_.RunFor(wait_time + rtt);
|
| + EXPECT_EQ(0u, quic_sender_.bytes_to_transfer());
|
| + }
|
| +
|
| + // Estimates the elapsed time for a given transfer size, given the
|
| + // bottleneck bandwidth and link propagation delay.
|
| + QuicTime::Delta EstimatedElapsedTime(
|
| + QuicByteCount transfer_size_bytes,
|
| + QuicBandwidth test_link_bandwidth,
|
| + const QuicTime::Delta& test_link_delay) const {
|
| + return test_link_bandwidth.TransferTime(transfer_size_bytes) +
|
| + 2 * test_link_delay;
|
| + }
|
| +
|
| + QuicTime QuicSenderStartTime() {
|
| + return quic_sender_.connection()->GetStats().connection_creation_time;
|
| + }
|
| +
|
| + void PrintTransferStats() {
|
| + VLOG(1) << "Summary for scenario " << GetParam();
|
| + VLOG(1) << "Sender stats is " << quic_sender_.connection()->GetStats();
|
| + VLOG(1) << "Connection elapsed time: "
|
| + << (clock_->Now() - QuicSenderStartTime()).ToMilliseconds()
|
| + << " (ms)";
|
| + }
|
| +
|
| + simulator::Simulator simulator_;
|
| + simulator::QuicEndpoint quic_sender_;
|
| + simulator::QuicEndpoint receiver_;
|
| + std::unique_ptr<simulator::Switch> switch_;
|
| + std::unique_ptr<simulator::SymmetricLink> quic_sender_link_;
|
| + std::unique_ptr<simulator::SymmetricLink> receiver_link_;
|
| + QuicConnectionStats stats_;
|
| +
|
| + SimpleRandom random_;
|
| +
|
| + // Owned by different components of the connection.
|
| + const QuicClock* clock_;
|
| + const RttStats* rtt_stats_;
|
| + SendAlgorithmInterface* sender_;
|
| +};
|
| +
|
| +INSTANTIATE_TEST_CASE_P(SendAlgorithmTests,
|
| + SendAlgorithmTest,
|
| + ::testing::ValuesIn(GetTestParams()),
|
| + TestParamToString);
|
| +
|
| +// Test a simple long data transfer in the default setup.
|
| +TEST_P(SendAlgorithmTest, SimpleWiredNetworkTransfer) {
|
| + CreateSetup(kTestLinkWiredBandwidth, kTestLinkWiredPropagationDelay,
|
| + kTestWiredBdp);
|
| + const QuicByteCount kTransferSizeBytes = 12 * 1024 * 1024;
|
| + const QuicTime::Delta maximum_elapsed_time =
|
| + EstimatedElapsedTime(kTransferSizeBytes, kTestLinkWiredBandwidth,
|
| + kTestLinkWiredPropagationDelay) *
|
| + 1.2;
|
| + DoSimpleTransfer(kTransferSizeBytes, maximum_elapsed_time);
|
| + PrintTransferStats();
|
| +}
|
| +
|
| +TEST_P(SendAlgorithmTest, LowBdpPolicedNetworkTransfer) {
|
| + CreateSetup(kTestLinkLowBdpBandwidth, kTestLinkLowBdpPropagationDelay,
|
| + kTestPolicerQueue);
|
| + const QuicByteCount kTransferSizeBytes = 5 * 1024 * 1024;
|
| + const QuicTime::Delta maximum_elapsed_time =
|
| + EstimatedElapsedTime(kTransferSizeBytes, kTestLinkLowBdpBandwidth,
|
| + kTestLinkLowBdpPropagationDelay) *
|
| + 1.2;
|
| + DoSimpleTransfer(kTransferSizeBytes, maximum_elapsed_time);
|
| + PrintTransferStats();
|
| +}
|
| +
|
| +TEST_P(SendAlgorithmTest, AppLimitedBurstsOverWiredNetwork) {
|
| + CreateSetup(kTestLinkWiredBandwidth, kTestLinkWiredPropagationDelay,
|
| + kTestWiredBdp);
|
| + const QuicByteCount kBurstSizeBytes = 512;
|
| + const int kNumBursts = 20;
|
| + const QuicTime::Delta kWaitTime = QuicTime::Delta::FromSeconds(3);
|
| + SendBursts(kNumBursts, kBurstSizeBytes, kTestWiredRtt, kWaitTime);
|
| + PrintTransferStats();
|
| +
|
| + const QuicTime::Delta estimated_burst_time =
|
| + EstimatedElapsedTime(kBurstSizeBytes, kTestLinkWiredBandwidth,
|
| + kTestLinkWiredPropagationDelay) +
|
| + kWaitTime;
|
| + const QuicTime::Delta max_elapsed_time =
|
| + kNumBursts * estimated_burst_time + kWaitTime;
|
| + const QuicTime::Delta actual_elapsed_time =
|
| + clock_->Now() - QuicSenderStartTime();
|
| + EXPECT_GE(max_elapsed_time, actual_elapsed_time);
|
| +}
|
| +
|
| +TEST_P(SendAlgorithmTest, SatelliteNetworkTransfer) {
|
| + CreateSetup(kTestLinkWiredBandwidth, kTestSatellitePropagationDelay,
|
| + kTestWiredBdp);
|
| + const QuicByteCount kTransferSizeBytes = 20 * 1024 * 1024;
|
| + const QuicTime::Delta maximum_elapsed_time =
|
| + EstimatedElapsedTime(kTransferSizeBytes, kTestLinkWiredBandwidth,
|
| + kTestSatellitePropagationDelay) *
|
| + 1.25;
|
| + DoSimpleTransfer(kTransferSizeBytes, maximum_elapsed_time);
|
| + PrintTransferStats();
|
| +}
|
| +
|
| +TEST_P(SendAlgorithmTest, 2GNetworkTransfer) {
|
| + CreateSetup(kTestLink2GBandwidth, kTestCellularPropagationDelay,
|
| + kCellularQueue);
|
| + const QuicByteCount kTransferSizeBytes = 1024 * 1024;
|
| + const QuicTime::Delta maximum_elapsed_time =
|
| + EstimatedElapsedTime(kTransferSizeBytes, kTestLink2GBandwidth,
|
| + kTestCellularPropagationDelay) *
|
| + 1.2;
|
| + DoSimpleTransfer(kTransferSizeBytes, maximum_elapsed_time);
|
| + PrintTransferStats();
|
| +}
|
| +
|
| +TEST_P(SendAlgorithmTest, 3GNetworkTransfer) {
|
| + CreateSetup(kTestLink3GBandwidth, kTestCellularPropagationDelay,
|
| + kCellularQueue);
|
| + const QuicByteCount kTransferSizeBytes = 5 * 1024 * 1024;
|
| + const QuicTime::Delta maximum_elapsed_time =
|
| + EstimatedElapsedTime(kTransferSizeBytes, kTestLink3GBandwidth,
|
| + kTestCellularPropagationDelay) *
|
| + 1.2;
|
| + DoSimpleTransfer(kTransferSizeBytes, maximum_elapsed_time);
|
| + PrintTransferStats();
|
| +}
|
| +
|
| +} // namespace test
|
| +} // namespace net
|
|
|