| // Copyright 2018 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 <lib/inspect/cpp/inspect.h> |
| #include <lib/inspect/cpp/vmo/heap.h> |
| #include <zircon/syscalls.h> |
| |
| #include <cmath> |
| #include <iostream> |
| #include <sstream> |
| |
| #include <fbl/ref_ptr.h> |
| #include <fbl/string_printf.h> |
| #include <perftest/perftest.h> |
| |
| #include "src/lib/fxl/strings/string_printf.h" |
| |
| namespace { |
| |
| const char* kName = "name"; |
| const size_t kLinearFloor = 10; |
| const size_t kLinearStep = 5; |
| const size_t kExponentialFloor = 10; |
| const size_t kExponentialInitialStep = 5; |
| const size_t kExponentialStepMultiplier = 2; |
| |
| using inspect::Inspector; |
| using inspect::Node; |
| using inspect::internal::BlockIndex; |
| using inspect::internal::Heap; |
| using inspect::internal::NumericProperty; |
| |
| template <typename T> |
| NumericProperty<T> CreateMetric(Node* root); |
| |
| template <> |
| NumericProperty<int64_t> CreateMetric<int64_t>(Node* root) { |
| return root->CreateInt(kName, 0); |
| } |
| |
| template <> |
| NumericProperty<uint64_t> CreateMetric<uint64_t>(Node* root) { |
| return root->CreateUint(kName, 0); |
| } |
| |
| template <> |
| NumericProperty<double> CreateMetric<double>(Node* root) { |
| return root->CreateDouble(kName, 0); |
| } |
| |
| template <typename T> |
| T CreateArrayMetric(Node* root, size_t size); |
| |
| template <> |
| inspect::IntArray CreateArrayMetric(Node* root, size_t size) { |
| return root->CreateIntArray(kName, size); |
| } |
| |
| template <> |
| inspect::UintArray CreateArrayMetric(Node* root, size_t size) { |
| return root->CreateUintArray(kName, size); |
| } |
| |
| template <> |
| inspect::DoubleArray CreateArrayMetric(Node* root, size_t size) { |
| return root->CreateDoubleArray(kName, size); |
| } |
| |
| template <> |
| inspect::LinearIntHistogram CreateArrayMetric(Node* root, size_t size) { |
| return root->CreateLinearIntHistogram(kName, kLinearFloor, kLinearStep, size); |
| } |
| |
| template <> |
| inspect::LinearUintHistogram CreateArrayMetric(Node* root, size_t size) { |
| return root->CreateLinearUintHistogram(kName, kLinearFloor, kLinearStep, size); |
| } |
| |
| template <> |
| inspect::LinearDoubleHistogram CreateArrayMetric(Node* root, size_t size) { |
| return root->CreateLinearDoubleHistogram(kName, kLinearFloor, kLinearStep, size); |
| } |
| |
| template <> |
| inspect::ExponentialIntHistogram CreateArrayMetric(Node* root, size_t size) { |
| return root->CreateExponentialIntHistogram(kName, kExponentialFloor, kExponentialInitialStep, |
| kExponentialStepMultiplier, size); |
| } |
| |
| template <> |
| inspect::ExponentialUintHistogram CreateArrayMetric(Node* root, size_t size) { |
| return root->CreateExponentialUintHistogram(kName, kExponentialFloor, kExponentialInitialStep, |
| kExponentialStepMultiplier, size); |
| } |
| |
| template <> |
| inspect::ExponentialDoubleHistogram CreateArrayMetric(Node* root, size_t size) { |
| return root->CreateExponentialDoubleHistogram(kName, kExponentialFloor, kExponentialInitialStep, |
| kExponentialStepMultiplier, size); |
| } |
| |
| bool TestNodeLifecycle(perftest::RepeatState* state) { |
| auto inspector = Inspector(); |
| auto& root = inspector.GetRoot(); |
| state->DeclareStep("Create"); |
| state->DeclareStep("Destroy"); |
| while (state->KeepRunning()) { |
| auto node = root.CreateChild(kName); |
| state->NextStep(); |
| } |
| return true; |
| } |
| |
| bool TestValueListLifecycle(perftest::RepeatState* state) { |
| struct Dummy { |
| uint64_t value; |
| }; |
| state->DeclareStep("Create"); |
| state->DeclareStep("Enlist"); |
| state->DeclareStep("EnlistAgain"); |
| state->DeclareStep("Destroy"); |
| while (state->KeepRunning()) { |
| inspect::ValueList list; |
| state->NextStep(); |
| list.emplace(Dummy{.value = 0}); |
| state->NextStep(); |
| list.emplace(Dummy{.value = 1}); |
| state->NextStep(); |
| } |
| return true; |
| } |
| |
| template <typename T> |
| bool TestMetricLifecycle(perftest::RepeatState* state) { |
| auto inspector = Inspector(); |
| auto& root = inspector.GetRoot(); |
| state->DeclareStep("Create"); |
| state->DeclareStep("Destroy"); |
| while (state->KeepRunning()) { |
| auto item = CreateMetric<T>(&root); |
| state->NextStep(); |
| } |
| return true; |
| } |
| |
| template <typename T> |
| bool TestArrayLifecycle(perftest::RepeatState* state, size_t size) { |
| auto inspector = Inspector(); |
| auto& root = inspector.GetRoot(); |
| state->DeclareStep("Create"); |
| state->DeclareStep("Destroy"); |
| while (state->KeepRunning()) { |
| auto item = CreateArrayMetric<T>(&root, size); |
| state->NextStep(); |
| } |
| return true; |
| } |
| |
| // Measure the time taken to set and modify NumericProperty. |
| template <typename T> |
| bool TestMetricModify(perftest::RepeatState* state) { |
| auto inspector = Inspector(); |
| auto& root = inspector.GetRoot(); |
| auto item = CreateMetric<T>(&root); |
| |
| state->DeclareStep("Set"); |
| state->DeclareStep("Add"); |
| state->DeclareStep("Subtract"); |
| |
| while (state->KeepRunning()) { |
| item.Set(1); |
| state->NextStep(); |
| item.Add(1); |
| state->NextStep(); |
| item.Subtract(1); |
| } |
| return true; |
| } |
| |
| template <typename T> |
| bool TestArrayModify(perftest::RepeatState* state, int size) { |
| auto inspector = Inspector(inspect::InspectSettings{.maximum_size = 1024 * 1024}); |
| auto& root = inspector.GetRoot(); |
| auto item = CreateArrayMetric<T>(&root, size); |
| |
| state->DeclareStep("Set"); |
| state->DeclareStep("Add"); |
| state->DeclareStep("Subtract"); |
| |
| int i = 0; |
| while (state->KeepRunning()) { |
| item.Set(i, 1); |
| state->NextStep(); |
| item.Add(i, 1); |
| state->NextStep(); |
| item.Subtract(i, 1); |
| i = (i + 1) % size; |
| } |
| return true; |
| } |
| |
| template <typename T> |
| bool TestHistogramInsert(perftest::RepeatState* state, int size, int value) { |
| auto inspector = Inspector(inspect::InspectSettings{.maximum_size = 1024 * 1024}); |
| auto& root = inspector.GetRoot(); |
| auto item = CreateArrayMetric<T>(&root, size); |
| |
| const int underflow_value = 0; |
| const int overflow_value = 10000000; |
| |
| state->DeclareStep("InsertUnderflow"); |
| state->DeclareStep("InsertOverflow"); |
| state->DeclareStep("InsertValue"); |
| |
| while (state->KeepRunning()) { |
| item.Insert(underflow_value); |
| state->NextStep(); |
| item.Insert(overflow_value); |
| state->NextStep(); |
| item.Insert(value); |
| } |
| return true; |
| } |
| |
| // Measure the time taken to set and modify Property. |
| bool TestProperty(perftest::RepeatState* state, int size) { |
| auto inspector = Inspector(inspect::InspectSettings{.maximum_size = 1024 * 1024}); |
| auto& root = inspector.GetRoot(); |
| auto item = root.CreateString(kName, ""); |
| std::string string; |
| string.resize(size, 'a'); |
| |
| state->DeclareStep("Create"); |
| state->DeclareStep("Set"); |
| state->DeclareStep("SetAgain"); |
| state->DeclareStep("Destroy"); |
| |
| while (state->KeepRunning()) { |
| auto item = root.CreateString(kName, ""); |
| state->NextStep(); |
| item.Set(string); |
| state->NextStep(); |
| item.Set(string); |
| state->NextStep(); |
| } |
| return true; |
| } |
| |
| // Measure how long it takes to allocate and extend a heap. |
| bool TestHeapExtend(perftest::RepeatState* state) { |
| zx::vmo vmo; |
| |
| state->DeclareStep("Create 1MB VMO"); |
| state->DeclareStep("Allocate 512K"); |
| state->DeclareStep("Extend"); |
| state->DeclareStep("Free"); |
| state->DeclareStep("Destroy"); |
| |
| while (state->KeepRunning()) { |
| BlockIndex index[513]; |
| if (zx::vmo::create(1 << 21, 0, &vmo) != ZX_OK) { |
| return false; |
| } |
| |
| auto heap = Heap(std::move(vmo)); |
| state->NextStep(); |
| |
| for (int i = 0; i < 512; i++) { |
| if (heap.Allocate(2048, &index[i]) != ZX_OK) { |
| return false; |
| } |
| } |
| state->NextStep(); |
| |
| if (heap.Allocate(2048, &index[512]) != ZX_OK) { |
| return false; |
| } |
| |
| state->NextStep(); |
| |
| for (int i = 512; i >= 0; i--) { |
| heap.Free(index[i]); |
| } |
| state->NextStep(); |
| } |
| |
| return true; |
| } |
| |
| void RegisterTests() { |
| perftest::RegisterTest("Inspect/ValueList/Lifecycle", TestValueListLifecycle); |
| perftest::RegisterTest("Inspect/Node/Lifecycle", TestNodeLifecycle); |
| perftest::RegisterTest("Inspect/IntMetric/Lifecycle", TestMetricLifecycle<int64_t>); |
| perftest::RegisterTest("Inspect/IntMetric/Modify", TestMetricModify<int64_t>); |
| perftest::RegisterTest("Inspect/UintMetric/Lifecycle", TestMetricLifecycle<uint64_t>); |
| perftest::RegisterTest("Inspect/UintMetric/Modify", TestMetricModify<uint64_t>); |
| perftest::RegisterTest("Inspect/DoubleMetric/Lifecycle", TestMetricLifecycle<double>); |
| perftest::RegisterTest("Inspect/DoubleMetric/Modify", TestMetricModify<double>); |
| for (auto size : {32, 128, 240}) { /* stop at 240 to fit in block */ |
| perftest::RegisterTest(fxl::StringPrintf("Inspect/UintArray/Lifecycle/%d", size).c_str(), |
| TestArrayLifecycle<inspect::UintArray>, size); |
| perftest::RegisterTest(fxl::StringPrintf("Inspect/UintArray/Modify/%d", size).c_str(), |
| TestArrayModify<inspect::UintArray>, size); |
| perftest::RegisterTest(fxl::StringPrintf("Inspect/IntArray/Lifecycle/%d", size).c_str(), |
| TestArrayLifecycle<inspect::IntArray>, size); |
| perftest::RegisterTest(fxl::StringPrintf("Inspect/IntArray/Modify/%d", size).c_str(), |
| TestArrayModify<inspect::IntArray>, size); |
| perftest::RegisterTest(fxl::StringPrintf("Inspect/DoubleArray/Lifecycle/%d", size).c_str(), |
| TestArrayLifecycle<inspect::DoubleArray>, size); |
| perftest::RegisterTest(fxl::StringPrintf("Inspect/DoubleArray/Modify/%d", size).c_str(), |
| TestArrayModify<inspect::DoubleArray>, size); |
| |
| const int linear_midpoint = kLinearFloor + (size / 2) * kLinearStep; |
| perftest::RegisterTest( |
| fxl::StringPrintf("Inspect/LinearUintHistogram/Lifecycle/%d", size).c_str(), |
| TestArrayLifecycle<inspect::LinearUintHistogram>, size); |
| perftest::RegisterTest(fxl::StringPrintf("Inspect/LinearUintHistogram/Insert/%d", size).c_str(), |
| TestHistogramInsert<inspect::LinearUintHistogram>, size, |
| linear_midpoint); |
| perftest::RegisterTest( |
| fxl::StringPrintf("Inspect/LinearIntHistogram/Lifecycle/%d", size).c_str(), |
| TestArrayLifecycle<inspect::LinearIntHistogram>, size); |
| perftest::RegisterTest(fxl::StringPrintf("Inspect/LinearIntHistogram/Insert/%d", size).c_str(), |
| TestHistogramInsert<inspect::LinearIntHistogram>, size, linear_midpoint); |
| perftest::RegisterTest( |
| fxl::StringPrintf("Inspect/LinearDoubleHistogram/Lifecycle/%d", size).c_str(), |
| TestArrayLifecycle<inspect::LinearDoubleHistogram>, size); |
| perftest::RegisterTest( |
| fxl::StringPrintf("Inspect/LinearDoubleHistogram/Insert/%d", size).c_str(), |
| TestHistogramInsert<inspect::LinearDoubleHistogram>, size, linear_midpoint); |
| } |
| for (auto size : {4, 16, 32}) { |
| const int exponential_midpoint = |
| static_cast<int>(kExponentialFloor + |
| kExponentialInitialStep * std::pow(kExponentialStepMultiplier, size / 2)); |
| perftest::RegisterTest( |
| fxl::StringPrintf("Inspect/ExponentialUintHistogram/Lifecycle/%d", size).c_str(), |
| TestArrayLifecycle<inspect::ExponentialUintHistogram>, size); |
| perftest::RegisterTest( |
| fxl::StringPrintf("Inspect/ExponentialUintHistogram/Insert/%d", size).c_str(), |
| TestHistogramInsert<inspect::ExponentialUintHistogram>, size, exponential_midpoint); |
| perftest::RegisterTest( |
| fxl::StringPrintf("Inspect/ExponentialIntHistogram/Lifecycle/%d", size).c_str(), |
| TestArrayLifecycle<inspect::ExponentialIntHistogram>, size); |
| perftest::RegisterTest( |
| fxl::StringPrintf("Inspect/ExponentialIntHistogram/Insert/%d", size).c_str(), |
| TestHistogramInsert<inspect::ExponentialIntHistogram>, size, exponential_midpoint); |
| perftest::RegisterTest( |
| fxl::StringPrintf("Inspect/ExponentialDoubleHistogram/Lifecycle/%d", size).c_str(), |
| TestArrayLifecycle<inspect::ExponentialDoubleHistogram>, size); |
| perftest::RegisterTest( |
| fxl::StringPrintf("Inspect/ExponentialDoubleHistogram/Insert/%d", size).c_str(), |
| TestHistogramInsert<inspect::ExponentialDoubleHistogram>, size, exponential_midpoint); |
| } |
| for (auto size : {4, 8, 100, 2000, 2048, 10000}) { |
| perftest::RegisterTest(fxl::StringPrintf("Inspect/Property/%d", size).c_str(), TestProperty, |
| size); |
| } |
| perftest::RegisterTest("Inspect/Heap/Extend", TestHeapExtend); |
| } |
| PERFTEST_CTOR(RegisterTests); |
| |
| } // namespace |