upload android base code part6
This commit is contained in:
parent
421e214c7d
commit
4e516ec6ed
35396 changed files with 9188716 additions and 0 deletions
44
android/system/netd/tests/benchmarks/Android.mk
Normal file
44
android/system/netd/tests/benchmarks/Android.mk
Normal file
|
@ -0,0 +1,44 @@
|
|||
#
|
||||
# Copyright (C) 2016 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# APCT build target for metrics tests
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := netd_benchmark
|
||||
LOCAL_CFLAGS := -Wall -Werror -Wunused-parameter
|
||||
# Bug: http://b/29823425 Disable -Wvarargs for Clang update to r271374
|
||||
LOCAL_CFLAGS += -Wno-varargs
|
||||
|
||||
EXTRA_LDLIBS := -lpthread
|
||||
LOCAL_SHARED_LIBRARIES += libbase libbinder liblog libnetd_client
|
||||
LOCAL_STATIC_LIBRARIES += libnetd_test_dnsresponder libutils
|
||||
|
||||
LOCAL_AIDL_INCLUDES := system/netd/server/binder
|
||||
LOCAL_C_INCLUDES += system/netd/include \
|
||||
system/netd/client \
|
||||
system/netd/server \
|
||||
system/netd/server/binder \
|
||||
system/netd/tests/dns_responder \
|
||||
bionic/libc/dns/include
|
||||
|
||||
LOCAL_SRC_FILES := main.cpp \
|
||||
connect_benchmark.cpp \
|
||||
dns_benchmark.cpp \
|
||||
../../server/binder/android/net/metrics/INetdEventListener.aidl
|
||||
|
||||
LOCAL_MODULE_TAGS := eng tests
|
||||
|
||||
include $(BUILD_NATIVE_BENCHMARK)
|
26
android/system/netd/tests/benchmarks/AndroidTest.xml
Normal file
26
android/system/netd/tests/benchmarks/AndroidTest.xml
Normal file
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<configuration description="Config for netd_benchmark">
|
||||
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
|
||||
<option name="cleanup" value="true" />
|
||||
<option name="push" value="netd_benchmark->/data/local/tmp/netd_benchmark" />
|
||||
</target_preparer>
|
||||
<option name="test-suite-tag" value="apct" />
|
||||
<test class="com.android.tradefed.testtype.GTest" >
|
||||
<option name="native-test-device-path" value="/data/local/tmp" />
|
||||
<option name="module-name" value="netd_benchmark" />
|
||||
</test>
|
||||
</configuration>
|
72
android/system/netd/tests/benchmarks/README.md
Normal file
72
android/system/netd/tests/benchmarks/README.md
Normal file
|
@ -0,0 +1,72 @@
|
|||
# NetD benchmarks
|
||||
|
||||
These are benchmarks for libc **connect** and **gethostbyname** functions as hooked by netd.
|
||||
|
||||
## Infrastructure
|
||||
|
||||
The benchmarks are powered by [google-benchmark](https://github.com/google/benchmark), which records
|
||||
four statistics:
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th>Statistic</th>
|
||||
<th>Meaning</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>real_time</th>
|
||||
<td>Mean wall-clock time taken for each iteration of the function under test to complete. This
|
||||
includes any time spent in other processes.
|
||||
<p>
|
||||
Some of the **connect** benchmarks override this by implementing their own timings, but
|
||||
the semantics are roughly the same. See connect_benchmark.cpp for details.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>cpu_time</th>
|
||||
<td>Mean time spent in the current thread during each iteration of the function under test. This
|
||||
does not include any time spent in other processes or blocking on I/O.
|
||||
<p>
|
||||
Since almost all of the functionality we are testing here is in the netd server, not the
|
||||
client, these timings are not relevant and should be ignored for most purposes.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>iterations</th>
|
||||
<td>The number of runs of the test function that were executed, across all threads, in order for
|
||||
the test to reach the minimum amount of time run. Most tests here define 'minimum time run'
|
||||
in terms of real time or 'manual time', rather than CPU time, for the reasons above.
|
||||
<p>
|
||||
This should be roughly inversely proportional to **real_time** for single-threaded
|
||||
benchmarks and also somewhat proportional to the number of threads used.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>label</th>
|
||||
<td>Field that the benchmark can fill with an arbitrary string.
|
||||
<p>
|
||||
For graphing purposes, a few of the benchmarks in this directory store the 90th-percentile
|
||||
latency in this field for comparison against the mean latency
|
||||
(it's only possible to plot one other value apart from mean).
|
||||
<p>
|
||||
If the graphing ecosystem ever becomes advanced enough to plot multiple outputs from one
|
||||
label, it might be more useful to log every decile to get a better picture of how spiky
|
||||
things are.</td>
|
||||
</table>
|
||||
|
||||
# Methods currently being benchmarked
|
||||
|
||||
## connect()
|
||||
|
||||
- Documented in [connect\_benchmark.cpp](connect_benchmark.cpp)
|
||||
|
||||
## getaddrinfo()
|
||||
|
||||
- Documented in [dns\_benchmark.cpp](dns_benchmark.cpp)
|
||||
|
||||
|
||||
<style type="text/css">
|
||||
tr:nth-child(2n+1) {
|
||||
background: lightgrey;
|
||||
}
|
||||
td,th {
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
349
android/system/netd/tests/benchmarks/connect_benchmark.cpp
Normal file
349
android/system/netd/tests/benchmarks/connect_benchmark.cpp
Normal file
|
@ -0,0 +1,349 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "connect_benchmark"
|
||||
|
||||
/*
|
||||
* See README.md for general notes.
|
||||
*
|
||||
* This set of benchmarks measures the throughput of connect() calls on a single thread for IPv4 and
|
||||
* IPv6 under the following scenarios:
|
||||
*
|
||||
* - FWmark disabled (::ANDROID_NO_USE_FWMARK_CLIENT).
|
||||
*
|
||||
* The control case for other high load benchmarks. Essentially just testing performance of
|
||||
* the kernel connect call. In real world use fwmark should stay on in order for traffic to
|
||||
* be routed properly.
|
||||
*
|
||||
* - FWmark enabled only for metrics (::ANDROID_FWMARK_METRICS_ONLY).
|
||||
*
|
||||
* The default mode up to and including 7.1. Every time connect() is called on an AF_INET or
|
||||
* AF_INET6 socket, netdclient sends a synchronous message to fwmarkserver to get the socket
|
||||
* marked. Only the fields that are useful for marking or for metrics are sent in this mode;
|
||||
* other fields are set to null for the RPC and ignored.
|
||||
*
|
||||
* - FWmark enabled for all events.
|
||||
*
|
||||
* The default mode starting from 7.1.2. As well as the normal connect() reporting, extra
|
||||
* fields are filled in to log the IP and port of the connection.
|
||||
*
|
||||
* A second synchronous message is sent to fwmarkserver after the connection completes, to
|
||||
* record latency. This message is forwarded to the system server over a oneway binder call.
|
||||
*
|
||||
* Realtime timed tests
|
||||
* ====================
|
||||
*
|
||||
* The tests named *_high_load record the following useful information:
|
||||
*
|
||||
* - real_time: the mean roundtrip time for one connect() call under load
|
||||
*
|
||||
* - iterations: the number of times the test was run within the timelimit --- approximately
|
||||
* MinTime / real_time
|
||||
*
|
||||
* Manually timed tests
|
||||
* ====================
|
||||
*
|
||||
* All other sets of tests apart from *_high_load run with manual timing. The purpose of these is to
|
||||
* measure 90th-percentile latency for connect() calls compared to mean latency.
|
||||
*
|
||||
* (TODO: ideally this should be against median latency, but google-benchmark only supports one
|
||||
* custom 'label' output for graphing. Stddev isn't appropriate because the latency
|
||||
* distribution is usually spiky, not in a nice neat normal-like distribution.)
|
||||
*
|
||||
* The manually timed tests record the following useful information:
|
||||
*
|
||||
* - real_time: the average time taken to complete a test run. Unlike the real_time used in high
|
||||
* load tests, this is calculated from before-and-after values of the realtime clock
|
||||
* over many iterations so may be less accurate than the under-load times.
|
||||
*
|
||||
* - iterations: the number of times the test was run within the timelimit --- approximately
|
||||
* MinTime / real_time, although as explained, may not be as meaningful because of
|
||||
* overhead from timing.
|
||||
*
|
||||
* - label: a manually-recorded time giving the 90th-percentile value of real_time over all
|
||||
* individual runs. Should be compared to real_time.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <cutils/sockets.h>
|
||||
#include <errno.h>
|
||||
#include <netinet/in.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <log/log.h>
|
||||
#include <utils/StrongPointer.h>
|
||||
|
||||
#include "FwmarkClient.h"
|
||||
#include "SockDiag.h"
|
||||
#include "Stopwatch.h"
|
||||
#include "android/net/metrics/INetdEventListener.h"
|
||||
|
||||
using android::base::StringPrintf;
|
||||
using android::net::metrics::INetdEventListener;
|
||||
|
||||
static int bindAndListen(int s) {
|
||||
sockaddr_in6 sin6 = { .sin6_family = AF_INET6 };
|
||||
if (bind(s, (sockaddr*) &sin6, sizeof(sin6)) == 0) {
|
||||
if (listen(s, 1)) {
|
||||
return -1;
|
||||
}
|
||||
sockaddr_in sin = {};
|
||||
socklen_t len = sizeof(sin);
|
||||
if (getsockname(s, (sockaddr*) &sin, &len)) {
|
||||
return -1;
|
||||
}
|
||||
return ntohs(sin.sin_port);
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void ipv4_loopback(benchmark::State& state, const bool waitBetweenRuns) {
|
||||
const int listensocket = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
const int port = bindAndListen(listensocket);
|
||||
if (port == -1) {
|
||||
state.SkipWithError("Unable to bind server socket");
|
||||
return;
|
||||
}
|
||||
|
||||
// ALOGW("Listening on port = %d", port);
|
||||
std::vector<uint64_t> latencies(state.max_iterations);
|
||||
uint64_t iterations = 0;
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
state.SkipWithError(StringPrintf("socket() failed with errno=%d", errno).c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
const Stopwatch stopwatch;
|
||||
|
||||
sockaddr_in server = { .sin_family = AF_INET, .sin_port = htons(port) };
|
||||
if (connect(sock, (sockaddr*) &server, sizeof(server))) {
|
||||
state.SkipWithError(StringPrintf("connect() failed with errno=%d", errno).c_str());
|
||||
close(sock);
|
||||
break;
|
||||
}
|
||||
|
||||
if (waitBetweenRuns) {
|
||||
latencies[iterations] = stopwatch.timeTaken() * 1e6L;
|
||||
state.SetIterationTime(latencies[iterations] / 1e9L);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
++iterations;
|
||||
}
|
||||
|
||||
sockaddr_in6 client;
|
||||
socklen_t clientlen = sizeof(client);
|
||||
int accepted = accept(listensocket, (sockaddr *) &client, &clientlen);
|
||||
if (accepted < 0) {
|
||||
state.SkipWithError(StringPrintf("accept() failed with errno=%d", errno).c_str());
|
||||
close(sock);
|
||||
break;
|
||||
}
|
||||
|
||||
close(accepted);
|
||||
close(sock);
|
||||
}
|
||||
close(listensocket);
|
||||
// ALOGI("Finished test on port = %d", port);
|
||||
|
||||
if (iterations > 0) {
|
||||
latencies.resize(iterations);
|
||||
sort(latencies.begin(), latencies.end());
|
||||
state.SetLabel(StringPrintf("%lld", (long long) latencies[iterations * 9 / 10]));
|
||||
}
|
||||
}
|
||||
|
||||
static void ipv6_loopback(benchmark::State& state, const bool waitBetweenRuns) {
|
||||
const int listensocket = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
const int port = bindAndListen(listensocket);
|
||||
if (port == -1) {
|
||||
state.SkipWithError("Unable to bind server socket");
|
||||
return;
|
||||
}
|
||||
|
||||
// ALOGW("Listening on port = %d", port);
|
||||
std::vector<uint64_t> latencies(state.max_iterations);
|
||||
uint64_t iterations = 0;
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
int sock = socket(AF_INET6, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
state.SkipWithError(StringPrintf("socket() failed with errno=%d", errno).c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
const Stopwatch stopwatch;
|
||||
|
||||
sockaddr_in6 server = { .sin6_family = AF_INET6, .sin6_port = htons(port) };
|
||||
if (connect(sock, (sockaddr*) &server, sizeof(server))) {
|
||||
state.SkipWithError(StringPrintf("connect() failed with errno=%d", errno).c_str());
|
||||
close(sock);
|
||||
break;
|
||||
}
|
||||
|
||||
if (waitBetweenRuns) {
|
||||
latencies[iterations] = stopwatch.timeTaken() * 1e6L;
|
||||
state.SetIterationTime(latencies[iterations] / 1e9L);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
++iterations;
|
||||
}
|
||||
|
||||
sockaddr_in6 client;
|
||||
socklen_t clientlen = sizeof(client);
|
||||
int accepted = accept(listensocket, (sockaddr *) &client, &clientlen);
|
||||
if (accepted < 0) {
|
||||
state.SkipWithError(StringPrintf("accept() failed with errno=%d", errno).c_str());
|
||||
close(sock);
|
||||
break;
|
||||
}
|
||||
|
||||
close(accepted);
|
||||
close(sock);
|
||||
}
|
||||
close(listensocket);
|
||||
// ALOGI("Finished test on port = %d", port);
|
||||
|
||||
if (iterations > 0) {
|
||||
latencies.resize(iterations);
|
||||
sort(latencies.begin(), latencies.end());
|
||||
state.SetLabel(StringPrintf("%lld", (long long) latencies[iterations * 9 / 10]));
|
||||
}
|
||||
}
|
||||
|
||||
static void run_at_reporting_level(decltype(ipv4_loopback) benchmarkFunction,
|
||||
::benchmark::State& state, const int reportingLevel,
|
||||
const bool waitBetweenRuns) {
|
||||
// Our master thread (thread_index == 0) will control setup and teardown for other threads.
|
||||
const bool isMaster = (state.thread_index == 0);
|
||||
|
||||
// Previous values of env variables used by fwmarkclient (only read/written by master thread)
|
||||
const std::string savedSettings[] = {
|
||||
FwmarkClient::ANDROID_NO_USE_FWMARK_CLIENT,
|
||||
FwmarkClient::ANDROID_FWMARK_METRICS_ONLY
|
||||
};
|
||||
std::map<std::string, std::string> prevSettings;
|
||||
|
||||
// SETUP
|
||||
if (isMaster) {
|
||||
for (const auto setting : savedSettings) {
|
||||
const char* prevEnvStr = getenv(setting.c_str());
|
||||
if (prevEnvStr != nullptr) {
|
||||
prevSettings[setting.c_str()] = prevEnvStr;
|
||||
}
|
||||
}
|
||||
switch (reportingLevel) {
|
||||
case INetdEventListener::REPORTING_LEVEL_NONE:
|
||||
setenv(FwmarkClient::ANDROID_NO_USE_FWMARK_CLIENT, "", 1);
|
||||
break;
|
||||
case INetdEventListener::REPORTING_LEVEL_METRICS:
|
||||
unsetenv(FwmarkClient::ANDROID_NO_USE_FWMARK_CLIENT);
|
||||
setenv(FwmarkClient::ANDROID_FWMARK_METRICS_ONLY, "", 1);
|
||||
break;
|
||||
case INetdEventListener::REPORTING_LEVEL_FULL:
|
||||
unsetenv(FwmarkClient::ANDROID_NO_USE_FWMARK_CLIENT);
|
||||
unsetenv(FwmarkClient::ANDROID_FWMARK_METRICS_ONLY);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TEST
|
||||
benchmarkFunction(state, waitBetweenRuns);
|
||||
|
||||
// TEARDOWN
|
||||
if (isMaster) {
|
||||
for (const auto setting : savedSettings) {
|
||||
if (prevSettings.count(setting)) {
|
||||
setenv(setting.c_str(), prevSettings[setting].c_str(), 1);
|
||||
} else {
|
||||
unsetenv(setting.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constexpr int MIN_THREADS = 1;
|
||||
constexpr int MAX_THREADS = 1;
|
||||
constexpr double MIN_TIME = 0.5 /* seconds */;
|
||||
|
||||
static void ipv4_metrics_reporting_no_fwmark(::benchmark::State& state) {
|
||||
run_at_reporting_level(ipv4_loopback, state, INetdEventListener::REPORTING_LEVEL_NONE, true);
|
||||
}
|
||||
BENCHMARK(ipv4_metrics_reporting_no_fwmark)->MinTime(MIN_TIME)->UseManualTime();
|
||||
|
||||
// IPv4 metrics under low load
|
||||
static void ipv4_metrics_reporting_no_load(::benchmark::State& state) {
|
||||
run_at_reporting_level(ipv4_loopback, state, INetdEventListener::REPORTING_LEVEL_METRICS, true);
|
||||
}
|
||||
BENCHMARK(ipv4_metrics_reporting_no_load)->MinTime(MIN_TIME)->UseManualTime();
|
||||
|
||||
static void ipv4_full_reporting_no_load(::benchmark::State& state) {
|
||||
run_at_reporting_level(ipv4_loopback, state, INetdEventListener::REPORTING_LEVEL_FULL, true);
|
||||
}
|
||||
BENCHMARK(ipv4_full_reporting_no_load)->MinTime(MIN_TIME)->UseManualTime();
|
||||
|
||||
// IPv4 benchmarks under high load
|
||||
static void ipv4_metrics_reporting_high_load(::benchmark::State& state) {
|
||||
run_at_reporting_level(ipv4_loopback, state, INetdEventListener::REPORTING_LEVEL_METRICS,
|
||||
false);
|
||||
}
|
||||
BENCHMARK(ipv4_metrics_reporting_high_load)
|
||||
->ThreadRange(MIN_THREADS, MAX_THREADS)->MinTime(MIN_TIME)->UseRealTime();
|
||||
|
||||
static void ipv4_full_reporting_high_load(::benchmark::State& state) {
|
||||
run_at_reporting_level(ipv4_loopback, state, INetdEventListener::REPORTING_LEVEL_FULL, false);
|
||||
}
|
||||
BENCHMARK(ipv4_full_reporting_high_load)
|
||||
->ThreadRange(MIN_THREADS, MAX_THREADS)->MinTime(MIN_TIME)->UseRealTime();
|
||||
|
||||
// IPv6 raw connect() without using fwmark
|
||||
static void ipv6_metrics_reporting_no_fwmark(::benchmark::State& state) {
|
||||
run_at_reporting_level(ipv6_loopback, state, INetdEventListener::REPORTING_LEVEL_NONE, true);
|
||||
}
|
||||
BENCHMARK(ipv6_metrics_reporting_no_fwmark)->MinTime(MIN_TIME)->UseManualTime();
|
||||
|
||||
// IPv6 metrics under low load
|
||||
static void ipv6_metrics_reporting_no_load(::benchmark::State& state) {
|
||||
run_at_reporting_level(ipv6_loopback, state, INetdEventListener::REPORTING_LEVEL_METRICS, true);
|
||||
}
|
||||
BENCHMARK(ipv6_metrics_reporting_no_load)->MinTime(MIN_TIME)->UseManualTime();
|
||||
|
||||
static void ipv6_full_reporting_no_load(::benchmark::State& state) {
|
||||
run_at_reporting_level(ipv6_loopback, state, INetdEventListener::REPORTING_LEVEL_FULL, true);
|
||||
}
|
||||
BENCHMARK(ipv6_full_reporting_no_load)->MinTime(MIN_TIME)->UseManualTime();
|
||||
|
||||
// IPv6 benchmarks under high load
|
||||
static void ipv6_metrics_reporting_high_load(::benchmark::State& state) {
|
||||
run_at_reporting_level(ipv6_loopback, state, INetdEventListener::REPORTING_LEVEL_METRICS,
|
||||
false);
|
||||
}
|
||||
BENCHMARK(ipv6_metrics_reporting_high_load)
|
||||
->ThreadRange(MIN_THREADS, MAX_THREADS)->MinTime(MIN_TIME)->UseRealTime();
|
||||
|
||||
static void ipv6_full_reporting_high_load(::benchmark::State& state) {
|
||||
run_at_reporting_level(ipv6_loopback, state, INetdEventListener::REPORTING_LEVEL_FULL, false);
|
||||
}
|
||||
BENCHMARK(ipv6_full_reporting_high_load)
|
||||
->ThreadRange(MIN_THREADS, MAX_THREADS)->MinTime(MIN_TIME)->UseRealTime();
|
194
android/system/netd/tests/benchmarks/dns_benchmark.cpp
Normal file
194
android/system/netd/tests/benchmarks/dns_benchmark.cpp
Normal file
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "dns_benchmark"
|
||||
|
||||
/*
|
||||
* See README.md for general notes.
|
||||
*
|
||||
* This set of benchmarks measures the throughput of getaddrinfo() on between 1 and 32 threads for
|
||||
* the purpose of keeping track of the maximum load that netd can reasonably handle.
|
||||
*
|
||||
* The benchmark fixture runs in 3 different modes:
|
||||
*
|
||||
* - getaddrinfo_log_nothing
|
||||
*
|
||||
* The control case. Switches all kinds of DNS events reporting off and runs getaddrinfo() in a
|
||||
* loop until the timer expires.
|
||||
*
|
||||
* This was the default and only mode in all versions before 7.0.
|
||||
*
|
||||
* - getaddrinfo_log_metrics
|
||||
*
|
||||
* DNS Logging Lite™ includes staple favourites such as event type (getaddrinfo/gethostbyname),
|
||||
* return code, and latency, but misses out in-depth information such as resolved IP addresses.
|
||||
*
|
||||
* It is expected that this is a little slower than getaddrinfo_log_nothing because of the
|
||||
* overhead, but not particularly worse, since it is a oneway binder call without too much data
|
||||
* being sent per event.
|
||||
*
|
||||
* This was the default mode between versions 7.0 and 7.1 inclusive.
|
||||
*
|
||||
* - getaddrinfo_log_everything
|
||||
*
|
||||
* DNS Logging, in full HD, includes extra non-metrics fields such as hostname, a truncated
|
||||
* list of resolved addresses, total resolved address count, and originating UID.
|
||||
*
|
||||
* Useful measurements
|
||||
* ===================
|
||||
*
|
||||
* - real_time: the average time taken to make a single getaddrinfo lookup on a local DNS resolver
|
||||
* run by DnsFixture. This will usually be higher on multithreaded tests as threads
|
||||
* block on DNS lookups and Binder connections.
|
||||
*
|
||||
* - iterations: total number of runs finished within the time limit. Higher is better. This is
|
||||
* roughly proportional to MinTime * nThreads / real_time.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <utils/String16.h>
|
||||
#include <utils/StrongPointer.h>
|
||||
|
||||
#include "dns_responder_client.h"
|
||||
#include "NetdClient.h"
|
||||
#include "android/net/metrics/INetdEventListener.h"
|
||||
|
||||
using android::base::StringPrintf;
|
||||
using android::net::metrics::INetdEventListener;
|
||||
|
||||
constexpr int MIN_THREADS = 1;
|
||||
constexpr int MAX_THREADS = 32;
|
||||
|
||||
class DnsFixture : public ::benchmark::Fixture {
|
||||
protected:
|
||||
static constexpr unsigned num_hosts = 1000;
|
||||
DnsResponderClient dns;
|
||||
std::vector<DnsResponderClient::Mapping> mappings;
|
||||
std::vector<std::unique_ptr<test::DNSResponder>> mDns;
|
||||
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& state) override {
|
||||
if (state.thread_index == 0) {
|
||||
dns.SetUp();
|
||||
|
||||
std::vector<std::string> domains = { "example.com" };
|
||||
std::vector<std::string> servers;
|
||||
dns.SetupMappings(num_hosts, domains, &mappings);
|
||||
|
||||
dns.SetupDNSServers(MAXNS, mappings, &mDns, &servers);
|
||||
|
||||
const std::vector<int> mDefaultParams_Binder = { 300, 25, 8, 8 };
|
||||
dns.SetResolversForNetwork(servers, domains, mDefaultParams_Binder);
|
||||
}
|
||||
}
|
||||
|
||||
void TearDown(const ::benchmark::State& state) override {
|
||||
if (state.thread_index == 0) {
|
||||
dns.ShutdownDNSServers(&mDns);
|
||||
dns.TearDown();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<DnsResponderClient::Mapping> const& getMappings() const {
|
||||
return mappings;
|
||||
}
|
||||
|
||||
android::sp<android::net::INetd> getNetd() const {
|
||||
return dns.mNetdSrv;
|
||||
}
|
||||
|
||||
void getaddrinfo_until_done(benchmark::State &state) {
|
||||
while (state.KeepRunning()) {
|
||||
const uint32_t ofs = arc4random_uniform(getMappings().size());
|
||||
const auto& mapping = getMappings()[ofs];
|
||||
addrinfo* result = nullptr;
|
||||
if (getaddrinfo(mapping.host.c_str(), nullptr, nullptr, &result)) {
|
||||
state.SkipWithError(StringPrintf("getaddrinfo failed with errno=%d",
|
||||
errno).c_str());
|
||||
break;
|
||||
}
|
||||
if (result) {
|
||||
freeaddrinfo(result);
|
||||
result = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void benchmark_at_reporting_level(benchmark::State &state, int metricsLevel) {
|
||||
const bool isMaster = (state.thread_index == 0);
|
||||
int oldMetricsLevel;
|
||||
|
||||
// SETUP
|
||||
if (isMaster) {
|
||||
auto rv = getNetd()->getMetricsReportingLevel(&oldMetricsLevel);
|
||||
if (!rv.isOk()) {
|
||||
state.SkipWithError(StringPrintf("Failed saving metrics reporting level: %s",
|
||||
rv.toString8().string()).c_str());
|
||||
return;
|
||||
}
|
||||
rv = getNetd()->setMetricsReportingLevel(metricsLevel);
|
||||
if (!rv.isOk()) {
|
||||
state.SkipWithError(StringPrintf("Failed changing metrics reporting: %s",
|
||||
rv.toString8().string()).c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// TEST
|
||||
getaddrinfo_until_done(state);
|
||||
|
||||
// TEARDOWN
|
||||
if (isMaster) {
|
||||
auto rv = getNetd()->setMetricsReportingLevel(oldMetricsLevel);
|
||||
if (!rv.isOk()) {
|
||||
state.SkipWithError(StringPrintf("Failed restoring metrics reporting level: %s",
|
||||
rv.toString8().string()).c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// DNS calls without any metrics logged or sent.
|
||||
BENCHMARK_DEFINE_F(DnsFixture, getaddrinfo_log_nothing)(benchmark::State& state) {
|
||||
benchmark_at_reporting_level(state, INetdEventListener::REPORTING_LEVEL_NONE);
|
||||
}
|
||||
BENCHMARK_REGISTER_F(DnsFixture, getaddrinfo_log_nothing)
|
||||
->ThreadRange(MIN_THREADS, MAX_THREADS)
|
||||
->UseRealTime();
|
||||
|
||||
// DNS calls with metrics only (netId, latency, return code) sent to the system server.
|
||||
BENCHMARK_DEFINE_F(DnsFixture, getaddrinfo_log_metrics)(benchmark::State& state) {
|
||||
benchmark_at_reporting_level(state, INetdEventListener::REPORTING_LEVEL_METRICS);
|
||||
}
|
||||
BENCHMARK_REGISTER_F(DnsFixture, getaddrinfo_log_metrics)
|
||||
->ThreadRange(MIN_THREADS, MAX_THREADS)
|
||||
->UseRealTime();
|
||||
|
||||
// DNS calls with all information logged and sent to the system server.
|
||||
BENCHMARK_DEFINE_F(DnsFixture, getaddrinfo_log_everything)(benchmark::State& state) {
|
||||
benchmark_at_reporting_level(state, INetdEventListener::REPORTING_LEVEL_FULL);
|
||||
}
|
||||
BENCHMARK_REGISTER_F(DnsFixture, getaddrinfo_log_everything)
|
||||
->ThreadRange(MIN_THREADS, MAX_THREADS)
|
||||
->UseRealTime();
|
19
android/system/netd/tests/benchmarks/main.cpp
Normal file
19
android/system/netd/tests/benchmarks/main.cpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
BENCHMARK_MAIN();
|
Loading…
Add table
Add a link
Reference in a new issue