blob: 037432032cd2312b4b3db18eb0d17b2818030e53 [file] [log] [blame]
Robin Lee2cf56172016-09-13 18:55:42 +09001/*
2 * Copyright (C) 2016 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#define LOG_TAG "connect_benchmark"
18
Robin Lee711237c2016-11-07 19:55:00 +000019/*
20 * See README.md for general notes.
21 *
22 * This set of benchmarks measures the throughput of connect() calls on a single thread for IPv4 and
Bernie Innocenticd257642018-12-20 15:56:40 +090023 * IPv6.
Robin Lee711237c2016-11-07 19:55:00 +000024 *
25 * Realtime timed tests
26 * ====================
27 *
28 * The tests named *_high_load record the following useful information:
29 *
30 * - real_time: the mean roundtrip time for one connect() call under load
31 *
32 * - iterations: the number of times the test was run within the timelimit --- approximately
33 * MinTime / real_time
34 *
35 * Manually timed tests
36 * ====================
37 *
38 * All other sets of tests apart from *_high_load run with manual timing. The purpose of these is to
39 * measure 90th-percentile latency for connect() calls compared to mean latency.
40 *
41 * (TODO: ideally this should be against median latency, but google-benchmark only supports one
42 * custom 'label' output for graphing. Stddev isn't appropriate because the latency
43 * distribution is usually spiky, not in a nice neat normal-like distribution.)
44 *
45 * The manually timed tests record the following useful information:
46 *
47 * - real_time: the average time taken to complete a test run. Unlike the real_time used in high
48 * load tests, this is calculated from before-and-after values of the realtime clock
49 * over many iterations so may be less accurate than the under-load times.
50 *
51 * - iterations: the number of times the test was run within the timelimit --- approximately
52 * MinTime / real_time, although as explained, may not be as meaningful because of
53 * overhead from timing.
54 *
55 * - label: a manually-recorded time giving the 90th-percentile value of real_time over all
56 * individual runs. Should be compared to real_time.
57 *
58 */
59
Robin Lee2cf56172016-09-13 18:55:42 +090060#include <arpa/inet.h>
61#include <cutils/sockets.h>
62#include <errno.h>
63#include <netinet/in.h>
64#include <time.h>
65
66#include <map>
67#include <functional>
68#include <thread>
69
70#include <android-base/stringprintf.h>
71#include <benchmark/benchmark.h>
72#include <log/log.h>
73#include <utils/StrongPointer.h>
74
75#include "FwmarkClient.h"
76#include "SockDiag.h"
77#include "Stopwatch.h"
Michal Karpinskid46aa712016-10-13 10:04:36 +010078#include "android/net/metrics/INetdEventListener.h"
Robin Lee2cf56172016-09-13 18:55:42 +090079
80using android::base::StringPrintf;
Michal Karpinskid46aa712016-10-13 10:04:36 +010081using android::net::metrics::INetdEventListener;
Robin Lee2cf56172016-09-13 18:55:42 +090082
83static int bindAndListen(int s) {
84 sockaddr_in6 sin6 = { .sin6_family = AF_INET6 };
85 if (bind(s, (sockaddr*) &sin6, sizeof(sin6)) == 0) {
86 if (listen(s, 1)) {
87 return -1;
88 }
89 sockaddr_in sin = {};
90 socklen_t len = sizeof(sin);
91 if (getsockname(s, (sockaddr*) &sin, &len)) {
92 return -1;
93 }
94 return ntohs(sin.sin_port);
95 } else {
96 return -1;
97 }
98}
99
100static void ipv4_loopback(benchmark::State& state, const bool waitBetweenRuns) {
Erik Klineab999f12018-07-04 11:29:31 +0900101 const int listensocket = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
Robin Lee2cf56172016-09-13 18:55:42 +0900102 const int port = bindAndListen(listensocket);
103 if (port == -1) {
104 state.SkipWithError("Unable to bind server socket");
105 return;
106 }
107
108 // ALOGW("Listening on port = %d", port);
109 std::vector<uint64_t> latencies(state.max_iterations);
110 uint64_t iterations = 0;
111
112 while (state.KeepRunning()) {
Erik Klineab999f12018-07-04 11:29:31 +0900113 int sock = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
Robin Lee2cf56172016-09-13 18:55:42 +0900114 if (sock < 0) {
115 state.SkipWithError(StringPrintf("socket() failed with errno=%d", errno).c_str());
116 break;
117 }
118
119 const Stopwatch stopwatch;
120
121 sockaddr_in server = { .sin_family = AF_INET, .sin_port = htons(port) };
Robin Leee65244b2016-12-01 19:03:33 +0000122 if (connect(sock, (sockaddr*) &server, sizeof(server))) {
Robin Lee2cf56172016-09-13 18:55:42 +0900123 state.SkipWithError(StringPrintf("connect() failed with errno=%d", errno).c_str());
124 close(sock);
125 break;
126 }
127
128 if (waitBetweenRuns) {
129 latencies[iterations] = stopwatch.timeTaken() * 1e6L;
130 state.SetIterationTime(latencies[iterations] / 1e9L);
131 std::this_thread::sleep_for(std::chrono::milliseconds(10));
132 ++iterations;
133 }
134
135 sockaddr_in6 client;
136 socklen_t clientlen = sizeof(client);
Erik Klineab999f12018-07-04 11:29:31 +0900137 int accepted = accept4(listensocket, (sockaddr*) &client, &clientlen, SOCK_CLOEXEC);
Robin Lee2cf56172016-09-13 18:55:42 +0900138 if (accepted < 0) {
139 state.SkipWithError(StringPrintf("accept() failed with errno=%d", errno).c_str());
140 close(sock);
141 break;
142 }
143
144 close(accepted);
145 close(sock);
146 }
147 close(listensocket);
148 // ALOGI("Finished test on port = %d", port);
149
150 if (iterations > 0) {
151 latencies.resize(iterations);
152 sort(latencies.begin(), latencies.end());
Chih-hung Hsieh03d6f382017-06-21 20:27:48 +0000153 state.SetLabel(StringPrintf("%lld", (long long) latencies[iterations * 9 / 10]));
Robin Lee2cf56172016-09-13 18:55:42 +0900154 }
155}
156
157static void ipv6_loopback(benchmark::State& state, const bool waitBetweenRuns) {
Erik Klineab999f12018-07-04 11:29:31 +0900158 const int listensocket = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
Robin Lee2cf56172016-09-13 18:55:42 +0900159 const int port = bindAndListen(listensocket);
160 if (port == -1) {
161 state.SkipWithError("Unable to bind server socket");
162 return;
163 }
164
165 // ALOGW("Listening on port = %d", port);
166 std::vector<uint64_t> latencies(state.max_iterations);
167 uint64_t iterations = 0;
168
169 while (state.KeepRunning()) {
Erik Klineab999f12018-07-04 11:29:31 +0900170 int sock = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
Robin Lee2cf56172016-09-13 18:55:42 +0900171 if (sock < 0) {
172 state.SkipWithError(StringPrintf("socket() failed with errno=%d", errno).c_str());
173 break;
174 }
175
176 const Stopwatch stopwatch;
177
178 sockaddr_in6 server = { .sin6_family = AF_INET6, .sin6_port = htons(port) };
Robin Leee65244b2016-12-01 19:03:33 +0000179 if (connect(sock, (sockaddr*) &server, sizeof(server))) {
Robin Lee2cf56172016-09-13 18:55:42 +0900180 state.SkipWithError(StringPrintf("connect() failed with errno=%d", errno).c_str());
181 close(sock);
182 break;
183 }
184
185 if (waitBetweenRuns) {
186 latencies[iterations] = stopwatch.timeTaken() * 1e6L;
187 state.SetIterationTime(latencies[iterations] / 1e9L);
188 std::this_thread::sleep_for(std::chrono::milliseconds(10));
189 ++iterations;
190 }
191
192 sockaddr_in6 client;
193 socklen_t clientlen = sizeof(client);
Erik Klineab999f12018-07-04 11:29:31 +0900194 int accepted = accept4(listensocket, (sockaddr*) &client, &clientlen, SOCK_CLOEXEC);
Robin Lee2cf56172016-09-13 18:55:42 +0900195 if (accepted < 0) {
196 state.SkipWithError(StringPrintf("accept() failed with errno=%d", errno).c_str());
197 close(sock);
198 break;
199 }
200
201 close(accepted);
202 close(sock);
203 }
204 close(listensocket);
205 // ALOGI("Finished test on port = %d", port);
206
207 if (iterations > 0) {
208 latencies.resize(iterations);
209 sort(latencies.begin(), latencies.end());
Chih-hung Hsieh03d6f382017-06-21 20:27:48 +0000210 state.SetLabel(StringPrintf("%lld", (long long) latencies[iterations * 9 / 10]));
Robin Lee2cf56172016-09-13 18:55:42 +0900211 }
212}
213
Bernie Innocenticd257642018-12-20 15:56:40 +0900214static void run(decltype(ipv4_loopback) benchmarkFunction, ::benchmark::State& state,
215 const bool waitBetweenRuns) {
Robin Lee2cf56172016-09-13 18:55:42 +0900216 benchmarkFunction(state, waitBetweenRuns);
Robin Lee2cf56172016-09-13 18:55:42 +0900217}
218
219constexpr int MIN_THREADS = 1;
220constexpr int MAX_THREADS = 1;
221constexpr double MIN_TIME = 0.5 /* seconds */;
222
Bernie Innocenticd257642018-12-20 15:56:40 +0900223// IPv4 benchmarks under no load
224static void ipv4_no_load(::benchmark::State& state) {
225 run(ipv4_loopback, state, true);
Robin Lee2cf56172016-09-13 18:55:42 +0900226}
Bernie Innocenticd257642018-12-20 15:56:40 +0900227BENCHMARK(ipv4_no_load)->MinTime(MIN_TIME)->UseManualTime();
Robin Lee2cf56172016-09-13 18:55:42 +0900228
229// IPv4 benchmarks under high load
Bernie Innocenticd257642018-12-20 15:56:40 +0900230static void ipv4_high_load(::benchmark::State& state) {
231 run(ipv4_loopback, state, false);
Robin Lee2cf56172016-09-13 18:55:42 +0900232}
Bernie Innocenticd257642018-12-20 15:56:40 +0900233BENCHMARK(ipv4_high_load)->ThreadRange(MIN_THREADS, MAX_THREADS)->MinTime(MIN_TIME)->UseRealTime();
Robin Lee2cf56172016-09-13 18:55:42 +0900234
235// IPv6 raw connect() without using fwmark
Bernie Innocenticd257642018-12-20 15:56:40 +0900236static void ipv6_no_load(::benchmark::State& state) {
237 run(ipv6_loopback, state, true);
Robin Lee2cf56172016-09-13 18:55:42 +0900238}
Bernie Innocenticd257642018-12-20 15:56:40 +0900239BENCHMARK(ipv6_no_load)->MinTime(MIN_TIME)->UseManualTime();
Robin Lee2cf56172016-09-13 18:55:42 +0900240
241// IPv6 benchmarks under high load
Bernie Innocenticd257642018-12-20 15:56:40 +0900242static void ipv6_high_load(::benchmark::State& state) {
243 run(ipv6_loopback, state, false);
Robin Lee2cf56172016-09-13 18:55:42 +0900244}
Bernie Innocenticd257642018-12-20 15:56:40 +0900245BENCHMARK(ipv6_high_load)->ThreadRange(MIN_THREADS, MAX_THREADS)->MinTime(MIN_TIME)->UseRealTime();