Home | History | Annotate | Download | only in benchmarks
      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:
     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 
    105     void TearDown(const ::benchmark::State& state) override {
    106         if (state.thread_index == 0) {
    107             dns.ShutdownDNSServers(&mDns);
    108             dns.TearDown();
    109         }
    110     }
    111 
    112     std::vector<DnsResponderClient::Mapping> const& getMappings() const {
    113         return mappings;
    114     }
    115 
    116     android::sp<android::net::INetd> getNetd() const {
    117         return dns.mNetdSrv;
    118     }
    119 
    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 
    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.
    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.
    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.
    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