Skip to content

Commit

Permalink
index btree benchmark
Browse files Browse the repository at this point in the history
  • Loading branch information
JacksonYao287 committed Dec 16, 2023
1 parent 91bea03 commit 6bac914
Show file tree
Hide file tree
Showing 10 changed files with 292 additions and 118 deletions.
2 changes: 1 addition & 1 deletion conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

class HomestoreConan(ConanFile):
name = "homestore"
version = "4.9.2"
version = "4.9.3"

homepage = "https://github.com/eBay/Homestore"
description = "HomeStore Storage Engine"
Expand Down
5 changes: 4 additions & 1 deletion src/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,8 @@ if (${non_coverage_build})
add_executable(log_store_benchmark)
target_sources(log_store_benchmark PRIVATE log_store_benchmark.cpp)
target_link_libraries(log_store_benchmark hs_logdev homestore ${COMMON_TEST_DEPS} benchmark::benchmark)
#add_test(NAME LogStoreBench COMMAND test_log_benchmark)

add_executable(index_btree_benchmark)
target_sources(index_btree_benchmark PRIVATE index_btree_benchmark.cpp)
target_link_libraries(index_btree_benchmark homestore ${COMMON_TEST_DEPS} benchmark::benchmark)
endif()
59 changes: 59 additions & 0 deletions src/tests/btree_helpers/btree_decls.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@

/*********************************************************************************
* Modifications Copyright 2017-2019 eBay Inc.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*********************************************************************************/
#pragma once

#include <homestore/index/index_table.hpp>

struct FixedLenBtree {
using BtreeType = IndexTable< TestFixedKey, TestFixedValue >;
using KeyType = TestFixedKey;
using ValueType = TestFixedValue;
static constexpr btree_node_type leaf_node_type = btree_node_type::FIXED;
static constexpr btree_node_type interior_node_type = btree_node_type::FIXED;
};

struct VarKeySizeBtree {
using BtreeType = IndexTable< TestVarLenKey, TestFixedValue >;
using KeyType = TestVarLenKey;
using ValueType = TestFixedValue;
static constexpr btree_node_type leaf_node_type = btree_node_type::VAR_KEY;
static constexpr btree_node_type interior_node_type = btree_node_type::VAR_KEY;
};

struct VarValueSizeBtree {
using BtreeType = IndexTable< TestVarLenKey, TestVarLenValue >;
using KeyType = TestVarLenKey;
using ValueType = TestVarLenValue;
static constexpr btree_node_type leaf_node_type = btree_node_type::VAR_OBJECT;
static constexpr btree_node_type interior_node_type = btree_node_type::VAR_OBJECT;
};

struct VarObjSizeBtree {
using BtreeType = IndexTable< TestVarLenKey, TestVarLenValue >;
using KeyType = TestVarLenKey;
using ValueType = TestVarLenValue;
static constexpr btree_node_type leaf_node_type = btree_node_type::VAR_OBJECT;
static constexpr btree_node_type interior_node_type = btree_node_type::VAR_OBJECT;
};

struct PrefixIntervalBtree {
using BtreeType = IndexTable< TestIntervalKey, TestIntervalValue >;
using KeyType = TestIntervalKey;
using ValueType = TestIntervalValue;
static constexpr btree_node_type leaf_node_type = btree_node_type::PREFIX;
static constexpr btree_node_type interior_node_type = btree_node_type::FIXED;
};
57 changes: 47 additions & 10 deletions src/tests/btree_helpers/btree_test_helper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,37 +13,35 @@
* specific language governing permissions and limitations under the License.
*
*********************************************************************************/
#pragma once

#include <random>
#include <map>
#include <atomic>
#include <memory>
#include <gtest/gtest.h>
#include <iomgr/io_environment.hpp>
#include <sisl/options/options.h>
#include <sisl/logging/logging.h>
#include <sisl/utility/enum.hpp>
#include <boost/algorithm/string.hpp>

