159 lines
5.4 KiB
C++
159 lines
5.4 KiB
C++
// Copyright 2015 The Chromium Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "base/functional/bind.h"
|
|
#include "base/memory/weak_ptr.h"
|
|
#include "base/run_loop.h"
|
|
#include "base/test/task_environment.h"
|
|
#include "base/timer/elapsed_timer.h"
|
|
#include "net/base/io_buffer.h"
|
|
#include "net/base/ip_endpoint.h"
|
|
#include "net/base/net_errors.h"
|
|
#include "net/base/test_completion_callback.h"
|
|
#include "net/log/net_log_source.h"
|
|
#include "net/socket/udp_client_socket.h"
|
|
#include "net/socket/udp_server_socket.h"
|
|
#include "net/socket/udp_socket.h"
|
|
#include "net/test/gtest_util.h"
|
|
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
|
|
#include "testing/gmock/include/gmock/gmock.h"
|
|
#include "testing/gtest/include/gtest/gtest.h"
|
|
#include "testing/perf/perf_result_reporter.h"
|
|
#include "testing/platform_test.h"
|
|
|
|
using net::test::IsOk;
|
|
|
|
namespace net {
|
|
|
|
namespace {
|
|
|
|
static constexpr char kMetricPrefixUDPSocket[] = "UDPSocketWrite.";
|
|
static constexpr char kMetricElapsedTimeMs[] = "elapsed_time";
|
|
static constexpr char kMetricWriteSpeedBytesPerSecond[] = "write_speed";
|
|
|
|
perf_test::PerfResultReporter SetUpUDPSocketReporter(const std::string& story) {
|
|
perf_test::PerfResultReporter reporter(kMetricPrefixUDPSocket, story);
|
|
reporter.RegisterImportantMetric(kMetricElapsedTimeMs, "ms");
|
|
reporter.RegisterImportantMetric(kMetricWriteSpeedBytesPerSecond,
|
|
"bytesPerSecond_biggerIsBetter");
|
|
return reporter;
|
|
}
|
|
|
|
class UDPSocketPerfTest : public PlatformTest {
|
|
public:
|
|
UDPSocketPerfTest()
|
|
: buffer_(base::MakeRefCounted<IOBufferWithSize>(kPacketSize)) {}
|
|
|
|
void DoneWritePacketsToSocket(UDPClientSocket* socket,
|
|
int num_of_packets,
|
|
base::OnceClosure* done_callback,
|
|
int error) {
|
|
WritePacketsToSocket(socket, num_of_packets, done_callback);
|
|
}
|
|
|
|
// Send |num_of_packets| to |socket|. Invoke |done_callback| when done.
|
|
void WritePacketsToSocket(UDPClientSocket* socket,
|
|
int num_of_packets,
|
|
base::OnceClosure* done_callback);
|
|
|
|
// Use non-blocking IO if |use_nonblocking_io| is true. This variable only
|
|
// has effect on Windows.
|
|
void WriteBenchmark(bool use_nonblocking_io);
|
|
|
|
protected:
|
|
static const int kPacketSize = 1024;
|
|
scoped_refptr<IOBufferWithSize> buffer_;
|
|
base::WeakPtrFactory<UDPSocketPerfTest> weak_factory_{this};
|
|
};
|
|
|
|
const int UDPSocketPerfTest::kPacketSize;
|
|
|
|
// Creates and address from an ip/port and returns it in |address|.
|
|
void CreateUDPAddress(const std::string& ip_str,
|
|
uint16_t port,
|
|
IPEndPoint* address) {
|
|
IPAddress ip_address;
|
|
if (!ip_address.AssignFromIPLiteral(ip_str))
|
|
return;
|
|
*address = IPEndPoint(ip_address, port);
|
|
}
|
|
|
|
void UDPSocketPerfTest::WritePacketsToSocket(UDPClientSocket* socket,
|
|
int num_of_packets,
|
|
base::OnceClosure* done_callback) {
|
|
scoped_refptr<IOBufferWithSize> io_buffer =
|
|
base::MakeRefCounted<IOBufferWithSize>(kPacketSize);
|
|
memset(io_buffer->data(), 'G', kPacketSize);
|
|
|
|
while (num_of_packets) {
|
|
int rv = socket->Write(
|
|
io_buffer.get(), io_buffer->size(),
|
|
base::BindOnce(&UDPSocketPerfTest::DoneWritePacketsToSocket,
|
|
weak_factory_.GetWeakPtr(), socket, num_of_packets - 1,
|
|
done_callback),
|
|
TRAFFIC_ANNOTATION_FOR_TESTS);
|
|
if (rv == ERR_IO_PENDING)
|
|
break;
|
|
--num_of_packets;
|
|
}
|
|
if (!num_of_packets) {
|
|
std::move(*done_callback).Run();
|
|
return;
|
|
}
|
|
}
|
|
|
|
void UDPSocketPerfTest::WriteBenchmark(bool use_nonblocking_io) {
|
|
base::ElapsedTimer total_elapsed_timer;
|
|
base::test::SingleThreadTaskEnvironment task_environment(
|
|
base::test::SingleThreadTaskEnvironment::MainThreadType::IO);
|
|
const uint16_t kPort = 9999;
|
|
|
|
// Setup the server to listen.
|
|
IPEndPoint bind_address;
|
|
CreateUDPAddress("127.0.0.1", kPort, &bind_address);
|
|
auto server = std::make_unique<UDPServerSocket>(nullptr, NetLogSource());
|
|
if (use_nonblocking_io)
|
|
server->UseNonBlockingIO();
|
|
int rv = server->Listen(bind_address);
|
|
ASSERT_THAT(rv, IsOk());
|
|
|
|
// Setup the client.
|
|
IPEndPoint server_address;
|
|
CreateUDPAddress("127.0.0.1", kPort, &server_address);
|
|
auto client = std::make_unique<UDPClientSocket>(DatagramSocket::DEFAULT_BIND,
|
|
nullptr, NetLogSource());
|
|
if (use_nonblocking_io)
|
|
client->UseNonBlockingIO();
|
|
rv = client->Connect(server_address);
|
|
EXPECT_THAT(rv, IsOk());
|
|
|
|
base::RunLoop run_loop;
|
|
base::OnceClosure done_callback = run_loop.QuitClosure();
|
|
base::ElapsedTimer write_elapsed_timer;
|
|
int packets = 100000;
|
|
client->SetSendBufferSize(1024);
|
|
WritePacketsToSocket(client.get(), packets, &done_callback);
|
|
run_loop.Run();
|
|
|
|
double write_elapsed = write_elapsed_timer.Elapsed().InSecondsF();
|
|
double total_elapsed = total_elapsed_timer.Elapsed().InMillisecondsF();
|
|
auto reporter =
|
|
SetUpUDPSocketReporter(use_nonblocking_io ? "nonblocking" : "blocking");
|
|
reporter.AddResult(kMetricElapsedTimeMs, total_elapsed);
|
|
reporter.AddResult(kMetricWriteSpeedBytesPerSecond,
|
|
packets * 1024 / write_elapsed);
|
|
}
|
|
|
|
TEST_F(UDPSocketPerfTest, Write) {
|
|
WriteBenchmark(false);
|
|
}
|
|
|
|
TEST_F(UDPSocketPerfTest, WriteNonBlocking) {
|
|
WriteBenchmark(true);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
} // namespace net
|