1 /*
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 "dns_benchmark"
18
19 /*
20 * See README.md for general notes.
21 *
22 * This set of benchmarks measures the throughput of getaddrinfo() on between 1 and 32 threads for
23 * the purpose of keeping track of the maximum load that netd can reasonably handle.
24 *
25 * The benchmark fixture runs in 3 different modes:
26 *
27 * - getaddrinfo_log_nothing
28 *
29 * The control case. Switches all kinds of DNS events reporting off and runs getaddrinfo() in a
30 * loop until the timer expires.
31 *
32 * This was the default and only mode in all versions before 7.0.
33 *
34 * - getaddrinfo_log_metrics
35 *
36 * DNS Logging Lite™ includes staple favourites such as event type (getaddrinfo/gethostbyname),
37 * return code, and latency, but misses out in-depth information such as resolved IP addresses.
38 *
39 * It is expected that this is a little slower than getaddrinfo_log_nothing because of the
40 * overhead, but not particularly worse, since it is a oneway binder call without too much data
41 * being sent per event.
42 *
43 * This was the default mode between versions 7.0 and 7.1 inclusive.
44 *
45 * - getaddrinfo_log_everything
46 *
47 * DNS Logging, in full HD, includes extra non-metrics fields such as hostname, a truncated
48 * list of resolved addresses, total resolved address count, and originating UID.
49 *
50 * Useful measurements
51 * ===================
52 *
53 * - real_time: the average time taken to make a single getaddrinfo lookup on a local DNS resolver
54 * run by DnsFixture. This will usually be higher on multithreaded tests as threads
55 * block on DNS lookups and Binder connections.
56 *
57 * - iterations: total number of runs finished within the time limit. Higher is better. This is
58 * roughly proportional to MinTime * nThreads / real_time.
59 *
60 */
61
62 #include <netdb.h>
63 #include <netinet/in.h>
64 #include <sys/types.h>
65 #include <sys/socket.h>
66
67 #include <android-base/stringprintf.h>
68 #include <benchmark/benchmark.h>
69 #include <utils/String16.h>
70 #include <utils/StrongPointer.h>
71
72 #include "dns_responder_client.h"
73 #include "NetdClient.h"
74 #include "android/net/metrics/INetdEventListener.h"
75
76 using android::base::StringPrintf;
77 using android::net::metrics::INetdEventListener;
78
79 constexpr int MIN_THREADS = 1;
80 constexpr int MAX_THREADS = 32;
81
82 class DnsFixture : public ::benchmark::Fixture {
83 protected:
84 static constexpr unsigned num_hosts = 1000;
85 DnsResponderClient dns;
86 std::vector<DnsResponderClient::Mapping> mappings;
87 std::vector<std::unique_ptr<test::DNSResponder>> mDns;
88
89 public:
SetUp(const::benchmark::State & state)90 void SetUp(const ::benchmark::State& state) override {
91 if (state.thread_index == 0) {
92 dns.SetUp();
93
94 std::vector<std::string> domains = { "example.com" };
95 std::vector<std::string> servers;
96 dns.SetupMappings(num_hosts, domains, &mappings);
97
98 dns.SetupDNSServers(MAXNS, mappings, &mDns, &servers);
99
100 const std::vector<int> mDefaultParams_Binder = { 300, 25, 8, 8 };
101 dns.SetResolversForNetwork(servers, domains, mDefaultParams_Binder);
102 }
103 }
104
TearDown(const::benchmark::State & state)105 void TearDown(const ::benchmark::State& state) override {
106 if (state.thread_index == 0) {
107 dns.ShutdownDNSServers(&mDns);
108 dns.TearDown();
109 }
110 }
111
getMappings() const112 std::vector<DnsResponderClient::Mapping> const& getMappings() const {
113 return mappings;
114 }
115
getNetd() const116 android::sp<android::net::INetd> getNetd() const {
117 return dns.mNetdSrv;
118 }
119
getaddrinfo_until_done(benchmark::State & state)120 void getaddrinfo_until_done(benchmark::State &state) {
121 while (state.KeepRunning()) {
122 const uint32_t ofs = arc4random_uniform(getMappings().size());
123 const auto& mapping = getMappings()[ofs];
124 addrinfo* result = nullptr;
125 if (getaddrinfo(mapping.host.c_str(), nullptr, nullptr, &result)) {
126 state.SkipWithError(StringPrintf("getaddrinfo failed with errno=%d",
127 errno).c_str());
128 break;
129 }
130 if (result) {
131 freeaddrinfo(result);
132 result = nullptr;
133 }
134 }
135 }
136
benchmark_at_reporting_level(benchmark::State & state,int metricsLevel)137 void benchmark_at_reporting_level(benchmark::State &state, int metricsLevel) {
138 const bool isMaster = (state.thread_index == 0);
139 int oldMetricsLevel;
140
141 // SETUP
142 if (isMaster) {
143 auto rv = getNetd()->getMetricsReportingLevel(&oldMetricsLevel);
144 if (!rv.isOk()) {
145 state.SkipWithError(StringPrintf("Failed saving metrics reporting level: %s",
146 rv.toString8().string()).c_str());
147 return;
148 }
149 rv = getNetd()->setMetricsReportingLevel(metricsLevel);
150 if (!rv.isOk()) {
151 state.SkipWithError(StringPrintf("Failed changing metrics reporting: %s",
152 rv.toString8().string()).c_str());
153 return;
154 }
155 }
156
157 // TEST
158 getaddrinfo_until_done(state);
159
160 // TEARDOWN
161 if (isMaster) {
162 auto rv = getNetd()->setMetricsReportingLevel(oldMetricsLevel);
163 if (!rv.isOk()) {
164 state.SkipWithError(StringPrintf("Failed restoring metrics reporting level: %s",
165 rv.toString8().string()).c_str());
166 return;
167 }
168 }
169 }
170 };
171
172 // DNS calls without any metrics logged or sent.
BENCHMARK_DEFINE_F(DnsFixture,getaddrinfo_log_nothing)173 BENCHMARK_DEFINE_F(DnsFixture, getaddrinfo_log_nothing)(benchmark::State& state) {
174 benchmark_at_reporting_level(state, INetdEventListener::REPORTING_LEVEL_NONE);
175 }
176 BENCHMARK_REGISTER_F(DnsFixture, getaddrinfo_log_nothing)
177 ->ThreadRange(MIN_THREADS, MAX_THREADS)
178 ->UseRealTime();
179
180 // DNS calls with metrics only (netId, latency, return code) sent to the system server.
BENCHMARK_DEFINE_F(DnsFixture,getaddrinfo_log_metrics)181 BENCHMARK_DEFINE_F(DnsFixture, getaddrinfo_log_metrics)(benchmark::State& state) {
182 benchmark_at_reporting_level(state, INetdEventListener::REPORTING_LEVEL_METRICS);
183 }
184 BENCHMARK_REGISTER_F(DnsFixture, getaddrinfo_log_metrics)
185 ->ThreadRange(MIN_THREADS, MAX_THREADS)
186 ->UseRealTime();
187
188 // DNS calls with all information logged and sent to the system server.
BENCHMARK_DEFINE_F(DnsFixture,getaddrinfo_log_everything)189 BENCHMARK_DEFINE_F(DnsFixture, getaddrinfo_log_everything)(benchmark::State& state) {
190 benchmark_at_reporting_level(state, INetdEventListener::REPORTING_LEVEL_FULL);
191 }
192 BENCHMARK_REGISTER_F(DnsFixture, getaddrinfo_log_everything)
193 ->ThreadRange(MIN_THREADS, MAX_THREADS)
194 ->UseRealTime();
195