|  | // 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/bidi_test_runner.h" | 
|  |  | 
|  | #include "net/third_party/quiche/src/quic/quartc/test/quartc_peer.h" | 
|  |  | 
|  | namespace quic { | 
|  | namespace test { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | 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; | 
|  | QUIC_VLOG(1) << "Frame details: source_id=" << message.frame.source_id | 
|  | << ", sequence_number=" << message.frame.sequence_number | 
|  | << ", one_way_delay (ms)=" << one_way_delay.ToMilliseconds(); | 
|  | 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() | 
|  | << "\n  fraction_lost=" << fraction_lost; | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | BidiTestRunner::BidiTestRunner(simulator::Simulator* simulator, | 
|  | QuartcPacketTransport* client_transport, | 
|  | QuartcPacketTransport* server_transport) | 
|  | : simulator_(simulator), | 
|  | client_transport_(client_transport), | 
|  | server_transport_(server_transport) { | 
|  | // Set up default data source configs. | 
|  | // Emulates an audio source with a 20 ms ptime. | 
|  | QuartcDataSource::Config audio; | 
|  | audio.id = 1; | 
|  | audio.frame_interval = QuicTime::Delta::FromMilliseconds(20); | 
|  | audio.min_bandwidth = QuicBandwidth::FromKBitsPerSecond(8); | 
|  | audio.max_bandwidth = QuicBandwidth::FromKBitsPerSecond(64); | 
|  |  | 
|  | // Emulates a video source at 30 fps. | 
|  | QuartcDataSource::Config video; | 
|  | video.id = 2; | 
|  | video.frame_interval = QuicTime::Delta::FromMicroseconds(33333); | 
|  | video.min_bandwidth = QuicBandwidth::FromKBitsPerSecond(25); | 
|  | video.max_bandwidth = QuicBandwidth::FromKBitsPerSecond(5000); | 
|  |  | 
|  | // Note: by placing audio first, it takes priority in bandwidth allocations. | 
|  | client_configs_.push_back(audio); | 
|  | client_configs_.push_back(video); | 
|  | server_configs_.push_back(audio); | 
|  | server_configs_.push_back(video); | 
|  | } | 
|  |  | 
|  | BidiTestRunner::~BidiTestRunner() { | 
|  | // Note that peers must be deleted before endpoints.  Peers close the | 
|  | // connection when deleted. | 
|  | client_peer_.reset(); | 
|  | server_peer_.reset(); | 
|  | } | 
|  |  | 
|  | bool BidiTestRunner::RunTest(QuicTime::Delta test_duration) { | 
|  | client_peer_ = QuicMakeUnique<QuartcPeer>( | 
|  | simulator_->GetClock(), simulator_->GetAlarmFactory(), | 
|  | simulator_->GetRandomGenerator(), | 
|  | simulator_->GetStreamSendBufferAllocator(), client_configs_); | 
|  | server_peer_ = QuicMakeUnique<QuartcPeer>( | 
|  | simulator_->GetClock(), simulator_->GetAlarmFactory(), | 
|  | simulator_->GetRandomGenerator(), | 
|  | simulator_->GetStreamSendBufferAllocator(), server_configs_); | 
|  |  | 
|  | QuartcEndpoint::Delegate* server_delegate = server_peer_.get(); | 
|  | if (server_interceptor_) { | 
|  | server_interceptor_->SetDelegate(server_delegate); | 
|  | server_delegate = server_interceptor_; | 
|  | } | 
|  | server_endpoint_ = QuicMakeUnique<QuartcServerEndpoint>( | 
|  | simulator_->GetAlarmFactory(), simulator_->GetClock(), | 
|  | simulator_->GetRandomGenerator(), server_delegate, QuartcSessionConfig()); | 
|  |  | 
|  | QuartcEndpoint::Delegate* client_delegate = client_peer_.get(); | 
|  | if (client_interceptor_) { | 
|  | client_interceptor_->SetDelegate(client_delegate); | 
|  | client_delegate = client_interceptor_; | 
|  | } | 
|  | client_endpoint_ = QuicMakeUnique<QuartcClientEndpoint>( | 
|  | simulator_->GetAlarmFactory(), simulator_->GetClock(), | 
|  | simulator_->GetRandomGenerator(), client_delegate, QuartcSessionConfig(), | 
|  | server_endpoint_->server_crypto_config()); | 
|  |  | 
|  | QuicTime start_time = simulator_->GetClock()->Now(); | 
|  | server_endpoint_->Connect(server_transport_); | 
|  | client_endpoint_->Connect(client_transport_); | 
|  |  | 
|  | // Measure connect latency. | 
|  | if (!simulator_->RunUntil([this] { return client_peer_->Enabled(); })) { | 
|  | return false; | 
|  | } | 
|  | QuicTime client_connected = simulator_->GetClock()->Now(); | 
|  | QuicTime::Delta client_connect_latency = client_connected - start_time; | 
|  |  | 
|  | if (!simulator_->RunUntil([this] { return server_peer_->Enabled(); })) { | 
|  | return false; | 
|  | } | 
|  | QuicTime server_connected = simulator_->GetClock()->Now(); | 
|  | QuicTime::Delta server_connect_latency = server_connected - start_time; | 
|  |  | 
|  | QUIC_LOG(INFO) << "Connect latencies (ms): client=" << client_connect_latency | 
|  | << ", server=" << server_connect_latency; | 
|  |  | 
|  | // Run the test. | 
|  | simulator_->RunFor(test_duration); | 
|  |  | 
|  | // Disable sending and drain. | 
|  | // Note that draining by waiting for the last sequence number sent may be | 
|  | // flaky if packet loss is enabled.  However, simulator-based tests don't | 
|  | // currently have any loss. | 
|  | server_peer_->SetEnabled(false); | 
|  | client_peer_->SetEnabled(false); | 
|  |  | 
|  | if (!simulator_->RunUntil([this] { return PacketsDrained(); })) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Compute results. | 
|  | QUIC_LOG(INFO) << "Printing client->server results:"; | 
|  | LogResults(server_peer_->received_messages(), | 
|  | client_peer_->GetLastSequenceNumbers()); | 
|  |  | 
|  | QUIC_LOG(INFO) << "Printing server->client results:"; | 
|  | 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 |