Create a PacketFilter for random loss and use it in QuartcBidiTest. This sets up a second benchmark in QuartcBidiTest which runs at 300 kbps, with 200 ms propagation delay, but also includes 2% random packet loss. Random loss is one of the features required to bring Simulator-based BidiTestRunner tests in line with higher-level Quartc quality tests. Those tests typically use 2-8% random loss, depending on the network profile. gfe-relnote: n/a (Quartc tests only) PiperOrigin-RevId: 244062413 Change-Id: Ic7cfc9b7e8c2b5339c8e1a25d7583b8cf156c870
diff --git a/quic/quartc/test/bidi_test_runner.cc b/quic/quartc/test/bidi_test_runner.cc index ebd6d33..b185db6 100644 --- a/quic/quartc/test/bidi_test_runner.cc +++ b/quic/quartc/test/bidi_test_runner.cc
@@ -11,22 +11,12 @@ namespace { -bool ContainsSequenceNumbers(const std::vector<ReceivedMessage>& messages, - IdToSequenceNumberMap id_to_sequence_number) { - for (const auto& message : messages) { - auto it = id_to_sequence_number.find(message.frame.source_id); - if (it != id_to_sequence_number.end() && - it->second == message.frame.sequence_number) { - id_to_sequence_number.erase(it); - } - } - return id_to_sequence_number.empty(); -} - -void LogResults(const std::vector<ReceivedMessage>& messages) { +void LogResults(const std::vector<ReceivedMessage>& messages, + IdToSequenceNumberMap sent_sequence_numbers) { QuicTime::Delta max_delay = QuicTime::Delta::Zero(); QuicTime::Delta total_delay = QuicTime::Delta::Zero(); QuicByteCount total_throughput = 0; + int64_t messages_received = 0; for (const auto& message : messages) { QuicTime::Delta one_way_delay = message.receive_time - message.frame.send_time; @@ -36,16 +26,28 @@ max_delay = std::max(max_delay, one_way_delay); total_delay = total_delay + one_way_delay; total_throughput += message.frame.size; + ++messages_received; } + + int64_t messages_expected = 0; + for (const auto& it : sent_sequence_numbers) { + // Sequence numbers start at zero, so add one to the last sequence number + // to get the expected number of messages. + messages_expected += it.second + 1; + } + QuicBandwidth total_bandwidth = QuicBandwidth::FromBytesAndTimeDelta( total_throughput, messages.back().receive_time - messages.front().receive_time); + double fraction_lost = + 1.0 - static_cast<double>(messages_received) / messages_expected; QUIC_LOG(INFO) << "Summary:\n max_delay (ms)=" << max_delay.ToMilliseconds() << "\n average_delay (ms)=" << total_delay.ToMilliseconds() / messages.size() << "\n total_throughput (bytes)=" << total_throughput << "\n total_bandwidth (bps)=" - << total_bandwidth.ToBitsPerSecond(); + << total_bandwidth.ToBitsPerSecond() + << "\n fraction_lost=" << fraction_lost; } } // namespace @@ -141,30 +143,45 @@ server_peer_->SetEnabled(false); client_peer_->SetEnabled(false); - IdToSequenceNumberMap sent_by_server = server_peer_->GetLastSequenceNumbers(); - if (!simulator_->RunUntil([this, &sent_by_server] { - return ContainsSequenceNumbers(client_peer_->received_messages(), - sent_by_server); - })) { - return false; - } - - IdToSequenceNumberMap sent_by_client = client_peer_->GetLastSequenceNumbers(); - if (!simulator_->RunUntil([this, &sent_by_client] { - return ContainsSequenceNumbers(server_peer_->received_messages(), - sent_by_client); - })) { + if (!simulator_->RunUntil([this] { return PacketsDrained(); })) { return false; } // Compute results. QUIC_LOG(INFO) << "Printing client->server results:"; - LogResults(server_peer_->received_messages()); + LogResults(server_peer_->received_messages(), + client_peer_->GetLastSequenceNumbers()); QUIC_LOG(INFO) << "Printing server->client results:"; - LogResults(client_peer_->received_messages()); + LogResults(client_peer_->received_messages(), + server_peer_->GetLastSequenceNumbers()); return true; } +bool BidiTestRunner::PacketsDrained() { + const ReceivedMessage& last_server_message = + server_peer_->received_messages().back(); + const ReceivedMessage& last_client_message = + client_peer_->received_messages().back(); + + // Last observed propagation delay on the client -> server path. + QuicTime::Delta last_client_server_delay = + last_server_message.receive_time - last_server_message.frame.send_time; + + // Last observed propagation delay on the server -> client path. + QuicTime::Delta last_server_client_delay = + last_client_message.receive_time - last_client_message.frame.send_time; + + // Last observed RTT based on the propagation delays above. + QuicTime::Delta last_rtt = + last_client_server_delay + last_server_client_delay; + + // If nothing interesting has happened for at least one RTT, then it's + // unlikely anything is still in flight. + QuicTime now = simulator_->GetClock()->Now(); + return now - last_server_message.receive_time > last_rtt && + now - last_client_message.receive_time > last_rtt; +} + } // namespace test } // namespace quic
diff --git a/quic/quartc/test/bidi_test_runner.h b/quic/quartc/test/bidi_test_runner.h index b76695a..4369e22 100644 --- a/quic/quartc/test/bidi_test_runner.h +++ b/quic/quartc/test/bidi_test_runner.h
@@ -76,6 +76,9 @@ virtual bool RunTest(QuicTime::Delta test_duration); private: + // Returns true when no pending packets are believed to be in-flight. + bool PacketsDrained(); + simulator::Simulator* simulator_; QuartcPacketTransport* client_transport_; QuartcPacketTransport* server_transport_;
diff --git a/quic/quartc/test/quartc_bidi_test.cc b/quic/quartc/test/quartc_bidi_test.cc index 5c0e234..db9972c 100644 --- a/quic/quartc/test/quartc_bidi_test.cc +++ b/quic/quartc/test/quartc_bidi_test.cc
@@ -11,6 +11,7 @@ #include "net/third_party/quiche/src/quic/platform/api/quic_test.h" #include "net/third_party/quiche/src/quic/quartc/simulated_packet_transport.h" #include "net/third_party/quiche/src/quic/quartc/test/bidi_test_runner.h" +#include "net/third_party/quiche/src/quic/quartc/test/random_packet_filter.h" #include "net/third_party/quiche/src/quic/test_tools/simulator/link.h" #include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" @@ -24,29 +25,47 @@ void CreateTransports(QuicBandwidth bandwidth, QuicTime::Delta propagation_delay, - QuicByteCount queue_length) { + QuicByteCount queue_length, + int loss_percent) { client_transport_ = QuicMakeUnique<simulator::SimulatedQuartcPacketTransport>( &simulator_, "client_transport", "server_transport", queue_length); server_transport_ = QuicMakeUnique<simulator::SimulatedQuartcPacketTransport>( &simulator_, "server_transport", "client_transport", queue_length); + client_filter_ = QuicMakeUnique<simulator::RandomPacketFilter>( + &simulator_, "client_filter", client_transport_.get()); + server_filter_ = QuicMakeUnique<simulator::RandomPacketFilter>( + &simulator_, "server_filter", server_transport_.get()); client_server_link_ = QuicMakeUnique<simulator::SymmetricLink>( - client_transport_.get(), server_transport_.get(), bandwidth, + client_filter_.get(), server_filter_.get(), bandwidth, propagation_delay); + client_filter_->set_loss_percent(loss_percent); + server_filter_->set_loss_percent(loss_percent); } simulator::Simulator simulator_; std::unique_ptr<simulator::SimulatedQuartcPacketTransport> client_transport_; std::unique_ptr<simulator::SimulatedQuartcPacketTransport> server_transport_; + std::unique_ptr<simulator::RandomPacketFilter> client_filter_; + std::unique_ptr<simulator::RandomPacketFilter> server_filter_; std::unique_ptr<simulator::SymmetricLink> client_server_link_; }; TEST_F(QuartcBidiTest, Basic300kbps200ms) { CreateTransports(QuicBandwidth::FromKBitsPerSecond(300), QuicTime::Delta::FromMilliseconds(200), - 10 * kDefaultMaxPacketSize); + 10 * kDefaultMaxPacketSize, /*loss_percent=*/0); + BidiTestRunner runner(&simulator_, client_transport_.get(), + server_transport_.get()); + EXPECT_TRUE(runner.RunTest(QuicTime::Delta::FromSeconds(30))); +} + +TEST_F(QuartcBidiTest, 300kbps200ms2PercentLoss) { + CreateTransports(QuicBandwidth::FromKBitsPerSecond(300), + QuicTime::Delta::FromMilliseconds(200), + 10 * kDefaultMaxPacketSize, /*loss_percent=*/2); BidiTestRunner runner(&simulator_, client_transport_.get(), server_transport_.get()); EXPECT_TRUE(runner.RunTest(QuicTime::Delta::FromSeconds(30)));
diff --git a/quic/quartc/test/random_packet_filter.cc b/quic/quartc/test/random_packet_filter.cc new file mode 100644 index 0000000..2fb160e --- /dev/null +++ b/quic/quartc/test/random_packet_filter.cc
@@ -0,0 +1,23 @@ +// Copyright (c) 2019 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 "net/third_party/quiche/src/quic/quartc/test/random_packet_filter.h" + +namespace quic { +namespace simulator { + +RandomPacketFilter::RandomPacketFilter(Simulator* simulator, + const std::string& name, + Endpoint* endpoint) + : PacketFilter(simulator, name, endpoint), simulator_(simulator) {} + +bool RandomPacketFilter::FilterPacket(const Packet& packet) { + uint64_t random = simulator_->GetRandomGenerator()->RandUint64(); + return 100 * static_cast<double>(random) / + std::numeric_limits<uint64_t>::max() >= + loss_percent_; +} + +} // namespace simulator +} // namespace quic
diff --git a/quic/quartc/test/random_packet_filter.h b/quic/quartc/test/random_packet_filter.h new file mode 100644 index 0000000..b97d498 --- /dev/null +++ b/quic/quartc/test/random_packet_filter.h
@@ -0,0 +1,39 @@ +// Copyright (c) 2019 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. + +#ifndef QUICHE_QUIC_QUARTC_TEST_RANDOM_PACKET_FILTER_H_ +#define QUICHE_QUIC_QUARTC_TEST_RANDOM_PACKET_FILTER_H_ + +#include "net/third_party/quiche/src/quic/test_tools/simulator/packet_filter.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/port.h" +#include "net/third_party/quiche/src/quic/test_tools/simulator/simulator.h" + +namespace quic { +namespace simulator { + +// Packet filter which randomly drops packets. +class RandomPacketFilter : public PacketFilter { + public: + RandomPacketFilter(Simulator* simulator, + const std::string& name, + Endpoint* endpoint); + + void set_loss_percent(double loss_percent) { + DCHECK_GE(loss_percent, 0); + DCHECK_LE(loss_percent, 100); + loss_percent_ = loss_percent; + } + + protected: + bool FilterPacket(const Packet& packet) override; + + private: + Simulator* simulator_; + double loss_percent_ = 0; +}; + +} // namespace simulator +} // namespace quic + +#endif // QUICHE_QUIC_QUARTC_TEST_RANDOM_PACKET_FILTER_H_