#include <homestore/btree/detail/simple_node.hpp>
#include <homestore/btree/detail/varlen_node.hpp>
#include <homestore/btree/detail/prefix_node.hpp>
#include <homestore/btree/mem_btree.hpp>
#include "test_common/range_scheduler.hpp"
#include "shadow_map.hpp"
#include "btree_test_kvs.hpp"

static constexpr uint32_t g_node_size{4096};

template < typename TestType >
struct BtreeTestHelper : public testing::Test {
struct BtreeTestHelper {
using T = TestType;
using K = typename TestType::KeyType;
using V = typename TestType::ValueType;
using mutex = iomgr::FiberManagerLib::shared_mutex;
using op_func_t = std::function< void(void) >;

BtreeTestHelper() : testing::Test(), m_shadow_map{SISL_OPTIONS["num_entries"].as< uint32_t >()} {}
BtreeTestHelper() : m_shadow_map{SISL_OPTIONS["num_entries"].as< uint32_t >()} {}

void SetUp() override {
void SetUp() {
m_cfg.m_leaf_node_type = T::leaf_node_type;
m_cfg.m_int_node_type = T::interior_node_type;
m_max_range_input = SISL_OPTIONS["num_entries"].as< uint32_t >();
Expand All @@ -66,7 +64,7 @@ struct BtreeTestHelper : public testing::Test {
m_operations["query"] = std::bind(&BtreeTestHelper::query_random, this);
}

void TearDown() override {}
void TearDown() {}

protected:
std::shared_ptr< typename T::BtreeType > m_bt;
Expand All @@ -82,6 +80,7 @@ struct BtreeTestHelper : public testing::Test {
std::condition_variable m_test_done_cv;

std::random_device m_re;
std::atomic< uint32_t > m_num_ops{0};

public:
void preload(uint32_t preload_size) {
Expand Down Expand Up @@ -110,6 +109,8 @@ struct BtreeTestHelper : public testing::Test {
LOGINFO("Preload Done");
}

uint32_t get_op_num() const { return m_num_ops.load(); }

////////////////////// All put operation variants ///////////////////////////////
void put(uint64_t k, btree_put_type put_type) { do_put(k, put_type, V::generate_rand()); }

Expand Down Expand Up @@ -364,6 +365,7 @@ struct BtreeTestHelper : public testing::Test {
}
}

protected:
void run_in_parallel(const std::vector< std::pair< std::string, int > >& op_list) {
auto test_count = m_fibers.size();
for (auto it = m_fibers.begin(); it < m_fibers.end(); ++it) {
Expand All @@ -379,10 +381,13 @@ struct BtreeTestHelper : public testing::Test {
// Construct a weighted distribution based on the input frequencies
std::discrete_distribution< uint32_t > s_rand_op_generator(weights.begin(), weights.end());
auto m_start_time = Clock::now();
auto time_to_stop = [this, m_start_time]() {return (get_elapsed_time_sec(m_start_time) > m_run_time);};
auto time_to_stop = [this, m_start_time]() {
return (get_elapsed_time_sec(m_start_time) > m_run_time);
};
for (uint32_t i = 0; i < num_iters_per_thread && !time_to_stop(); i++) {
uint32_t op_idx = s_rand_op_generator(re);
(this->m_operations[op_list[op_idx].first])();
m_num_ops.fetch_add(1);
}
{
std::unique_lock lg(m_test_done_mtx);
Expand All @@ -397,4 +402,36 @@ struct BtreeTestHelper : public testing::Test {
}
LOGINFO("ALL parallel jobs joined");
}

std::vector< std::pair< std::string, int > > build_op_list(std::vector< std::string >& input_ops) {
std::vector< std::pair< std::string, int > > ops;
int total = std::accumulate(input_ops.begin(), input_ops.end(), 0, [](int sum, const auto& str) {
std::vector< std::string > tokens;
boost::split(tokens, str, boost::is_any_of(":"));
if (tokens.size() == 2) {
try {
return sum + std::stoi(tokens[1]);
} catch (const std::exception&) {
// Invalid frequency, ignore this element
}
}
return sum; // Ignore malformed strings
});

std::transform(input_ops.begin(), input_ops.end(), std::back_inserter(ops), [total](const auto& str) {
std::vector< std::string > tokens;
boost::split(tokens, str, boost::is_any_of(":"));
if (tokens.size() == 2) {
try {
return std::make_pair(tokens[0], (int)(100.0 * std::stoi(tokens[1]) / total));
} catch (const std::exception&) {
// Invalid frequency, ignore this element
}
}
return std::make_pair(std::string(), 0);
});

return ops;
// this->run_in_parallel(ops);
}
};
5 changes: 5 additions & 0 deletions src/tests/btree_helpers/btree_test_kvs.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,17 @@
*
*********************************************************************************/
#pragma once

#include <string>
#include <random>
#include <map>
#include <memory>
#include <array>

#include <homestore/btree/btree_kv.hpp>
#include <homestore/btree/detail/simple_node.hpp>
#include <homestore/btree/detail/varlen_node.hpp>
#include <homestore/btree/detail/prefix_node.hpp>

static constexpr uint32_t g_max_keysize{100}; // for node size = 512 : free space : 442 => 100+100+6(record size) = 46%
static constexpr uint32_t g_max_valsize{100};
Expand Down
142 changes: 142 additions & 0 deletions src/tests/index_btree_benchmark.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*********************************************************************************
* Modifications Copyright 2017-2019 eBay Inc.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed
* under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
* CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
*********************************************************************************/

#include <benchmark/benchmark.h>
#include <boost/uuid/random_generator.hpp>
#include <stdint.h>

#include <iomgr/io_environment.hpp>
#include <sisl/options/options.h>
#include <homestore/btree/detail/btree_internal.hpp>
#include "test_common/homestore_test_common.hpp"
#include "btree_helpers/btree_test_kvs.hpp"
#include "test_common/range_scheduler.hpp"
#include "btree_helpers/btree_test_helper.hpp"
#include "btree_helpers/btree_decls.h"

using namespace homestore;

#define INDEX_BETREE_BENCHMARK(BTREE_TYPE) \
BENCHMARK(run_benchmark< BTREE_TYPE >) \
->Setup(BM_Setup< BTREE_TYPE >) \
->Teardown(BM_Teardown< BTREE_TYPE >) \
->UseRealTime() \
->Iterations(1) \
->Name(#BTREE_TYPE);

// this is used to splite the setup and teardown from the benchmark to get a more accurate result
void* globle_helper{nullptr};

#define GET_BENCHMARK_HELPER(BTREE_TYPE) static_cast< IndexBtreeBenchmark< BTREE_TYPE >* >(globle_helper)

SISL_LOGGING_INIT(HOMESTORE_LOG_MODS)
std::vector< std::string > test_common::HSTestHelper::s_dev_names;
SISL_OPTIONS_ENABLE(logging, index_btree_benchmark, iomgr, test_common_setup)

SISL_OPTION_GROUP(index_btree_benchmark,
(num_iters, "", "num_iters", "number of iterations for rand ops",
::cxxopts::value< uint32_t >()->default_value("500"), "number"),
(num_entries, "", "num_entries", "number of entries to test with",
::cxxopts::value< uint32_t >()->default_value("5000"), "number"),
(run_time, "", "run_time", "run time for io", ::cxxopts::value< uint32_t >()->default_value("30"),
"seconds"),
(operation_list, "", "operation_list",
"operation list instead of default created following by percentage",
::cxxopts::value< std::vector< std::string > >()->default_value({"put:100"}), "operations [...]"),
(preload_size, "", "preload_size", "number of entries to preload tree with",
::cxxopts::value< uint32_t >()->default_value("1000"), "number"))

template < typename TestType >
struct IndexBtreeBenchmark : public BtreeTestHelper< TestType > {
using T = TestType;
using K = typename TestType::KeyType;
using V = typename TestType::ValueType;
IndexBtreeBenchmark() { SetUp(); }

~IndexBtreeBenchmark() { TearDown(); }

void SetUp() {
test_common::HSTestHelper::start_homestore(
"index_btree_benchmark", {{HS_SERVICE::META, {.size_pct = 10.0}}, {HS_SERVICE::INDEX, {.size_pct = 70.0}}});

this->m_cfg = BtreeConfig(hs()->index_service().node_size());
this->m_is_multi_threaded = true;

auto uuid = boost::uuids::random_generator()();
auto parent_uuid = boost::uuids::random_generator()();

BtreeTestHelper< TestType >::SetUp();
this->m_bt = std::make_shared< typename T::BtreeType >(uuid, parent_uuid, 0, this->m_cfg);
hs()->index_service().add_index_table(this->m_bt);
auto input_ops = SISL_OPTIONS["operation_list"].as< std::vector< std::string > >();
m_op_list = this->build_op_list(input_ops);
}

void TearDown() {
BtreeTestHelper< TestType >::TearDown();
test_common::HSTestHelper::shutdown_homestore();
}

void run_benchmark() { this->run_in_parallel(m_op_list); }

private:
std::vector< std::pair< std::string, int > > m_op_list;
};

template < class BenchmarkType >
void BM_Setup(const benchmark::State& state) {
globle_helper = new IndexBtreeBenchmark< BenchmarkType >();
auto helper = GET_BENCHMARK_HELPER(BenchmarkType);
helper->preload(SISL_OPTIONS["preload_size"].as< uint32_t >());
}

template < class BenchmarkType >
void BM_Teardown(const benchmark::State& state) {
delete GET_BENCHMARK_HELPER(BenchmarkType);
}

template < class BenchmarkType >
void add_custom_counter(benchmark::State& state) {
auto helper = GET_BENCHMARK_HELPER(BenchmarkType);
auto totol_ops = helper->get_op_num();
state.counters["thread_num"] = SISL_OPTIONS["num_threads"].as< uint32_t >();
state.counters["fiber_num"] = SISL_OPTIONS["num_fibers"].as< uint32_t >();
state.counters["total_ops"] = totol_ops;
state.counters["rate"] = benchmark::Counter(totol_ops, benchmark::Counter::kIsRate);
state.counters["InvRate"] =
benchmark::Counter(totol_ops, benchmark::Counter::kIsRate | benchmark::Counter::kInvert);
}

template < class BenchmarkType >
void run_benchmark(benchmark::State& state) {
auto helper = GET_BENCHMARK_HELPER(BenchmarkType);
for (auto _ : state) {
helper->run_benchmark();
}
add_custom_counter< BenchmarkType >(state);
}

INDEX_BETREE_BENCHMARK(FixedLenBtree)
INDEX_BETREE_BENCHMARK(VarKeySizeBtree)
INDEX_BETREE_BENCHMARK(VarValueSizeBtree)
INDEX_BETREE_BENCHMARK(VarObjSizeBtree)
INDEX_BETREE_BENCHMARK(PrefixIntervalBtree)

int main(int argc, char** argv) {
SISL_OPTIONS_LOAD(argc, argv, logging, index_btree_benchmark, iomgr, test_common_setup);
::benchmark::Initialize(&argc, argv);
::benchmark::RunSpecifiedBenchmarks();
}
3 changes: 0 additions & 3 deletions src/tests/test_btree_node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,6 @@
*
*********************************************************************************/
#include <gtest/gtest.h>
#include <random>
#include <map>
#include <memory>

#include <sisl/options/options.h>
#include <sisl/logging/logging.h>
Expand Down
Loading

0 comments on commit 6bac914

Please sign in to comment.