blob: 4333c6c20efd64db333ddaadc4eac60d69aa64d9 [file] [log] [blame]
// 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