blob: ed9053873c47116f1829c5ea35485e8a4bdd144c [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>
Mike Yue7e332f2019-03-13 17:15:48 +080073#include <netdutils/Stopwatch.h>
Robin Lee2cf56172016-09-13 18:55:42 +090074#include <utils/StrongPointer.h>
75
76#include "FwmarkClient.h"
77#include "SockDiag.h"
Robin Lee2cf56172016-09-13 18:55:42 +090078
79using android::base::StringPrintf;
Mike Yue7e332f2019-03-13 17:15:48 +080080using android::netdutils::Stopwatch;
Robin Lee2cf56172016-09-13 18:55:42 +090081
82static int bindAndListen(int s) {
83 sockaddr_in6 sin6 = { .sin6_family = AF_INET6 };
84 if (bind(s, (sockaddr*) &sin6, sizeof(sin6)) == 0) {
85 if (listen(s, 1)) {
86 return -1;
87 }
88 sockaddr_in sin = {};
89 socklen_t len = sizeof(sin);
90 if (getsockname(s, (sockaddr*) &sin, &len)) {
91 return -1;
92 }
93 return ntohs(sin.sin_port);
94 } else {
95 return -1;
96 }
97}
98
99static void ipv4_loopback(benchmark::State& state, const bool waitBetweenRuns) {
Erik Klineab999f12018-07-04 11:29:31 +0900100 const int listensocket = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
Robin Lee2cf56172016-09-13 18:55:42 +0900101 const int port = bindAndListen(listensocket);
102 if (port == -1) {
103 state.SkipWithError("Unable to bind server socket");
104 return;
105 }
106
107 // ALOGW("Listening on port = %d", port);
108 std::vector<uint64_t> latencies(state.max_iterations);
109 uint64_t iterations = 0;
110
111 while (state.KeepRunning()) {
Erik Klineab999f12018-07-04 11:29:31 +0900112 int sock = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
Robin Lee2cf56172016-09-13 18:55:42 +0900113 if (sock < 0) {
114 state.SkipWithError(StringPrintf("socket() failed with errno=%d", errno).c_str());
115 break;
116 }
117
118 const Stopwatch stopwatch;
119
120 sockaddr_in server = { .sin_family = AF_INET, .sin_port = htons(port) };
Robin Leee65244b2016-12-01 19:03:33 +0000121 if (connect(sock, (sockaddr*) &server, sizeof(server))) {
Robin Lee2cf56172016-09-13 18:55:42 +0900122 state.SkipWithError(StringPrintf("connect() failed with errno=%d", errno).c_str());
123 close(sock);
124 break;
125 }
126
127 if (waitBetweenRuns) {
Bernie Innocenti196f1b82019-05-20 16:34:16 +0900128 latencies[iterations] = stopwatch.timeTakenUs();
129 state.SetIterationTime(static_cast<double>(latencies[iterations]) / 1.0e6L);
Robin Lee2cf56172016-09-13 18:55:42 +0900130 std::this_thread::sleep_for(std::chrono::milliseconds(10));
131 ++iterations;
132 }
133
134 sockaddr_in6 client;
135 socklen_t clientlen = sizeof(client);
Erik Klineab999f12018-07-04 11:29:31 +0900136 int accepted = accept4(listensocket, (sockaddr*) &client, &clientlen, SOCK_CLOEXEC);
Robin Lee2cf56172016-09-13 18:55:42 +0900137 if (accepted < 0) {
138 state.SkipWithError(StringPrintf("accept() failed with errno=%d", errno).c_str());
139 close(sock);
140 break;
141 }
142
143 close(accepted);
144 close(sock);
145 }
146 close(listensocket);
147 // ALOGI("Finished test on port = %d", port);
148
149 if (iterations > 0) {
150 latencies.resize(iterations);
151 sort(latencies.begin(), latencies.end());
Chih-hung Hsieh03d6f382017-06-21 20:27:48 +0000152 state.SetLabel(StringPrintf("%lld", (long long) latencies[iterations * 9 / 10]));
Robin Lee2cf56172016-09-13 18:55:42 +0900153 }
154}
155
156static void ipv6_loopback(benchmark::State& state, const bool waitBetweenRuns) {
Erik Klineab999f12018-07-04 11:29:31 +0900157 const int listensocket = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
Robin Lee2cf56172016-09-13 18:55:42 +0900158 const int port = bindAndListen(listensocket);
159 if (port == -1) {
160 state.SkipWithError("Unable to bind server socket");
161 return;
162 }
163
164 // ALOGW("Listening on port = %d", port);
165 std::vector<uint64_t> latencies(state.max_iterations);
166 uint64_t iterations = 0;
167
168 while (state.KeepRunning()) {
Erik Klineab999f12018-07-04 11:29:31 +0900169 int sock = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
Robin Lee2cf56172016-09-13 18:55:42 +0900170 if (sock < 0) {
171 state.SkipWithError(StringPrintf("socket() failed with errno=%d", errno).c_str());
172 break;
173 }
174
175 const Stopwatch stopwatch;
176
177 sockaddr_in6 server = { .sin6_family = AF_INET6, .sin6_port = htons(port) };
Robin Leee65244b2016-12-01 19:03:33 +0000178 if (connect(sock, (sockaddr*) &server, sizeof(server))) {
Robin Lee2cf56172016-09-13 18:55:42 +0900179 state.SkipWithError(StringPrintf("connect() failed with errno=%d", errno).c_str());
180 close(sock);
181 break;
182 }
183
184 if (waitBetweenRuns) {
Bernie Innocenti196f1b82019-05-20 16:34:16 +0900185 latencies[iterations] = stopwatch.timeTakenUs();
186 state.SetIterationTime(static_cast<double>(latencies[iterations]) / 1.0e6L);
Robin Lee2cf56172016-09-13 18:55:42 +0900187 std::this_thread::sleep_for(std::chrono::milliseconds(10));
188 ++iterations;
189 }
190
191 sockaddr_in6 client;
192 socklen_t clientlen = sizeof(client);
Erik Klineab999f12018-07-04 11:29:31 +0900193 int accepted = accept4(listensocket, (sockaddr*) &client, &clientlen, SOCK_CLOEXEC);
Robin Lee2cf56172016-09-13 18:55:42 +0900194 if (accepted < 0) {
195 state.SkipWithError(StringPrintf("accept() failed with errno=%d", errno).c_str());
196 close(sock);
197 break;
198 }
199
200 close(accepted);
201 close(sock);
202 }
203 close(listensocket);
204 // ALOGI("Finished test on port = %d", port);
205
206 if (iterations > 0) {
207 latencies.resize(iterations);
208 sort(latencies.begin(), latencies.end());
Chih-hung Hsieh03d6f382017-06-21 20:27:48 +0000209 state.SetLabel(StringPrintf("%lld", (long long) latencies[iterations * 9 / 10]));
Robin Lee2cf56172016-09-13 18:55:42 +0900210 }
211}
212
Bernie Innocenticd257642018-12-20 15:56:40 +0900213static void run(decltype(ipv4_loopback) benchmarkFunction, ::benchmark::State& state,
214 const bool waitBetweenRuns) {
Robin Lee2cf56172016-09-13 18:55:42 +0900215 benchmarkFunction(state, waitBetweenRuns);
Robin Lee2cf56172016-09-13 18:55:42 +0900216}
217
218constexpr int MIN_THREADS = 1;
219constexpr int MAX_THREADS = 1;
220constexpr double MIN_TIME = 0.5 /* seconds */;
221
Bernie Innocenticd257642018-12-20 15:56:40 +0900222// IPv4 benchmarks under no load
223static void ipv4_no_load(::benchmark::State& state) {
224 run(ipv4_loopback, state, true);
Robin Lee2cf56172016-09-13 18:55:42 +0900225}
Bernie Innocenticd257642018-12-20 15:56:40 +0900226BENCHMARK(ipv4_no_load)->MinTime(MIN_TIME)->UseManualTime();
Robin Lee2cf56172016-09-13 18:55:42 +0900227
228// IPv4 benchmarks under high load
Bernie Innocenticd257642018-12-20 15:56:40 +0900229static void ipv4_high_load(::benchmark::State& state) {
230 run(ipv4_loopback, state, false);
Robin Lee2cf56172016-09-13 18:55:42 +0900231}
Bernie Innocenticd257642018-12-20 15:56:40 +0900232BENCHMARK(ipv4_high_load)->ThreadRange(MIN_THREADS, MAX_THREADS)->MinTime(MIN_TIME)->UseRealTime();
Robin Lee2cf56172016-09-13 18:55:42 +0900233
234// IPv6 raw connect() without using fwmark
Bernie Innocenticd257642018-12-20 15:56:40 +0900235static void ipv6_no_load(::benchmark::State& state) {
236 run(ipv6_loopback, state, true);
Robin Lee2cf56172016-09-13 18:55:42 +0900237}
Bernie Innocenticd257642018-12-20 15:56:40 +0900238BENCHMARK(ipv6_no_load)->MinTime(MIN_TIME)->UseManualTime();
Robin Lee2cf56172016-09-13 18:55:42 +0900239
240// IPv6 benchmarks under high load
Bernie Innocenticd257642018-12-20 15:56:40 +0900241static void ipv6_high_load(::benchmark::State& state) {
242 run(ipv6_loopback, state, false);
Robin Lee2cf56172016-09-13 18:55:42 +0900243}
Bernie Innocenticd257642018-12-20 15:56:40 +0900244BENCHMARK(ipv6_high_load)->ThreadRange(MIN_THREADS, MAX_THREADS)->MinTime(MIN_TIME)->UseRealTime();