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_