| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <iostream> |
| #include <vector> |
| |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/component/cpp/startup_context.h> |
| #include <lib/fidl/cpp/optional.h> |
| #include <lib/fit/function.h> |
| #include <lib/fxl/command_line.h> |
| #include <lib/fxl/files/directory.h> |
| #include <lib/fxl/files/scoped_temp_dir.h> |
| #include <lib/fxl/logging.h> |
| #include <lib/fxl/strings/string_number_conversions.h> |
| #include <lib/zx/time.h> |
| #include <trace/event.h> |
| |
| #include "peridot/bin/ledger/fidl/include/types.h" |
| #include "peridot/bin/ledger/testing/data_generator.h" |
| #include "peridot/bin/ledger/testing/get_ledger.h" |
| #include "peridot/bin/ledger/testing/get_page_ensure_initialized.h" |
| #include "peridot/bin/ledger/testing/quit_on_error.h" |
| #include "peridot/bin/ledger/testing/run_with_tracing.h" |
| #include "peridot/lib/rng/test_random.h" |
| |
| namespace ledger { |
| namespace { |
| |
| constexpr fxl::StringView kBinaryPath = |
| "fuchsia-pkg://fuchsia.com/ledger_benchmarks#meta/get_page.cmx"; |
| constexpr fxl::StringView kStoragePath = "/data/benchmark/ledger/get_page"; |
| constexpr fxl::StringView kPageCountFlag = "requests-count"; |
| constexpr fxl::StringView kReuseFlag = "reuse"; |
| constexpr fxl::StringView kWaitForCachedPageFlag = "wait-for-cached-page"; |
| |
| constexpr zx::duration kDuration = zx::msec(500); |
| |
| void PrintUsage() { |
| std::cout << "Usage: trace record " |
| << kBinaryPath |
| // Comment to make clang format not break formatting. |
| << " --" << kPageCountFlag << "=<int>" |
| << " [--" << kReuseFlag << "]" |
| << " [--" << kWaitForCachedPageFlag << "]" << std::endl; |
| } |
| |
| // Benchmark that measures the time taken to get a page. |
| // |
| // Parameters: |
| // --requests-count=<int> number of requests made. |
| // --reuse - if this flag is specified, the same id will be used. Otherwise, a |
| // new page with a random id is requested every time. |
| // --wait_for_cached_page - if this flag is specified, the benchmark will wait |
| // for a sufficient amount of time before each page request, to allow Ledger |
| // to precache an empty new page. |
| class GetPageBenchmark { |
| public: |
| GetPageBenchmark(async::Loop* loop, |
| std::unique_ptr<component::StartupContext> startup_context, |
| size_t requests_count, bool reuse, |
| bool wait_for_cached_page); |
| |
| void Run(); |
| |
| private: |
| void RunSingle(size_t request_number); |
| void ShutDown(); |
| fit::closure QuitLoopClosure(); |
| |
| async::Loop* const loop_; |
| rng::TestRandom random_; |
| files::ScopedTempDir tmp_dir_; |
| DataGenerator generator_; |
| std::unique_ptr<component::StartupContext> startup_context_; |
| const size_t requests_count_; |
| const bool reuse_; |
| const bool wait_for_cached_page_; |
| fuchsia::sys::ComponentControllerPtr component_controller_; |
| LedgerPtr ledger_; |
| PageIdPtr page_id_; |
| std::vector<PagePtr> pages_; |
| bool get_page_called_ = false; |
| bool get_page_id_called_ = false; |
| |
| FXL_DISALLOW_COPY_AND_ASSIGN(GetPageBenchmark); |
| }; |
| |
| GetPageBenchmark::GetPageBenchmark( |
| async::Loop* loop, |
| std::unique_ptr<component::StartupContext> startup_context, |
| size_t requests_count, bool reuse, bool wait_for_cached_page) |
| : loop_(loop), |
| random_(0), |
| tmp_dir_(kStoragePath), |
| generator_(&random_), |
| startup_context_(std::move(startup_context)), |
| requests_count_(requests_count), |
| reuse_(reuse), |
| wait_for_cached_page_(wait_for_cached_page) { |
| FXL_DCHECK(loop_); |
| FXL_DCHECK(requests_count_ > 0); |
| } |
| |
| void GetPageBenchmark::Run() { |
| Status status = GetLedger( |
| startup_context_.get(), component_controller_.NewRequest(), nullptr, "", |
| "get_page", DetachedPath(tmp_dir_.path()), QuitLoopClosure(), &ledger_); |
| |
| if (QuitOnError(QuitLoopClosure(), status, "GetLedger")) { |
| return; |
| } |
| |
| page_id_ = fidl::MakeOptional(generator_.MakePageId()); |
| RunSingle(requests_count_); |
| } |
| |
| void GetPageBenchmark::RunSingle(size_t request_number) { |
| if (request_number == 0) { |
| ShutDown(); |
| return; |
| } |
| if (wait_for_cached_page_) { |
| // Wait before each page request, so that a pre-cached page is ready. |
| zx_nanosleep(zx_deadline_after(kDuration.get())); |
| } |
| TRACE_ASYNC_BEGIN("benchmark", "get page", requests_count_ - request_number); |
| PagePtr page; |
| |
| get_page_called_ = false; |
| get_page_id_called_ = false; |
| ledger_->GetPage( |
| reuse_ ? fidl::Clone(page_id_) : nullptr, page.NewRequest(), |
| [this, request_number](Status status) { |
| if (QuitOnError(QuitLoopClosure(), status, "Ledger::GetPage")) { |
| return; |
| } |
| TRACE_ASYNC_END("benchmark", "get page", |
| requests_count_ - request_number); |
| get_page_called_ = true; |
| if (get_page_id_called_) { |
| // Wait for both GetPage and GetId to do the following run. |
| RunSingle(request_number - 1); |
| } |
| }); |
| |
| TRACE_ASYNC_BEGIN("benchmark", "get page id", |
| requests_count_ - request_number); |
| // Request the page id before the GetPage callback is called. |
| page->GetId([this, request_number](PageId found_page_id) { |
| TRACE_ASYNC_END("benchmark", "get page id", |
| requests_count_ - request_number); |
| get_page_id_called_ = true; |
| if (get_page_called_) { |
| // Wait for both GetPage and GetId to do the following run. |
| RunSingle(request_number - 1); |
| } |
| }); |
| |
| pages_.push_back(std::move(page)); |
| } |
| |
| void GetPageBenchmark::ShutDown() { |
| KillLedgerProcess(&component_controller_); |
| loop_->Quit(); |
| } |
| |
| fit::closure GetPageBenchmark::QuitLoopClosure() { |
| return [this] { loop_->Quit(); }; |
| } |
| |
| int Main(int argc, const char** argv) { |
| fxl::CommandLine command_line = fxl::CommandLineFromArgcArgv(argc, argv); |
| async::Loop loop(&kAsyncLoopConfigAttachToThread); |
| auto startup_context = component::StartupContext::CreateFromStartupInfo(); |
| |
| std::string requests_count_str; |
| size_t requests_count; |
| if (!command_line.GetOptionValue(kPageCountFlag.ToString(), |
| &requests_count_str) || |
| !fxl::StringToNumberWithError(requests_count_str, &requests_count) || |
| requests_count == 0) { |
| PrintUsage(); |
| return EXIT_FAILURE; |
| } |
| bool reuse = command_line.HasOption(kReuseFlag); |
| bool wait_for_cached_page = command_line.HasOption(kWaitForCachedPageFlag); |
| |
| GetPageBenchmark app(&loop, std::move(startup_context), requests_count, reuse, |
| wait_for_cached_page); |
| |
| return RunWithTracing(&loop, [&app] { app.Run(); }); |
| } |
| |
| } // namespace |
| } // namespace ledger |
| |
| int main(int argc, const char** argv) { return ledger::Main(argc, argv); } |