1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <malloc.h>
18 #include <stdio.h>
19
20 #include <android-base/logging.h>
21 #include <benchmark/benchmark.h>
22
23 #include "adb_trace.h"
24 #include "sysdeps.h"
25 #include "transport.h"
26
27 #define ADB_CONNECTION_BENCHMARK(benchmark_name, ...) \
28 BENCHMARK_TEMPLATE(benchmark_name, FdConnection, ##__VA_ARGS__) \
29 ->Arg(1) \
30 ->Arg(16384) \
31 ->Arg(MAX_PAYLOAD) \
32 ->UseRealTime(); \
33 BENCHMARK_TEMPLATE(benchmark_name, NonblockingFdConnection, ##__VA_ARGS__) \
34 ->Arg(1) \
35 ->Arg(16384) \
36 ->Arg(MAX_PAYLOAD) \
37 ->UseRealTime()
38
39 struct NonblockingFdConnection;
40 template <typename ConnectionType>
41 std::unique_ptr<Connection> MakeConnection(unique_fd fd);
42
43 template <>
MakeConnection(unique_fd fd)44 std::unique_ptr<Connection> MakeConnection<FdConnection>(unique_fd fd) {
45 auto fd_connection = std::make_unique<FdConnection>(std::move(fd));
46 return std::make_unique<BlockingConnectionAdapter>(std::move(fd_connection));
47 }
48
49 template <>
MakeConnection(unique_fd fd)50 std::unique_ptr<Connection> MakeConnection<NonblockingFdConnection>(unique_fd fd) {
51 return Connection::FromFd(std::move(fd));
52 }
53
54 template <typename ConnectionType>
BM_Connection_Unidirectional(benchmark::State & state)55 void BM_Connection_Unidirectional(benchmark::State& state) {
56 int fds[2];
57 if (adb_socketpair(fds) != 0) {
58 LOG(FATAL) << "failed to create socketpair";
59 }
60
61 auto client = MakeConnection<ConnectionType>(unique_fd(fds[0]));
62 auto server = MakeConnection<ConnectionType>(unique_fd(fds[1]));
63
64 std::atomic<size_t> received_bytes;
65
66 client->SetReadCallback([](Connection*, std::unique_ptr<apacket>) -> bool { return true; });
67 server->SetReadCallback([&received_bytes](Connection*, std::unique_ptr<apacket> packet) -> bool {
68 received_bytes += packet->payload.size();
69 return true;
70 });
71
72 client->SetErrorCallback(
73 [](Connection*, const std::string& error) { LOG(INFO) << "client closed: " << error; });
74 server->SetErrorCallback(
75 [](Connection*, const std::string& error) { LOG(INFO) << "server closed: " << error; });
76
77 client->Start();
78 server->Start();
79
80 for (auto _ : state) {
81 size_t data_size = state.range(0);
82 std::unique_ptr<apacket> packet = std::make_unique<apacket>();
83 memset(&packet->msg, 0, sizeof(packet->msg));
84 packet->msg.command = A_WRTE;
85 packet->msg.data_length = data_size;
86 packet->payload.resize(data_size);
87
88 memset(&packet->payload[0], 0xff, data_size);
89
90 received_bytes = 0;
91 client->Write(std::move(packet));
92 while (received_bytes < data_size) {
93 continue;
94 }
95 }
96 state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * state.range(0));
97
98 client->Stop();
99 server->Stop();
100 }
101
102 ADB_CONNECTION_BENCHMARK(BM_Connection_Unidirectional);
103
104 enum class ThreadPolicy {
105 MainThread,
106 SameThread,
107 };
108
109 template <typename ConnectionType, enum ThreadPolicy Policy>
BM_Connection_Echo(benchmark::State & state)110 void BM_Connection_Echo(benchmark::State& state) {
111 int fds[2];
112 if (adb_socketpair(fds) != 0) {
113 LOG(FATAL) << "failed to create socketpair";
114 }
115
116 auto client = MakeConnection<ConnectionType>(unique_fd(fds[0]));
117 auto server = MakeConnection<ConnectionType>(unique_fd(fds[1]));
118
119 std::atomic<size_t> received_bytes;
120
121 fdevent_reset();
122 std::thread fdevent_thread([]() { fdevent_loop(); });
123
124 client->SetReadCallback([&received_bytes](Connection*, std::unique_ptr<apacket> packet) -> bool {
125 received_bytes += packet->payload.size();
126 return true;
127 });
128
129 static const auto handle_packet = [](Connection* connection, std::unique_ptr<apacket> packet) {
130 connection->Write(std::move(packet));
131 };
132
133 server->SetReadCallback([](Connection* connection, std::unique_ptr<apacket> packet) -> bool {
134 if (Policy == ThreadPolicy::MainThread) {
135 auto raw_packet = packet.release();
136 fdevent_run_on_main_thread([connection, raw_packet]() {
137 std::unique_ptr<apacket> packet(raw_packet);
138 handle_packet(connection, std::move(packet));
139 });
140 } else {
141 handle_packet(connection, std::move(packet));
142 }
143 return true;
144 });
145
146 client->SetErrorCallback(
147 [](Connection*, const std::string& error) { LOG(INFO) << "client closed: " << error; });
148 server->SetErrorCallback(
149 [](Connection*, const std::string& error) { LOG(INFO) << "server closed: " << error; });
150
151 client->Start();
152 server->Start();
153
154 for (auto _ : state) {
155 size_t data_size = state.range(0);
156 std::unique_ptr<apacket> packet = std::make_unique<apacket>();
157 memset(&packet->msg, 0, sizeof(packet->msg));
158 packet->msg.command = A_WRTE;
159 packet->msg.data_length = data_size;
160 packet->payload.resize(data_size);
161
162 memset(&packet->payload[0], 0xff, data_size);
163
164 received_bytes = 0;
165 client->Write(std::move(packet));
166 while (received_bytes < data_size) {
167 continue;
168 }
169 }
170 state.SetBytesProcessed(static_cast<int64_t>(state.iterations()) * state.range(0));
171
172 client->Stop();
173 server->Stop();
174
175 // TODO: Make it so that you don't need to poke the fdevent loop to make it terminate?
176 fdevent_terminate_loop();
177 fdevent_run_on_main_thread([]() {});
178
179 fdevent_thread.join();
180 }
181
182 ADB_CONNECTION_BENCHMARK(BM_Connection_Echo, ThreadPolicy::SameThread);
183 ADB_CONNECTION_BENCHMARK(BM_Connection_Echo, ThreadPolicy::MainThread);
184
main(int argc,char ** argv)185 int main(int argc, char** argv) {
186 // Set M_DECAY_TIME so that our allocations aren't immediately purged on free.
187 mallopt(M_DECAY_TIME, 1);
188
189 android::base::SetMinimumLogSeverity(android::base::WARNING);
190 adb_trace_init(argv);
191 ::benchmark::Initialize(&argc, argv);
192 if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1;
193 ::benchmark::RunSpecifiedBenchmarks();
194 }
195