Skip to content

Commit

Permalink
perf: add new BPS tree variations benchmarks
Browse files Browse the repository at this point in the history
These add three new configs to be tested in the benchmarks: tree with
child cardinalities enabled, with inner cardinality enabled and with
both of these.

Since there's a lot of tests to run, most of them were disabled to
not hold the GitHub `perf_micro` pipeline for so long. These can be
enabled by defining `ENABLE_EXTRA_BENCHMARKS` as 1.

NO_DOC=new benchmarks
NO_TEST=new benchmarks
NO_CHANGELOG=new benchmarks
  • Loading branch information
mkostoevr committed Apr 17, 2024
1 parent be71197 commit 8011d9a
Showing 1 changed file with 149 additions and 20 deletions.
169 changes: 149 additions & 20 deletions perf/bps_tree.cc
Expand Up @@ -4,13 +4,19 @@
#include <inttypes.h>
#include <time.h>
#include <random>
#include <memory>

#include <benchmark/benchmark.h>
#include <trivia/util.h>

/* A config to enable height-based and first/last/inc/dec benchmarks. */
#define ENABLE_EXTRA_BENCHMARKS 0

#define BPS_TREE_NO_DEBUG 1

/* A simple test tree. */

#define tree_i64_EXTENT_SIZE 2048
#define tree_i64_EXTENT_SIZE 8192
#define tree_i64_elem_t int64_t
#define tree_i64_key_t int64_t
#define BPS_TREE_NAME tree_i64_t
Expand All @@ -31,6 +37,83 @@
#undef bps_tree_elem_t
#undef bps_tree_key_t

/* Tree with child cardinalities of inner blocks. */

#define BPS_INNER_CHILD_CARDS
#define treecc_i64_EXTENT_SIZE 8192
#define treecc_i64_elem_t int64_t
#define treecc_i64_key_t int64_t
#define BPS_TREE_NAME treecc_i64_t
#define BPS_TREE_BLOCK_SIZE 512
#define BPS_TREE_EXTENT_SIZE treecc_i64_EXTENT_SIZE
#define BPS_TREE_IS_IDENTICAL(a, b) ((a) == (b))
#define BPS_TREE_COMPARE(a, b, arg) ((a) - (b))
#define BPS_TREE_COMPARE_KEY(a, b, arg) ((a) - (b))
#define bps_tree_elem_t treecc_i64_elem_t
#define bps_tree_key_t treecc_i64_key_t
#include "salad/bps_tree.h"
#undef BPS_TREE_NAME
#undef BPS_TREE_BLOCK_SIZE
#undef BPS_TREE_EXTENT_SIZE
#undef BPS_TREE_IS_IDENTICAL
#undef BPS_TREE_COMPARE
#undef BPS_TREE_COMPARE_KEY
#undef bps_tree_elem_t
#undef bps_tree_key_t
#undef BPS_INNER_CHILD_CARDS

/* Tree with inner block cardinalities. */

#define BPS_INNER_CARD
#define treeic_i64_EXTENT_SIZE 8192
#define treeic_i64_elem_t int64_t
#define treeic_i64_key_t int64_t
#define BPS_TREE_NAME treeic_i64_t
#define BPS_TREE_BLOCK_SIZE 512
#define BPS_TREE_EXTENT_SIZE treeic_i64_EXTENT_SIZE
#define BPS_TREE_IS_IDENTICAL(a, b) ((a) == (b))
#define BPS_TREE_COMPARE(a, b, arg) ((a) - (b))
#define BPS_TREE_COMPARE_KEY(a, b, arg) ((a) - (b))
#define bps_tree_elem_t treeic_i64_elem_t
#define bps_tree_key_t treeic_i64_key_t
#include "salad/bps_tree.h"
#undef BPS_TREE_NAME
#undef BPS_TREE_BLOCK_SIZE
#undef BPS_TREE_EXTENT_SIZE
#undef BPS_TREE_IS_IDENTICAL
#undef BPS_TREE_COMPARE
#undef BPS_TREE_COMPARE_KEY
#undef bps_tree_elem_t
#undef bps_tree_key_t
#undef BPS_INNER_CARD

/* Tree with inner block cardinalities and child cardinalities. */

