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