xref: /aosp_15_r20/system/netd/tests/benchmarks/connect_benchmark.cpp (revision 8542734a0dd1db395a4d42aae09c37f3c3c3e7a1)
1*8542734aSAndroid Build Coastguard Worker /*
2*8542734aSAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*8542734aSAndroid Build Coastguard Worker  *
4*8542734aSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*8542734aSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*8542734aSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*8542734aSAndroid Build Coastguard Worker  *
8*8542734aSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*8542734aSAndroid Build Coastguard Worker  *
10*8542734aSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*8542734aSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*8542734aSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*8542734aSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*8542734aSAndroid Build Coastguard Worker  * limitations under the License.
15*8542734aSAndroid Build Coastguard Worker  */
16*8542734aSAndroid Build Coastguard Worker 
17*8542734aSAndroid Build Coastguard Worker #define LOG_TAG "connect_benchmark"
18*8542734aSAndroid Build Coastguard Worker 
19*8542734aSAndroid Build Coastguard Worker /*
20*8542734aSAndroid Build Coastguard Worker  * See README.md for general notes.
21*8542734aSAndroid Build Coastguard Worker  *
22*8542734aSAndroid Build Coastguard Worker  * This set of benchmarks measures the throughput of connect() calls on a single thread for IPv4 and
23*8542734aSAndroid Build Coastguard Worker  * IPv6.
24*8542734aSAndroid Build Coastguard Worker  *
25*8542734aSAndroid Build Coastguard Worker  * Realtime timed tests
26*8542734aSAndroid Build Coastguard Worker  * ====================
27*8542734aSAndroid Build Coastguard Worker  *
28*8542734aSAndroid Build Coastguard Worker  * The tests named *_high_load record the following useful information:
29*8542734aSAndroid Build Coastguard Worker  *
30*8542734aSAndroid Build Coastguard Worker  *   - real_time: the mean roundtrip time for one connect() call under load
31*8542734aSAndroid Build Coastguard Worker  *
32*8542734aSAndroid Build Coastguard Worker  *   - iterations: the number of times the test was run within the timelimit --- approximately
33*8542734aSAndroid Build Coastguard Worker  *                 MinTime / real_time
34*8542734aSAndroid Build Coastguard Worker  *
35*8542734aSAndroid Build Coastguard Worker  * Manually timed tests
36*8542734aSAndroid Build Coastguard Worker  * ====================
37*8542734aSAndroid Build Coastguard Worker  *
38*8542734aSAndroid Build Coastguard Worker  * All other sets of tests apart from *_high_load run with manual timing. The purpose of these is to
39*8542734aSAndroid Build Coastguard Worker  * measure 90th-percentile latency for connect() calls compared to mean latency.
40*8542734aSAndroid Build Coastguard Worker  *
41*8542734aSAndroid Build Coastguard Worker  * (TODO: ideally this should be against median latency, but google-benchmark only supports one
42*8542734aSAndroid Build Coastguard Worker  *        custom 'label' output for graphing. Stddev isn't appropriate because the latency
43*8542734aSAndroid Build Coastguard Worker  *        distribution is usually spiky, not in a nice neat normal-like distribution.)
44*8542734aSAndroid Build Coastguard Worker  *
45*8542734aSAndroid Build Coastguard Worker  * The manually timed tests record the following useful information:
46*8542734aSAndroid Build Coastguard Worker  *
47*8542734aSAndroid Build Coastguard Worker  *  - real_time: the average time taken to complete a test run. Unlike the real_time used in high
48*8542734aSAndroid Build Coastguard Worker  *               load tests, this is calculated from before-and-after values of the realtime clock
49*8542734aSAndroid Build Coastguard Worker  *               over many iterations so may be less accurate than the under-load times.
50*8542734aSAndroid Build Coastguard Worker  *
51*8542734aSAndroid Build Coastguard Worker  *  - iterations: the number of times the test was run within the timelimit --- approximately
52*8542734aSAndroid Build Coastguard Worker  *                MinTime / real_time, although as explained, may not be as meaningful because of
53*8542734aSAndroid Build Coastguard Worker  *                overhead from timing.
54*8542734aSAndroid Build Coastguard Worker  *
55*8542734aSAndroid Build Coastguard Worker  *  - label: a manually-recorded time giving the 90th-percentile value of real_time over all
56*8542734aSAndroid Build Coastguard Worker  *           individual runs. Should be compared to real_time.
57*8542734aSAndroid Build Coastguard Worker  *
58*8542734aSAndroid Build Coastguard Worker  */
59*8542734aSAndroid Build Coastguard Worker 
60*8542734aSAndroid Build Coastguard Worker #include <arpa/inet.h>
61*8542734aSAndroid Build Coastguard Worker #include <cutils/sockets.h>
62*8542734aSAndroid Build Coastguard Worker #include <errno.h>
63*8542734aSAndroid Build Coastguard Worker #include <netinet/in.h>
64*8542734aSAndroid Build Coastguard Worker #include <time.h>
65*8542734aSAndroid Build Coastguard Worker 
66*8542734aSAndroid Build Coastguard Worker #include <map>
67*8542734aSAndroid Build Coastguard Worker #include <functional>
68*8542734aSAndroid Build Coastguard Worker #include <thread>
69*8542734aSAndroid Build Coastguard Worker 
70*8542734aSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
71*8542734aSAndroid Build Coastguard Worker #include <benchmark/benchmark.h>
72*8542734aSAndroid Build Coastguard Worker #include <log/log.h>
73*8542734aSAndroid Build Coastguard Worker #include <netdutils/Stopwatch.h>
74*8542734aSAndroid Build Coastguard Worker #include <utils/StrongPointer.h>
75*8542734aSAndroid Build Coastguard Worker 
76*8542734aSAndroid Build Coastguard Worker #include "FwmarkClient.h"
77*8542734aSAndroid Build Coastguard Worker #include "SockDiag.h"
78*8542734aSAndroid Build Coastguard Worker 
79*8542734aSAndroid Build Coastguard Worker using android::base::StringPrintf;
80*8542734aSAndroid Build Coastguard Worker using android::netdutils::Stopwatch;
81*8542734aSAndroid Build Coastguard Worker 
bindAndListen(int s)82*8542734aSAndroid Build Coastguard Worker static int bindAndListen(int s) {
83*8542734aSAndroid Build Coastguard Worker     sockaddr_in6 sin6 = { .sin6_family = AF_INET6 };
84*8542734aSAndroid Build Coastguard Worker     if (bind(s, (sockaddr*) &sin6, sizeof(sin6)) == 0) {
85*8542734aSAndroid Build Coastguard Worker         if (listen(s, 1)) {
86*8542734aSAndroid Build Coastguard Worker             return -1;
87*8542734aSAndroid Build Coastguard Worker         }
88*8542734aSAndroid Build Coastguard Worker         sockaddr_in sin = {};
89*8542734aSAndroid Build Coastguard Worker         socklen_t len = sizeof(sin);
90*8542734aSAndroid Build Coastguard Worker         if (getsockname(s, (sockaddr*) &sin, &len)) {
91*8542734aSAndroid Build Coastguard Worker             return -1;
92*8542734aSAndroid Build Coastguard Worker         }
93*8542734aSAndroid Build Coastguard Worker         return ntohs(sin.sin_port);
94*8542734aSAndroid Build Coastguard Worker     } else {
95*8542734aSAndroid Build Coastguard Worker         return -1;
96*8542734aSAndroid Build Coastguard Worker     }
97*8542734aSAndroid Build Coastguard Worker }
98*8542734aSAndroid Build Coastguard Worker 
ipv4_loopback(benchmark::State & state,const bool waitBetweenRuns)99*8542734aSAndroid Build Coastguard Worker static void ipv4_loopback(benchmark::State& state, const bool waitBetweenRuns) {
100*8542734aSAndroid Build Coastguard Worker     const int listensocket = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
101*8542734aSAndroid Build Coastguard Worker     const int port = bindAndListen(listensocket);
102*8542734aSAndroid Build Coastguard Worker     if (port == -1) {
103*8542734aSAndroid Build Coastguard Worker         state.SkipWithError("Unable to bind server socket");
104*8542734aSAndroid Build Coastguard Worker         return;
105*8542734aSAndroid Build Coastguard Worker     }
106*8542734aSAndroid Build Coastguard Worker 
107*8542734aSAndroid Build Coastguard Worker     // ALOGW("Listening on port = %d", port);
108*8542734aSAndroid Build Coastguard Worker     std::vector<uint64_t> latencies(state.max_iterations);
109*8542734aSAndroid Build Coastguard Worker     uint64_t iterations = 0;
110*8542734aSAndroid Build Coastguard Worker 
111*8542734aSAndroid Build Coastguard Worker     while (state.KeepRunning()) {
112*8542734aSAndroid Build Coastguard Worker         int sock = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
113*8542734aSAndroid Build Coastguard Worker         if (sock < 0) {
114*8542734aSAndroid Build Coastguard Worker             state.SkipWithError(StringPrintf("socket() failed with errno=%d", errno).c_str());
115*8542734aSAndroid Build Coastguard Worker             break;
116*8542734aSAndroid Build Coastguard Worker         }
117*8542734aSAndroid Build Coastguard Worker 
118*8542734aSAndroid Build Coastguard Worker         const Stopwatch stopwatch;
119*8542734aSAndroid Build Coastguard Worker 
120*8542734aSAndroid Build Coastguard Worker         sockaddr_in server = { .sin_family = AF_INET, .sin_port = htons(port) };
121*8542734aSAndroid Build Coastguard Worker         if (connect(sock, (sockaddr*) &server, sizeof(server))) {
122*8542734aSAndroid Build Coastguard Worker             state.SkipWithError(StringPrintf("connect() failed with errno=%d", errno).c_str());
123*8542734aSAndroid Build Coastguard Worker             close(sock);
124*8542734aSAndroid Build Coastguard Worker             break;
125*8542734aSAndroid Build Coastguard Worker         }
126*8542734aSAndroid Build Coastguard Worker 
127*8542734aSAndroid Build Coastguard Worker         if (waitBetweenRuns) {
128*8542734aSAndroid Build Coastguard Worker             latencies[iterations] = stopwatch.timeTakenUs();
129*8542734aSAndroid Build Coastguard Worker             state.SetIterationTime(static_cast<double>(latencies[iterations]) / 1.0e6L);
130*8542734aSAndroid Build Coastguard Worker             std::this_thread::sleep_for(std::chrono::milliseconds(10));
131*8542734aSAndroid Build Coastguard Worker             ++iterations;
132*8542734aSAndroid Build Coastguard Worker         }
133*8542734aSAndroid Build Coastguard Worker 
134*8542734aSAndroid Build Coastguard Worker         sockaddr_in6 client;
135*8542734aSAndroid Build Coastguard Worker         socklen_t clientlen = sizeof(client);
136*8542734aSAndroid Build Coastguard Worker         int accepted = accept4(listensocket, (sockaddr*) &client, &clientlen, SOCK_CLOEXEC);
137*8542734aSAndroid Build Coastguard Worker         if (accepted < 0) {
138*8542734aSAndroid Build Coastguard Worker             state.SkipWithError(StringPrintf("accept() failed with errno=%d", errno).c_str());
139*8542734aSAndroid Build Coastguard Worker             close(sock);
140*8542734aSAndroid Build Coastguard Worker             break;
141*8542734aSAndroid Build Coastguard Worker         }
142*8542734aSAndroid Build Coastguard Worker 
143*8542734aSAndroid Build Coastguard Worker         close(accepted);
144*8542734aSAndroid Build Coastguard Worker         close(sock);
145*8542734aSAndroid Build Coastguard Worker     }
146*8542734aSAndroid Build Coastguard Worker     close(listensocket);
147*8542734aSAndroid Build Coastguard Worker     // ALOGI("Finished test on port = %d", port);
148*8542734aSAndroid Build Coastguard Worker 
149*8542734aSAndroid Build Coastguard Worker     if (iterations > 0) {
150*8542734aSAndroid Build Coastguard Worker         latencies.resize(iterations);
151*8542734aSAndroid Build Coastguard Worker         sort(latencies.begin(), latencies.end());
152*8542734aSAndroid Build Coastguard Worker         state.SetLabel(StringPrintf("%lld", (long long) latencies[iterations * 9 / 10]));
153*8542734aSAndroid Build Coastguard Worker     }
154*8542734aSAndroid Build Coastguard Worker }
155*8542734aSAndroid Build Coastguard Worker 
ipv6_loopback(benchmark::State & state,const bool waitBetweenRuns)156*8542734aSAndroid Build Coastguard Worker static void ipv6_loopback(benchmark::State& state, const bool waitBetweenRuns) {
157*8542734aSAndroid Build Coastguard Worker     const int listensocket = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
158*8542734aSAndroid Build Coastguard Worker     const int port = bindAndListen(listensocket);
159*8542734aSAndroid Build Coastguard Worker     if (port == -1) {
160*8542734aSAndroid Build Coastguard Worker         state.SkipWithError("Unable to bind server socket");
161*8542734aSAndroid Build Coastguard Worker         return;
162*8542734aSAndroid Build Coastguard Worker     }
163*8542734aSAndroid Build Coastguard Worker 
164*8542734aSAndroid Build Coastguard Worker     // ALOGW("Listening on port = %d", port);
165*8542734aSAndroid Build Coastguard Worker     std::vector<uint64_t> latencies(state.max_iterations);
166*8542734aSAndroid Build Coastguard Worker     uint64_t iterations = 0;
167*8542734aSAndroid Build Coastguard Worker 
168*8542734aSAndroid Build Coastguard Worker     while (state.KeepRunning()) {
169*8542734aSAndroid Build Coastguard Worker         int sock = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
170*8542734aSAndroid Build Coastguard Worker         if (sock < 0) {
171*8542734aSAndroid Build Coastguard Worker             state.SkipWithError(StringPrintf("socket() failed with errno=%d", errno).c_str());
172*8542734aSAndroid Build Coastguard Worker             break;
173*8542734aSAndroid Build Coastguard Worker         }
174*8542734aSAndroid Build Coastguard Worker 
175*8542734aSAndroid Build Coastguard Worker         const Stopwatch stopwatch;
176*8542734aSAndroid Build Coastguard Worker 
177*8542734aSAndroid Build Coastguard Worker         sockaddr_in6 server = { .sin6_family = AF_INET6, .sin6_port = htons(port) };
178*8542734aSAndroid Build Coastguard Worker         if (connect(sock, (sockaddr*) &server, sizeof(server))) {
179*8542734aSAndroid Build Coastguard Worker             state.SkipWithError(StringPrintf("connect() failed with errno=%d", errno).c_str());
180*8542734aSAndroid Build Coastguard Worker             close(sock);
181*8542734aSAndroid Build Coastguard Worker             break;
182*8542734aSAndroid Build Coastguard Worker         }
183*8542734aSAndroid Build Coastguard Worker 
184*8542734aSAndroid Build Coastguard Worker         if (waitBetweenRuns) {
185*8542734aSAndroid Build Coastguard Worker             latencies[iterations] = stopwatch.timeTakenUs();
186*8542734aSAndroid Build Coastguard Worker             state.SetIterationTime(static_cast<double>(latencies[iterations]) / 1.0e6L);
187*8542734aSAndroid Build Coastguard Worker             std::this_thread::sleep_for(std::chrono::milliseconds(10));
188*8542734aSAndroid Build Coastguard Worker             ++iterations;
189*8542734aSAndroid Build Coastguard Worker         }
190*8542734aSAndroid Build Coastguard Worker 
191*8542734aSAndroid Build Coastguard Worker         sockaddr_in6 client;
192*8542734aSAndroid Build Coastguard Worker         socklen_t clientlen = sizeof(client);
193*8542734aSAndroid Build Coastguard Worker         int accepted = accept4(listensocket, (sockaddr*) &client, &clientlen, SOCK_CLOEXEC);
194*8542734aSAndroid Build Coastguard Worker         if (accepted < 0) {
195*8542734aSAndroid Build Coastguard Worker             state.SkipWithError(StringPrintf("accept() failed with errno=%d", errno).c_str());
196*8542734aSAndroid Build Coastguard Worker             close(sock);
197*8542734aSAndroid Build Coastguard Worker             break;
198*8542734aSAndroid Build Coastguard Worker         }
199*8542734aSAndroid Build Coastguard Worker 
200*8542734aSAndroid Build Coastguard Worker         close(accepted);
201*8542734aSAndroid Build Coastguard Worker         close(sock);
202*8542734aSAndroid Build Coastguard Worker     }
203*8542734aSAndroid Build Coastguard Worker     close(listensocket);
204*8542734aSAndroid Build Coastguard Worker     // ALOGI("Finished test on port = %d", port);
205*8542734aSAndroid Build Coastguard Worker 
206*8542734aSAndroid Build Coastguard Worker     if (iterations > 0) {
207*8542734aSAndroid Build Coastguard Worker         latencies.resize(iterations);
208*8542734aSAndroid Build Coastguard Worker         sort(latencies.begin(), latencies.end());
209*8542734aSAndroid Build Coastguard Worker         state.SetLabel(StringPrintf("%lld", (long long) latencies[iterations * 9 / 10]));
210*8542734aSAndroid Build Coastguard Worker     }
211*8542734aSAndroid Build Coastguard Worker }
212*8542734aSAndroid Build Coastguard Worker 
run(decltype(ipv4_loopback) benchmarkFunction,::benchmark::State & state,const bool waitBetweenRuns)213*8542734aSAndroid Build Coastguard Worker static void run(decltype(ipv4_loopback) benchmarkFunction, ::benchmark::State& state,
214*8542734aSAndroid Build Coastguard Worker                 const bool waitBetweenRuns) {
215*8542734aSAndroid Build Coastguard Worker     benchmarkFunction(state, waitBetweenRuns);
216*8542734aSAndroid Build Coastguard Worker }
217*8542734aSAndroid Build Coastguard Worker 
218*8542734aSAndroid Build Coastguard Worker constexpr int MIN_THREADS = 1;
219*8542734aSAndroid Build Coastguard Worker constexpr int MAX_THREADS = 1;
220*8542734aSAndroid Build Coastguard Worker constexpr double MIN_TIME = 0.5 /* seconds */;
221*8542734aSAndroid Build Coastguard Worker 
222*8542734aSAndroid Build Coastguard Worker // IPv4 benchmarks under no load
ipv4_no_load(::benchmark::State & state)223*8542734aSAndroid Build Coastguard Worker static void ipv4_no_load(::benchmark::State& state) {
224*8542734aSAndroid Build Coastguard Worker     run(ipv4_loopback, state, true);
225*8542734aSAndroid Build Coastguard Worker }
226*8542734aSAndroid Build Coastguard Worker BENCHMARK(ipv4_no_load)->MinTime(MIN_TIME)->UseManualTime();
227*8542734aSAndroid Build Coastguard Worker 
228*8542734aSAndroid Build Coastguard Worker // IPv4 benchmarks under high load
ipv4_high_load(::benchmark::State & state)229*8542734aSAndroid Build Coastguard Worker static void ipv4_high_load(::benchmark::State& state) {
230*8542734aSAndroid Build Coastguard Worker     run(ipv4_loopback, state, false);
231*8542734aSAndroid Build Coastguard Worker }
232*8542734aSAndroid Build Coastguard Worker BENCHMARK(ipv4_high_load)->ThreadRange(MIN_THREADS, MAX_THREADS)->MinTime(MIN_TIME)->UseRealTime();
233*8542734aSAndroid Build Coastguard Worker 
234*8542734aSAndroid Build Coastguard Worker // IPv6 raw connect() without using fwmark
ipv6_no_load(::benchmark::State & state)235*8542734aSAndroid Build Coastguard Worker static void ipv6_no_load(::benchmark::State& state) {
236*8542734aSAndroid Build Coastguard Worker     run(ipv6_loopback, state, true);
237*8542734aSAndroid Build Coastguard Worker }
238*8542734aSAndroid Build Coastguard Worker BENCHMARK(ipv6_no_load)->MinTime(MIN_TIME)->UseManualTime();
239*8542734aSAndroid Build Coastguard Worker 
240*8542734aSAndroid Build Coastguard Worker // IPv6 benchmarks under high load
ipv6_high_load(::benchmark::State & state)241*8542734aSAndroid Build Coastguard Worker static void ipv6_high_load(::benchmark::State& state) {
242*8542734aSAndroid Build Coastguard Worker     run(ipv6_loopback, state, false);
243*8542734aSAndroid Build Coastguard Worker }
244*8542734aSAndroid Build Coastguard Worker BENCHMARK(ipv6_high_load)->ThreadRange(MIN_THREADS, MAX_THREADS)->MinTime(MIN_TIME)->UseRealTime();
245