[ledger][benchmark] Add first memory usage benchmark.
Test: put_memory.tspec
This CL introduces LedgerMemoryEstimator, providing an API to capture
Ledger's memory usage. This API is used in this CL to measure the
memory usage after every insertion in the `put` benchmark.
Change-Id: I2822f649e1382875b21327f3d5dbf215eac94fd4
diff --git a/peridot/tests/benchmarks/benchmarks.cc b/peridot/tests/benchmarks/benchmarks.cc
index 53e3127..7b64fd0 100644
--- a/peridot/tests/benchmarks/benchmarks.cc
+++ b/peridot/tests/benchmarks/benchmarks.cc
@@ -45,6 +45,7 @@
benchmarks_runner.AddTspecBenchmark("ledger.disk_space_updates", "/pkgfs/packages/ledger_benchmarks/0/data/disk_space_updates.tspec");
benchmarks_runner.AddTspecBenchmark("ledger.disk_space_one_commit_per_entry", "/pkgfs/packages/ledger_benchmarks/0/data/disk_space_one_commit_per_entry.tspec");
benchmarks_runner.AddTspecBenchmark("ledger.disk_space_cleared_page", "/pkgfs/packages/ledger_benchmarks/0/data/disk_space_cleared_page.tspec");
+ benchmarks_runner.AddTspecBenchmark("ledger.put_memory", "/pkgfs/packages/ledger_benchmarks/0/data/put_memory.tspec");
benchmarks_runner.AddTspecBenchmark("modular.story_runner.json", "/pkgfs/packages/modular_benchmarks/0/data/modular_benchmark_story.tspec", "fuchsia.modular");
// clang-format on
diff --git a/src/ledger/bin/testing/BUILD.gn b/src/ledger/bin/testing/BUILD.gn
index 822df1f..386d1bd 100644
--- a/src/ledger/bin/testing/BUILD.gn
+++ b/src/ledger/bin/testing/BUILD.gn
@@ -27,6 +27,8 @@
"get_page_ensure_initialized.h",
"ledger_matcher.cc",
"ledger_matcher.h",
+ "ledger_memory_usage.cc",
+ "ledger_memory_usage.h",
"page_data_generator.cc",
"page_data_generator.h",
"quit_on_error.cc",
@@ -61,7 +63,9 @@
"//third_party/googletest:gtest",
"//third_party/rapidjson",
"//zircon/public/lib/fit",
+ "//zircon/public/lib/task-utils",
"//zircon/public/lib/trace-provider",
+ "//zircon/public/lib/zx",
]
deps = [
diff --git a/src/ledger/bin/testing/ledger_memory_usage.cc b/src/ledger/bin/testing/ledger_memory_usage.cc
new file mode 100644
index 0000000..a84ac04
--- /dev/null
+++ b/src/ledger/bin/testing/ledger_memory_usage.cc
@@ -0,0 +1,117 @@
+// Copyright 2019 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 "src/ledger/bin/testing/ledger_memory_usage.h"
+
+#include <lib/zx/object.h>
+#include <lib/zx/process.h>
+#include <src/lib/fxl/logging.h>
+#include <src/lib/fxl/strings/string_view.h>
+#include <task-utils/walker.h>
+#include <zircon/status.h>
+#include <zircon/syscalls.h>
+
+#include <string>
+
+namespace ledger {
+namespace {
+
+constexpr fxl::StringView kLedgerBinaryName = "ledger.cmx";
+
+// Retrieves the name of the task with the given handle. Returns true on
+// success, or false otherwise.
+bool GetTaskName(zx::unowned<zx::process>& task, std::string* name) {
+ char task_name[ZX_MAX_NAME_LEN];
+ zx_status_t status =
+ task->get_property(ZX_PROP_NAME, task_name, ZX_MAX_NAME_LEN);
+ if (status != ZX_OK) {
+ // Failed to get the name of task.
+ return false;
+ }
+ *name = std::string(task_name);
+ return true;
+}
+
+// Retrieves the private bytes used by the given task. Returns true on success,
+// or false otherwise.
+bool GetMemoryUsageForTask(zx::process& task, uint64_t* memory) {
+ zx_info_task_stats_t info;
+ zx_status_t status =
+ task.get_info(ZX_INFO_TASK_STATS, &info, sizeof(info), nullptr, nullptr);
+ if (status != ZX_OK) {
+ return false;
+ }
+ *memory = info.mem_private_bytes;
+ return true;
+}
+
+// |Walker| is a |TaskEnumerator| used to find the Ledger process and the
+// corresponding handle.
+class Walker final : public TaskEnumerator {
+ public:
+ Walker() = default;
+ ~Walker() = default;
+
+ // TaskEnumerator:
+ zx_status_t OnProcess(int depth, zx_handle_t task, zx_koid_t koid,
+ zx_koid_t /*pkoid*/) override {
+ zx::unowned<zx::process> unowned_task(task);
+ std::string process_name;
+ FXL_CHECK(GetTaskName(unowned_task, &process_name));
+ if (process_name == kLedgerBinaryName) {
+ if (ledger_handle_.is_valid()) {
+ // This is the second Ledger process we find: interrupt the iteration by
+ // returning a status different than |ZK_OK|.
+ return ZX_ERR_ALREADY_EXISTS;
+ }
+ // This process corresponds to Ledger.
+ FXL_CHECK(unowned_task->duplicate(ZX_RIGHT_SAME_RIGHTS,
+ &ledger_handle_) == ZX_OK);
+ }
+ return ZX_OK;
+ }
+
+ // Returns the handle of the Ledger process, or an invalid handle if it was
+ // not found. This method should be called only after a successful termination
+ // of |Walker::WalkRootJobTree()|. The caller takes ownership of the returned
+ // handle, meaning that this method can only be called once.
+ zx::process TakeLedgerHandle() { return std::move(ledger_handle_); }
+
+ protected:
+ // TaskEnumerator:
+ bool has_on_process() const override { return true; }
+
+ private:
+ zx::process ledger_handle_;
+};
+
+} // namespace
+
+LedgerMemoryEstimator::LedgerMemoryEstimator() = default;
+LedgerMemoryEstimator::~LedgerMemoryEstimator() = default;
+
+bool LedgerMemoryEstimator::Init() {
+ FXL_DCHECK(!ledger_task_.is_valid()) << "Init should only be called once";
+ Walker walker;
+ zx_status_t status = walker.WalkRootJobTree();
+ if (status == ZX_ERR_ALREADY_EXISTS) {
+ // TODO(nellyv): Update so that we know how which Ledger corresponds to the
+ // test being executed.
+ FXL_LOG(ERROR) << "More than one Ledger processes are running.";
+ return false;
+ }
+ ledger_task_ = walker.TakeLedgerHandle();
+ if (!ledger_task_.is_valid()) {
+ FXL_LOG(ERROR) << "Failed to find a Ledger process.";
+ return false;
+ }
+ return true;
+}
+
+bool LedgerMemoryEstimator::GetLedgerMemoryUsage(uint64_t* memory) {
+ FXL_CHECK(ledger_task_);
+ return GetMemoryUsageForTask(ledger_task_, memory);
+}
+
+} // namespace ledger
diff --git a/src/ledger/bin/testing/ledger_memory_usage.h b/src/ledger/bin/testing/ledger_memory_usage.h
new file mode 100644
index 0000000..ddb5151
--- /dev/null
+++ b/src/ledger/bin/testing/ledger_memory_usage.h
@@ -0,0 +1,39 @@
+// Copyright 2019 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.
+
+#ifndef SRC_LEDGER_BIN_TESTING_LEDGER_MEMORY_USAGE_H_
+#define SRC_LEDGER_BIN_TESTING_LEDGER_MEMORY_USAGE_H_
+
+#include <lib/fit/function.h>
+#include <lib/zx/object.h>
+#include <lib/zx/process.h>
+
+namespace ledger {
+
+// Allows estimating Ledger's memory usage. Assumes there is a single ledger
+// process running throughout the lifetime of a |LedgerMemoryEstimator| object.
+class LedgerMemoryEstimator {
+ public:
+ LedgerMemoryEstimator();
+ ~LedgerMemoryEstimator();
+
+ // Initializes the |LedgerMemoryEstimator|. This must be called before any
+ // call to |GetLedgerMemoryUsage|. Ledger must already be running before
+ // |Init()| is called.
+ bool Init();
+
+ // Updates |memory| to store the memory usage, in bytes, of the Ledger binary.
+ // This only includes the private bytes, not the shared memory. Returns true
+ // on success; false otherwise.
+ // Note that a successfull call to |Init()| must be made before calling this
+ // method.
+ bool GetLedgerMemoryUsage(uint64_t* memory);
+
+ private:
+ zx::process ledger_task_;
+};
+
+} // namespace ledger
+
+#endif // SRC_LEDGER_BIN_TESTING_LEDGER_MEMORY_USAGE_H_
diff --git a/src/ledger/bin/tests/benchmark/BUILD.gn b/src/ledger/bin/tests/benchmark/BUILD.gn
index 327a8e4..c259be1 100644
--- a/src/ledger/bin/tests/benchmark/BUILD.gn
+++ b/src/ledger/bin/tests/benchmark/BUILD.gn
@@ -272,6 +272,11 @@
},
{
+ path = rebase_path("put/put_memory.tspec")
+ dest = "put_memory.tspec"
+ },
+
+ {
path = rebase_path("put/put_as_reference.tspec")
dest = "put_as_reference.tspec"
},
diff --git a/src/ledger/bin/tests/benchmark/README.md b/src/ledger/bin/tests/benchmark/README.md
index 5c8af85..e31c0ac 100644
--- a/src/ledger/bin/tests/benchmark/README.md
+++ b/src/ledger/bin/tests/benchmark/README.md
@@ -100,6 +100,8 @@
* `put_as_reference.tspec`: entries are put as references (CreateReference +
PutReference)
* `transaction.tspec`: changes are made in a transaction
+ * `put_memory.tspec`: how much memory is Ledger using after every insertion
+ in the basic case?
* __Update entry__: How long does it take to update an existing value in Ledger
(make several Put operations with the same key, but different values)?
* `update_entry.tspec`: basic case
diff --git a/src/ledger/bin/tests/benchmark/put/put.cc b/src/ledger/bin/tests/benchmark/put/put.cc
index f9555dd..d6b28e0 100644
--- a/src/ledger/bin/tests/benchmark/put/put.cc
+++ b/src/ledger/bin/tests/benchmark/put/put.cc
@@ -19,6 +19,7 @@
#include "src/ledger/bin/testing/data_generator.h"
#include "src/ledger/bin/testing/get_ledger.h"
#include "src/ledger/bin/testing/get_page_ensure_initialized.h"
+#include "src/ledger/bin/testing/ledger_memory_usage.h"
#include "src/ledger/bin/testing/page_data_generator.h"
#include "src/ledger/bin/testing/quit_on_error.h"
#include "src/ledger/bin/testing/run_with_tracing.h"
@@ -119,6 +120,7 @@
// Whether all expected watch notifications have been received. Shut down
// should be blocked until this is set to true.
bool all_watcher_notifications_received_ = false;
+ LedgerMemoryEstimator memory_estimator_;
FXL_DISALLOW_COPY_AND_ASSIGN(PutBenchmark);
};
@@ -167,6 +169,7 @@
if (QuitOnError(QuitLoopClosure(), status, "GetLedger")) {
return;
}
+ FXL_CHECK(memory_estimator_.Init());
GetPageEnsureInitialized(
&ledger_, nullptr, DelayCallback::YES, QuitLoopClosure(),
@@ -266,6 +269,10 @@
}
PutEntry(std::move(keys[i]), std::move(value),
[this, i, key_number, keys = std::move(keys)]() mutable {
+ uint64_t memory;
+ FXL_CHECK(memory_estimator_.GetLedgerMemoryUsage(&memory));
+ TRACE_COUNTER("benchmark", "ledger_memory_put", i, "memory",
+ TA_UINT64(memory));
if (transaction_size_ > 0 &&
(i % transaction_size_ == transaction_size_ - 1 ||
i + 1 == entry_count_)) {
diff --git a/src/ledger/bin/tests/benchmark/put/put.cmx b/src/ledger/bin/tests/benchmark/put/put.cmx
index 465d50a..f5d82fa 100644
--- a/src/ledger/bin/tests/benchmark/put/put.cmx
+++ b/src/ledger/bin/tests/benchmark/put/put.cmx
@@ -3,6 +3,7 @@
"binary": "bin/ledger_benchmark_put"
},
"sandbox": {
+ "dev": [ "misc/sysinfo" ],
"features": [
"isolated-persistent-storage"
],
diff --git a/src/ledger/bin/tests/benchmark/put/put_memory.tspec b/src/ledger/bin/tests/benchmark/put/put_memory.tspec
new file mode 100644
index 0000000..2ff28e2
--- /dev/null
+++ b/src/ledger/bin/tests/benchmark/put/put_memory.tspec
@@ -0,0 +1,22 @@
+{
+ "test_suite_name": "fuchsia.ledger.put_entry",
+ "app": "fuchsia-pkg://fuchsia.com/ledger_benchmarks#meta/put.cmx",
+ "args": [
+ "--entry-count=100", "--transaction-size=0", "--key-size=100",
+ "--value-size=1000", "--refs=off"
+ ],
+ "categories": ["benchmark", "ledger"],
+ "duration": 60,
+ "measure": [
+ {
+ "type": "argument_value",
+ "output_test_name": "put_memory/memory",
+ "event_name": "ledger_memory_put",
+ "event_category": "benchmark",
+ "argument_name": "memory",
+ "argument_unit": "bytes",
+ "expected_sample_count": 100,
+ "split_first": true
+ }
+ ]
+}