From a42314e43614f29fd93547a85784dc4f1975f477 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Tue, 19 Dec 2017 15:08:19 -0800 Subject: [PATCH] debuggerd: add pause time benchmark. Add a benchmark to measure how long we pause a process when dumping. Bug: http://b/62112103 Test: manually ran it Change-Id: Iceec2f722915b0ae26144c86dcbeb35793f963da --- debuggerd/Android.bp | 10 +++ debuggerd/debuggerd_benchmark.cpp | 128 ++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 debuggerd/debuggerd_benchmark.cpp diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index c473e3395..7fec47dae 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -218,6 +218,16 @@ cc_test { }, } +cc_benchmark { + name: "debuggerd_benchmark", + defaults: ["debuggerd_defaults"], + srcs: ["debuggerd_benchmark.cpp"], + shared_libs: [ + "libbase", + "libdebuggerd_client", + ], +} + cc_binary { name: "crash_dump", srcs: [ diff --git a/debuggerd/debuggerd_benchmark.cpp b/debuggerd/debuggerd_benchmark.cpp new file mode 100644 index 000000000..37ee214d0 --- /dev/null +++ b/debuggerd/debuggerd_benchmark.cpp @@ -0,0 +1,128 @@ +/* + * Copyright 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. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +using namespace std::chrono_literals; + +static_assert(std::chrono::high_resolution_clock::is_steady); + +enum class ThreadState { Starting, Started, Stopping }; + +static void SetScheduler() { + struct sched_param param { + .sched_priority = 1, + }; + + if (sched_setscheduler(getpid(), SCHED_FIFO, ¶m) != 0) { + fprintf(stderr, "failed to set scheduler to SCHED_FIFO: %s", strerror(errno)); + } +} + +static std::chrono::duration GetMaximumPause(std::atomic& state) { + std::chrono::duration max_diff(0); + + const auto begin = std::chrono::high_resolution_clock::now(); + auto last = begin; + state.store(ThreadState::Started); + while (state.load() != ThreadState::Stopping) { + auto now = std::chrono::high_resolution_clock::now(); + + auto diff = now - last; + if (diff > max_diff) { + max_diff = diff; + } + + last = now; + } + + return max_diff; +} + +static void PerformDump() { + pid_t target = getpid(); + pid_t forkpid = fork(); + if (forkpid == -1) { + err(1, "fork failed"); + } else if (forkpid != 0) { + int status; + pid_t pid = waitpid(forkpid, &status, 0); + if (pid == -1) { + err(1, "waitpid failed"); + } else if (!WIFEXITED(status)) { + err(1, "child didn't exit"); + } else if (WEXITSTATUS(status) != 0) { + errx(1, "child exited with non-zero status %d", WEXITSTATUS(status)); + } + } else { + android::base::unique_fd output_fd(open("/dev/null", O_WRONLY | O_CLOEXEC)); + if (output_fd == -1) { + err(1, "failed to open /dev/null"); + } + + if (!debuggerd_trigger_dump(target, kDebuggerdNativeBacktrace, 1000, std::move(output_fd))) { + errx(1, "failed to trigger dump"); + } + + _exit(0); + } +} + +template +static void BM_maximum_pause_impl(benchmark::State& state, const Fn& function) { + SetScheduler(); + + for (auto _ : state) { + std::chrono::duration max_pause; + std::atomic thread_state(ThreadState::Starting); + auto thread = std::thread([&]() { max_pause = GetMaximumPause(thread_state); }); + + while (thread_state != ThreadState::Started) { + std::this_thread::sleep_for(1ms); + } + + function(); + + thread_state = ThreadState::Stopping; + thread.join(); + + state.SetIterationTime(max_pause.count()); + } +} + +static void BM_maximum_pause_noop(benchmark::State& state) { + BM_maximum_pause_impl(state, []() {}); +} + +static void BM_maximum_pause_debuggerd(benchmark::State& state) { + BM_maximum_pause_impl(state, []() { PerformDump(); }); +} + +BENCHMARK(BM_maximum_pause_noop)->Iterations(128)->UseManualTime(); +BENCHMARK(BM_maximum_pause_debuggerd)->Iterations(128)->UseManualTime(); + +BENCHMARK_MAIN();