blob: e22437dae8567a068fe032f396f59b37700e235a [file] [log] [blame]
// 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 <memory>
#include <lib/async-loop/cpp/loop.h>
#include <lib/async/cpp/task.h>
#include <lib/callback/waiter.h>
#include <lib/component/cpp/startup_context.h>
#include <lib/fit/function.h>
#include <lib/fsl/vmo/strings.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/filesystem/get_directory_content_size.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/page_data_generator.h"
#include "peridot/bin/ledger/testing/quit_on_error.h"
#include "peridot/bin/ledger/testing/run_with_tracing.h"
#include "peridot/lib/convert/convert.h"
#include "peridot/lib/rng/test_random.h"
namespace ledger {
namespace {
constexpr fxl::StringView kBinaryPath =
"fuchsia-pkg://fuchsia.com/ledger_benchmarks#meta/delete_entry.cmx";
constexpr fxl::StringView kStoragePath = "/data/benchmark/ledger/delete_entry";
constexpr fxl::StringView kEntryCountFlag = "entry-count";
constexpr fxl::StringView kTransactionSizeFlag = "transaction-size";
constexpr fxl::StringView kKeySizeFlag = "key-size";
constexpr fxl::StringView kValueSizeFlag = "value-size";
void PrintUsage() {
std::cout << "Usage: trace record "
<< kBinaryPath
// Comment to make clang format not break formatting.
<< " --" << kEntryCountFlag << "=<int>"
<< " --" << kTransactionSizeFlag << "=<int>"
<< " --" << kKeySizeFlag << "=<int>"
<< " --" << kValueSizeFlag << "=<int>" << std::endl;
}
// Benchmark that measures the time taken to delete an entry from a page.
//
// Parameters:
// --entry-count=<int> the number of entries to be put and deleted
// --transaction_size=<int> number of delete operations in each transaction. 0
// means no explicit transactions.
// --key-size=<int> size of the keys for the entries
// --value-size=<int> the size of a single value in bytes
class DeleteEntryBenchmark {
public:
DeleteEntryBenchmark(
async::Loop* loop,
std::unique_ptr<component::StartupContext> startup_context,
size_t entry_count, size_t transaction_size, size_t key_size,
size_t value_size);
void Run();
private:
void Populate();
void RunSingle(size_t i);
void CommitAndRunNext(size_t i);
void ShutDown();
fit::closure QuitLoopClosure();
async::Loop* const loop_;
rng::TestRandom random_;
files::ScopedTempDir tmp_dir_;
DataGenerator generator_;
PageDataGenerator page_data_generator_;
std::unique_ptr<component::StartupContext> startup_context_;
const size_t entry_count_;
const size_t transaction_size_;
const size_t key_size_;
const size_t value_size_;
fuchsia::sys::ComponentControllerPtr component_controller_;
LedgerPtr ledger_;
PagePtr page_;
std::vector<std::vector<uint8_t>> keys_;
FXL_DISALLOW_COPY_AND_ASSIGN(DeleteEntryBenchmark);
};
DeleteEntryBenchmark::DeleteEntryBenchmark(
async::Loop* loop,
std::unique_ptr<component::StartupContext> startup_context,
size_t entry_count, size_t transaction_size, size_t key_size,
size_t value_size)
: loop_(loop),
random_(0),
tmp_dir_(kStoragePath),
generator_(&random_),
page_data_generator_(&random_),
startup_context_(std::move(startup_context)),
entry_count_(entry_count),
transaction_size_(transaction_size),
key_size_(key_size),
value_size_(value_size) {
FXL_DCHECK(loop_);
FXL_DCHECK(entry_count_ > 0);
FXL_DCHECK(transaction_size_ >= 0);
FXL_DCHECK(key_size_ > 0);
FXL_DCHECK(value_size_ > 0);
}
void DeleteEntryBenchmark::Run() {
Status status =
GetLedger(startup_context_.get(), component_controller_.NewRequest(),
nullptr, "", "delete_entry", DetachedPath(tmp_dir_.path()),
QuitLoopClosure(), &ledger_);
if (QuitOnError(QuitLoopClosure(), status, "GetLedger")) {
return;
}
GetPageEnsureInitialized(
&ledger_, nullptr, DelayCallback::YES, QuitLoopClosure(),
[this](Status status, PagePtr page, PageId id) {
if (QuitOnError(QuitLoopClosure(), status, "Page initialization")) {
return;
}
page_ = std::move(page);
Populate();
});
}
void DeleteEntryBenchmark::Populate() {
auto keys = generator_.MakeKeys(entry_count_, key_size_, entry_count_);
for (size_t i = 0; i < entry_count_; i++) {
keys_.push_back(keys[i]);
}
page_data_generator_.Populate(
&page_, std::move(keys), value_size_, entry_count_,
PageDataGenerator::ReferenceStrategy::REFERENCE, Priority::EAGER,
[this](Status status) {
if (status != Status::OK) {
QuitOnError(QuitLoopClosure(), status, "PageGenerator::Populate");
return;
}
if (transaction_size_ > 0) {
page_->StartTransaction([this](Status status) {
if (QuitOnError(QuitLoopClosure(), status,
"Page::StartTransaction")) {
return;
}
TRACE_ASYNC_BEGIN("benchmark", "transaction", 0);
RunSingle(0);
});
} else {
RunSingle(0);
}
});
}
void DeleteEntryBenchmark::RunSingle(size_t i) {
if (i == entry_count_) {
ShutDown();
uint64_t tmp_dir_size = 0;
FXL_CHECK(
GetDirectoryContentSize(DetachedPath(tmp_dir_.path()), &tmp_dir_size));
TRACE_COUNTER("benchmark", "ledger_directory_size", 0, "directory_size",
TA_UINT64(tmp_dir_size));
return;
}
TRACE_ASYNC_BEGIN("benchmark", "delete_entry", i);
page_->Delete(std::move(keys_[i]), [this, i](Status status) {
if (QuitOnError(QuitLoopClosure(), status, "Page::Delete")) {
return;
}
TRACE_ASYNC_END("benchmark", "delete_entry", i);
if (transaction_size_ > 0 &&
(i % transaction_size_ == transaction_size_ - 1 ||
i + 1 == entry_count_)) {
CommitAndRunNext(i);
} else {
RunSingle(i + 1);
}
});
}
void DeleteEntryBenchmark::CommitAndRunNext(size_t i) {
TRACE_ASYNC_BEGIN("benchmark", "commit", i / transaction_size_);
page_->Commit([this, i](Status status) {
if (QuitOnError(QuitLoopClosure(), status, "Page::Commit")) {
return;
}
TRACE_ASYNC_END("benchmark", "commit", i / transaction_size_);
TRACE_ASYNC_END("benchmark", "transaction", i / transaction_size_);
if (i == entry_count_ - 1) {
RunSingle(i + 1);
return;
}
page_->StartTransaction([this, i = i + 1](Status status) {
if (QuitOnError(QuitLoopClosure(), status, "Page::StartTransaction")) {
return;
}
TRACE_ASYNC_BEGIN("benchmark", "transaction", i / transaction_size_);
RunSingle(i);
});
});
}
void DeleteEntryBenchmark::ShutDown() {
KillLedgerProcess(&component_controller_);
loop_->Quit();
}
fit::closure DeleteEntryBenchmark::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 entry_count_str;
size_t entry_count;
std::string transaction_size_str;
size_t transaction_size;
std::string key_size_str;
size_t key_size;
std::string value_size_str;
size_t value_size;
if (!command_line.GetOptionValue(kEntryCountFlag.ToString(),
&entry_count_str) ||
!fxl::StringToNumberWithError(entry_count_str, &entry_count) ||
entry_count == 0 ||
!command_line.GetOptionValue(kTransactionSizeFlag.ToString(),
&transaction_size_str) ||
!fxl::StringToNumberWithError(transaction_size_str, &transaction_size) ||
!command_line.GetOptionValue(kKeySizeFlag.ToString(), &key_size_str) ||
!fxl::StringToNumberWithError(key_size_str, &key_size) || key_size == 0 ||
!command_line.GetOptionValue(kValueSizeFlag.ToString(),
&value_size_str) ||
!fxl::StringToNumberWithError(value_size_str, &value_size) ||
value_size == 0) {
PrintUsage();
return -1;
}
DeleteEntryBenchmark app(&loop, std::move(startup_context), entry_count,
transaction_size, key_size, value_size);
return RunWithTracing(&loop, [&app] { app.Run(); });
}
} // namespace
} // namespace ledger
int main(int argc, const char** argv) { return ledger::Main(argc, argv); }