summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_test.cc')
-rw-r--r--chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_test.cc371
1 files changed, 371 insertions, 0 deletions
diff --git a/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_test.cc b/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_test.cc
new file mode 100644
index 00000000000..c07508c41bf
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_test.cc
@@ -0,0 +1,371 @@
+// 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 <string>
+
+#include "net/third_party/quiche/src/quic/core/congestion_control/rtt_stats.h"
+#include "net/third_party/quiche/src/quic/core/congestion_control/send_algorithm_interface.h"
+#include "net/third_party/quiche/src/quic/core/quic_types.h"
+#include "net/third_party/quiche/src/quic/core/quic_utils.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_logging.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_str_cat.h"
+#include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
+#include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_config_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_connection_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_sent_packet_manager_peer.h"
+#include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/quic_endpoint.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h"
+#include "net/third_party/quiche/src/quic/test_tools/simulator/switch.h"
+
+namespace quic {
+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(50);
+const QuicTime::Delta kTestWiredTransferTime =
+ kTestLinkWiredBandwidth.TransferTime(kMaxOutgoingPacketSize) +
+ kLocalLinkBandwidth.TransferTime(kMaxOutgoingPacketSize);
+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(50);
+const QuicByteCount kTestPolicerQueue = kMaxOutgoingPacketSize;
+
+// 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);
+
+// Small RTT scenario, below the per-ack-update threshold of 30ms.
+const QuicTime::Delta kTestLinkSmallRTTDelay =
+ QuicTime::Delta::FromMilliseconds(10);
+
+const char* CongestionControlTypeToString(CongestionControlType cc_type) {
+ switch (cc_type) {
+ case kCubicBytes:
+ return "CUBIC_BYTES";
+ case kRenoBytes:
+ return "RENO_BYTES";
+ case kBBR:
+ return "BBR";
+ case kPCC:
+ return "PCC";
+ default:
+ QUIC_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;
+ }
+
+ const CongestionControlType congestion_control_type;
+};
+
+std::string TestParamToString(
+ const testing::TestParamInfo<TestParams>& params) {
+ return QuicStrCat(
+ 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, kCubicBytes, kRenoBytes, kPCC}) {
+ params.push_back(TestParams(congestion_control_type));
+ }
+ return params;
+}
+
+} // namespace
+
+class SendAlgorithmTest : public QuicTestWithParam<TestParams> {
+ protected:
+ SendAlgorithmTest()
+ : simulator_(),
+ quic_sender_(&simulator_,
+ "QUIC sender",
+ "Receiver",
+ Perspective::IS_CLIENT,
+ TestConnectionId()),
+ receiver_(&simulator_,
+ "Receiver",
+ "QUIC sender",
+ Perspective::IS_SERVER,
+ TestConnectionId()) {
+ rtt_stats_ = quic_sender_.connection()->sent_packet_manager().GetRttStats();
+ sender_ = SendAlgorithmInterface::Create(
+ simulator_.GetClock(), rtt_stats_,
+ QuicSentPacketManagerPeer::GetUnackedPacketMap(
+ QuicConnectionPeer::GetSentPacketManager(
+ quic_sender_.connection())),
+ GetParam().congestion_control_type, &random_, &stats_,
+ kInitialCongestionWindowPackets);
+ quic_sender_.RecordTrace();
+
+ QuicConnectionPeer::SetSendAlgorithm(quic_sender_.connection(), sender_);
+ clock_ = simulator_.GetClock();
+ simulator_.set_random_generator(&random_);
+
+ uint64_t seed = QuicRandom::GetInstance()->RandUint64();
+ random_.set_seed(seed);
+ QUIC_LOG(INFO) << "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_ = QuicMakeUnique<simulator::Switch>(&simulator_, "Switch", 8,
+ bottleneck_queue_length);
+ quic_sender_link_ = QuicMakeUnique<simulator::SymmetricLink>(
+ &quic_sender_, switch_->port(1), kLocalLinkBandwidth,
+ kLocalPropagationDelay);
+ receiver_link_ = QuicMakeUnique<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() {
+ const QuicConnectionStats& stats = quic_sender_.connection()->GetStats();
+ QUIC_LOG(INFO) << "Summary for scenario " << GetParam();
+ QUIC_LOG(INFO) << "Sender stats is " << stats;
+ const double rtx_rate =
+ static_cast<double>(stats.bytes_retransmitted) / stats.bytes_sent;
+ QUIC_LOG(INFO) << "Retransmit rate (num_rtx/num_total_sent): " << rtx_rate;
+ QUIC_LOG(INFO) << "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_SUITE_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 = 12 * 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();
+}
+
+TEST_P(SendAlgorithmTest, LowRTTTransfer) {
+ CreateSetup(kTestLinkWiredBandwidth, kTestLinkSmallRTTDelay, kCellularQueue);
+
+ const QuicByteCount kTransferSizeBytes = 12 * 1024 * 1024;
+ const QuicTime::Delta maximum_elapsed_time =
+ EstimatedElapsedTime(kTransferSizeBytes, kTestLinkWiredBandwidth,
+ kTestLinkSmallRTTDelay) *
+ 1.2;
+ DoSimpleTransfer(kTransferSizeBytes, maximum_elapsed_time);
+ PrintTransferStats();
+}
+
+} // namespace test
+} // namespace quic