#define BPS_INNER_CHILD_CARDS
#define BPS_INNER_CARD
#define treebo_i64_EXTENT_SIZE 8192
#define treebo_i64_elem_t int64_t
#define treebo_i64_key_t int64_t
#define BPS_TREE_NAME treebo_i64_t
#define BPS_TREE_BLOCK_SIZE 512
#define BPS_TREE_EXTENT_SIZE treebo_i64_EXTENT_SIZE
#define BPS_TREE_IS_IDENTICAL(a, b) ((a) == (b))
#define BPS_TREE_COMPARE(a, b, arg) ((a) - (b))
#define BPS_TREE_COMPARE_KEY(a, b, arg) ((a) - (b))
#define bps_tree_elem_t treebo_i64_elem_t
#define bps_tree_key_t treebo_i64_key_t
#include "salad/bps_tree.h"
#undef BPS_TREE_NAME
#undef BPS_TREE_BLOCK_SIZE
#undef BPS_TREE_EXTENT_SIZE
#undef BPS_TREE_IS_IDENTICAL
#undef BPS_TREE_COMPARE
#undef BPS_TREE_COMPARE_KEY
#undef bps_tree_elem_t
#undef bps_tree_key_t
#undef BPS_INNER_CARD
#undef BPS_INNER_CHILD_CARDS

/**
* Generate the benchmark variations required.
*/
Expand All @@ -44,20 +127,31 @@
BENCHMARK(type##_##func##_size_##size)

/* Run the func benchmark on the tree of the given height (max size). */
#if ENABLE_EXTRA_BENCHMARKS
#define generate_benchmark_height(type, func, height) static void \
type##_##func##_height_##height(benchmark::State &state) \
{ \
test_##func<type>(state, type::height_##height##_max_size); \
} \
BENCHMARK(type##_##func##_height_##height)
#else
#define generate_benchmark_height(...)
#endif

/* The same as generate_benchmark_size, but sets iterations explicitly. */
#define generate_benchmark_size_iterations(type, func, size) \
generate_benchmark_size(type, func, size)->Iterations(size)

/* Meant to create specified benchmarks for all trees. */
#if ENABLE_EXTRA_BENCHMARKS
#define generate_benchmarks(generator, func, arg) \
generator(tree_i64, func, arg)
generator(tree_i64, func, arg); \
generator(treecc_i64, func, arg); \
generator(treeic_i64, func, arg); \
generator(treebo_i64, func, arg)
#else
#define generate_benchmarks(generator, func, arg) generator(tree_i64, func, arg)
#endif

/* Create size-based benchmarks for all trees. */
#define generate_benchmarks_size(func, size) \
Expand All @@ -81,16 +175,19 @@
*/
template<int EXTENT_SIZE>
class DummyAllocator {
std::vector<char> m_buf;
std::unique_ptr<char[]> m_buf;
size_t m_buf_size;
size_t m_pos = 0;

public:
DummyAllocator(size_t size)
: m_buf(((size + EXTENT_SIZE - 1) / EXTENT_SIZE) * EXTENT_SIZE)
{
/* Any BPS Tree requires 3 extents on the first insert. */
if (m_buf.size() < EXTENT_SIZE * 3)
m_buf.resize(EXTENT_SIZE * 3);
m_buf_size = ((size + EXTENT_SIZE - 1) / EXTENT_SIZE) *
EXTENT_SIZE;
/* The calculated size is incorrect for small trees. */
if (m_buf_size < EXTENT_SIZE * 10)
m_buf_size = EXTENT_SIZE * 10;
m_buf = std::unique_ptr<char[]>(new char[m_buf_size]);
}

void
Expand All @@ -105,7 +202,7 @@ class DummyAllocator {
DummyAllocator *self = (DummyAllocator *)ctx;
void *result = (void *)&self->m_buf[self->m_pos];
self->m_pos += EXTENT_SIZE;
if (unlikely(self->m_pos > self->m_buf.size())) {
if (unlikely(self->m_pos > self->m_buf_size)) {
fprintf(stderr, "Ouf of bounds allocation.\n");
exit(-1);
}
Expand Down Expand Up @@ -160,6 +257,9 @@ public: \

/* The class must be created for each instantiated BPS tree to test it. */
CREATE_TREE_CLASS(tree_i64);
CREATE_TREE_CLASS(treecc_i64);
CREATE_TREE_CLASS(treeic_i64);
CREATE_TREE_CLASS(treebo_i64);

/**
* Value generators to make key-independent benchmarks.
Expand Down Expand Up @@ -230,16 +330,17 @@ template<class tree>
static void
test_build(benchmark::State &state, size_t count)
{
std::vector<typename tree::elem_t> arr;
auto arr = std::unique_ptr<typename tree::elem_t[]>(
new typename tree::elem_t[count]);
for (size_t i = 0; i < count; i++)
arr.emplace_back(i);
arr[i] = i;

typename tree::Allocator allocator(count);
for (auto _ : state) {
typename tree::tree_t t;
tree::create(&t, 0, allocator.alloc, allocator.free,
&allocator, NULL);
tree::build(&t, &arr.front(), count);
tree::build(&t, &arr[0], count);
tree::destroy(&t);
allocator.reset();
}
Expand All @@ -252,21 +353,27 @@ template<class tree, class KeyGen>
static void
test_find(benchmark::State &state, size_t count, KeyGen kg)
{
std::vector<typename tree::elem_t> arr;
auto arr = std::unique_ptr<typename tree::elem_t[]>(
new typename tree::elem_t[count]);
for (size_t i = 0; i < count; i++)
arr.emplace_back(i);
arr[i] = i;

typename tree::Allocator allocator(count);

typename tree::tree_t t;
tree::create(&t, 0, allocator.alloc, allocator.free,
&allocator, NULL);
tree::build(&t, &arr.front(), count);
if (tree::build(&t, &arr[0], count) == -1) {
fprintf(stderr, "Tree build has failed.\n");
exit(-1);
}
for (auto _ : state)
benchmark::DoNotOptimize(tree::find(&t, kg()));
tree::destroy(&t);
}

#if ENABLE_EXTRA_BENCHMARKS

template<class tree>
static void
test_find_first(benchmark::State &state, size_t count)
Expand Down Expand Up @@ -327,6 +434,8 @@ generate_benchmarks_height(find_dec, 2);
generate_benchmarks_height(find_dec, 3);
generate_benchmarks_height(find_dec, 4);

#endif

template<class tree>
static void
test_find_rand(benchmark::State &state, size_t count)
Expand All @@ -352,16 +461,20 @@ template<class tree, class KeyGen>
static void
test_delete_insert(benchmark::State &state, size_t count, KeyGen kg)
{
std::vector<typename tree::elem_t> arr;
auto arr = std::unique_ptr<typename tree::elem_t[]>(
new typename tree::elem_t[count]);
for (size_t i = 0; i < count; i++)
arr.emplace_back(i);
arr[i] = i;

typename tree::Allocator allocator(count);

typename tree::tree_t t;
tree::create(&t, 0, allocator.alloc, allocator.free,
&allocator, NULL);
tree::build(&t, &arr.front(), count);
if (tree::build(&t, &arr[0], count) == -1) {
fprintf(stderr, "Tree build has failed.\n");
exit(-1);
}
typename tree::elem_t replaced, successor;
for (auto _ : state) {
typename tree::elem_t elem(kg());
Expand All @@ -371,6 +484,8 @@ test_delete_insert(benchmark::State &state, size_t count, KeyGen kg)
tree::destroy(&t);
}

#if ENABLE_EXTRA_BENCHMARKS

template<class tree>
static void
test_delete_insert_first(benchmark::State &state, size_t count)
Expand Down Expand Up @@ -431,6 +546,8 @@ generate_benchmarks_height(delete_insert_dec, 2);
generate_benchmarks_height(delete_insert_dec, 3);
generate_benchmarks_height(delete_insert_dec, 4);

#endif

template<class tree>
static void
test_delete_insert_rand(benchmark::State &state, size_t count)
Expand Down Expand Up @@ -469,6 +586,8 @@ test_insert(benchmark::State &state, size_t count, KeyGen kg)
tree::destroy(&t);
}

#if ENABLE_EXTRA_BENCHMARKS

template<class tree>
static void
test_insert_first(benchmark::State &state, size_t count)
Expand All @@ -487,6 +606,8 @@ test_insert_last(benchmark::State &state, size_t count)

generate_benchmarks_size_iterations(insert_last, 10000000);

#endif

template<class tree>
static void
test_insert_rand(benchmark::State &state, size_t count)
Expand All @@ -500,21 +621,27 @@ template<class tree, class KeyGen>
static void
test_delete(benchmark::State &state, size_t count, KeyGen kg)
{
std::vector<typename tree::elem_t> arr;
auto arr = std::unique_ptr<typename tree::elem_t[]>(
new typename tree::elem_t[count]);
for (size_t i = 0; i < count; i++)
arr.emplace_back(i);
arr[i] = i;

typename tree::Allocator allocator(count);

typename tree::tree_t t;
tree::create(&t, 0, allocator.alloc, allocator.free,
&allocator, NULL);
tree::build(&t, &arr.front(), count);
if (tree::build(&t, &arr[0], count) == -1) {
fprintf(stderr, "Tree build has failed.\n");
exit(-1);
}
for (auto _ : state)
tree::delete_(&t, kg());
tree::destroy(&t);
}

#if ENABLE_EXTRA_BENCHMARKS

template<class tree>
static void
test_delete_first(benchmark::State &state, size_t count)
Expand All @@ -533,6 +660,8 @@ test_delete_last(benchmark::State &state, size_t count)

generate_benchmarks_size_iterations(delete_last, 10000000);

#endif

template<class tree>
static void
test_delete_rand(benchmark::State &state, size_t count)
Expand Down

0 comments on commit 8011d9a

Please sign in to comment.