Commit d8e493d3 authored by Philipp Götze's avatar Philipp Götze
Browse files

🔨 Moved and added new benchmarks

parent ceabcc8d
include(../../cmake/Testing.cmake.in) include(../cmake/Testing.cmake.in)
do_bench(trees/tree_get) do_bench(trees/tree_get)
do_bench(trees/tree_traverse) do_bench(trees/tree_traverse)
do_bench(trees/tree_scan) do_bench(trees/tree_scan)
do_bench(trees/tree_insert) do_bench(trees/tree_insert)
do_bench(trees/tree_split) do_bench(trees/tree_split)
do_bench(trees/tree_erase)
do_bench(trees/tree_balance)
do_bench(trees/tree_merge)
# PTABLE # PTABLE
#do_bench(ptable/insert ptable) #do_bench(ptable/insert ptable)
do_bench(ptable/scan ptable) do_bench(ptable/scan ptable)
......
...@@ -18,9 +18,9 @@ ...@@ -18,9 +18,9 @@
#ifndef PTABLE_COMMON_H #ifndef PTABLE_COMMON_H
#define PTABLE_COMMON_H #define PTABLE_COMMON_H
#include <chrono> #include <libpmempool.h>
#include <unistd.h> #include <unistd.h>
#include <experimental/filesystem> #include <chrono>
#include "ptable/PTable.hpp" #include "ptable/PTable.hpp"
using pmem::obj::make_persistent; using pmem::obj::make_persistent;
...@@ -35,7 +35,7 @@ using PTableType = dbis::ptable::PTable<MyKey, MyTuple>; ...@@ -35,7 +35,7 @@ using PTableType = dbis::ptable::PTable<MyKey, MyTuple>;
using Vector = std::vector<long int>; using Vector = std::vector<long int>;
using VectorVector = std::vector<Vector>; using VectorVector = std::vector<Vector>;
const int hibit_pos(int n) noexcept; int hibit_pos(int n) noexcept;
template <size_t SIZE> template <size_t SIZE>
static inline VectorVector *createPointVector(VectorVector *v); static inline VectorVector *createPointVector(VectorVector *v);
...@@ -78,7 +78,7 @@ const VectorVector NON_KEY_RANGES = { ...@@ -78,7 +78,7 @@ const VectorVector NON_KEY_RANGES = {
Vector{0, NUM_TUPLES - 1, 0, NUM_TUPLES - 1} //100,0% Vector{0, NUM_TUPLES - 1, 0, NUM_TUPLES - 1} //100,0%
}; };
const int hibit_pos(int n) noexcept { int hibit_pos(int n) noexcept {
int c = 0; int c = 0;
while (n>>1 != 0) { while (n>>1 != 0) {
c++; c++;
...@@ -102,13 +102,15 @@ void insert (pool<root> &pop, const std::string &path, size_t entries) { ...@@ -102,13 +102,15 @@ void insert (pool<root> &pop, const std::string &path, size_t entries) {
std::vector<typename std::chrono::duration<int64_t, std::micro>::rep> measures; std::vector<typename std::chrono::duration<int64_t, std::micro>::rep> measures;
pop = pool<root>::create(path, LAYOUT, POOL_SIZE); pop = pool<root>::create(path, LAYOUT, POOL_SIZE);
const auto alloc_class = pop.ctl_set<struct pobj_alloc_class_desc>(
"heap.alloc_class.128.desc", PTableType::IndexType::AllocClass);
transaction::run(pop, [&] { transaction::run(pop, [&] {
const auto tInfo = VTableInfo<MyKey, MyTuple>("MyTable", {"a","b","c","d"}); const auto tInfo = VTableInfo<MyKey, MyTuple>("MyTable", {"a","b","c","d"});
const auto dims = Dimensions({ const auto dims = Dimensions({
{0, 10, ALIGNMENT}, {0, 10, ALIGNMENT},
{3, 10, ALIGNMENT} {3, 10, ALIGNMENT}
}); });
pop.root()->pTable = make_persistent<PTableType>(tInfo, dims); pop.root()->pTable = make_persistent<PTableType>(alloc_class, tInfo, dims);
}); });
auto &pTable = pop.root()->pTable; auto &pTable = pop.root()->pTable;
......
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <experimental/filesystem>
#include "common.hpp" #include "common.hpp"
using namespace dbis::ptable; using namespace dbis::ptable;
...@@ -23,7 +22,7 @@ using namespace dbis::ptable; ...@@ -23,7 +22,7 @@ using namespace dbis::ptable;
int main() { int main() {
pool<root> pop; pool<root> pop;
std::experimental::filesystem::remove_all(path); pmempool_rm(path.c_str(), 0);
if (access(path.c_str(), F_OK) != 0) { if (access(path.c_str(), F_OK) != 0) {
insert(pop, path, NUM_TUPLES); insert(pop, path, NUM_TUPLES);
} else { } else {
......
...@@ -25,33 +25,34 @@ ...@@ -25,33 +25,34 @@
using namespace dbis::ptable; using namespace dbis::ptable;
static void BM_PointQuery(benchmark::State& state) { static void BM_PointQuery(benchmark::State& state) {
pool<root> pop; pool<root> pop;
const std::string path = dbis::gPmemPath + "benchdb" + std::to_string(state.range(0)) + ".db"; const std::string path = dbis::gPmemPath + "benchdb" + std::to_string(state.range(0)) + ".db";
//std::remove(path.c_str()); // std::remove(path.c_str());
if (access(path.c_str(), F_OK) != 0) { if (access(path.c_str(), F_OK) != 0) {
insert(pop, path, state.range(0)); insert(pop, path, state.range(0));
} else { } else {
//std::cerr << "WARNING: Table already exists" << std::endl; // std::cerr << "WARNING: Table already exists" << std::endl;
pop = pool<root>::open(path, LAYOUT); pop = pool<root>::open(path, LAYOUT);
} }
auto &pTable = *pop.root()->pTable; auto& pTable = *pop.root()->pTable;
for (auto _ : state) { for (auto _ : state) {
auto ptp = pTable.getByKey(state.range(1)); auto ptp = pTable.getByKey(state.range(1));
if (ptp.getNode() != nullptr) ptp;// ptp.createTuple(); if (ptp.getNode() != nullptr)
else std::cerr << "key not found" << '\n'; ptp; // ptp.createTuple();
else
std::cerr << "key not found" << '\n';
} }
transaction::run(pop, [&] { delete_persistent<PTableType>(pop.root()->pTable); }); transaction::run(pop, [&] { delete_persistent<PTableType>(pop.root()->pTable); });
pop.close(); pop.close();
std::experimental::filesystem::remove_all(path); pmempool_rm(path.c_str(), 0);
} }
static void VectorArguments(benchmark::internal::Benchmark* b) { static void VectorArguments(benchmark::internal::Benchmark* b) {
for (const auto &arg : POINT_ACCESS) b->Args(arg); for (const auto& arg : POINT_ACCESS) b->Args(arg);
} }
BENCHMARK(BM_PointQuery)->Apply(VectorArguments); BENCHMARK(BM_PointQuery)->Apply(VectorArguments);
......
...@@ -21,9 +21,7 @@ ...@@ -21,9 +21,7 @@
using namespace dbis::ptable; using namespace dbis::ptable;
static void BM_RangeScan(benchmark::State &state) { static void BM_RangeScan(benchmark::State &state) {
pool<root> pop; pool<root> pop;
if (access(path.c_str(), F_OK) != 0) { if (access(path.c_str(), F_OK) != 0) {
...@@ -37,20 +35,20 @@ static void BM_RangeScan(benchmark::State &state) { ...@@ -37,20 +35,20 @@ static void BM_RangeScan(benchmark::State &state) {
/* RangeScan using Block iterator */ /* RangeScan using Block iterator */
for (auto _ : state) { for (auto _ : state) {
auto iter = pTable->rangeScan(ColumnRangeMap({{0, {(int)state.range(0), (int)state.range(1)}}})); auto iter =
for (const auto &tp: iter) { pTable->rangeScan(ColumnRangeMap({{0, {(int)state.range(0), (int)state.range(1)}}}));
for (const auto &tp : iter) {
tp; tp;
} }
} }
pop.close(); pop.close();
} }
static void KeyRangeArguments(benchmark::internal::Benchmark* b) { static void KeyRangeArguments(benchmark::internal::Benchmark *b) {
for (const auto &arg : KEY_RANGES) b->Args(arg); for (const auto &arg : KEY_RANGES) b->Args(arg);
} }
BENCHMARK(BM_RangeScan)->Apply(KeyRangeArguments); BENCHMARK(BM_RangeScan)->Apply(KeyRangeArguments);
static void BM_NonKeyRangeScan(benchmark::State &state) { static void BM_NonKeyRangeScan(benchmark::State &state) {
pool<root> pop; pool<root> pop;
if (access(path.c_str(), F_OK) != 0) { if (access(path.c_str(), F_OK) != 0) {
...@@ -64,21 +62,21 @@ static void BM_NonKeyRangeScan(benchmark::State &state) { ...@@ -64,21 +62,21 @@ static void BM_NonKeyRangeScan(benchmark::State &state) {
/* RangeScan using Block iterator */ /* RangeScan using Block iterator */
for (auto _ : state) { for (auto _ : state) {
auto iter = pTable->rangeScan(ColumnRangeMap({{0, {(int)state.range(0), (int) state.range(1)}}, auto iter =
{3, {(double)state.range(2), (double)state.range(3)}}})); pTable->rangeScan(ColumnRangeMap({{0, {(int)state.range(0), (int)state.range(1)}},
for (const auto &tp: iter) { {3, {(double)state.range(2), (double)state.range(3)}}}));
for (const auto &tp : iter) {
tp; tp;
} }
} }
pop.close(); pop.close();
} }
static void NonKeyRangeArguments(benchmark::internal::Benchmark* b) { static void NonKeyRangeArguments(benchmark::internal::Benchmark *b) {
for (const auto &arg : NON_KEY_RANGES) b->Args(arg); for (const auto &arg : NON_KEY_RANGES) b->Args(arg);
} }
BENCHMARK(BM_NonKeyRangeScan)->Apply(NonKeyRangeArguments); BENCHMARK(BM_NonKeyRangeScan)->Apply(NonKeyRangeArguments);
static void BM_PBPTreeKeyScan(benchmark::State &state) { static void BM_PBPTreeKeyScan(benchmark::State &state) {
pool<root> pop; pool<root> pop;
if (access(path.c_str(), F_OK) != 0) { if (access(path.c_str(), F_OK) != 0) {
...@@ -92,7 +90,8 @@ static void BM_PBPTreeKeyScan(benchmark::State &state) { ...@@ -92,7 +90,8 @@ static void BM_PBPTreeKeyScan(benchmark::State &state) {
for (auto _ : state) { for (auto _ : state) {
/* Scan via Index scan */ /* Scan via Index scan */
pTable->rangeScan2(state.range(0), state.range(1), [](int k, const PTuple<int, MyTuple> tp){tp;}); pTable->rangeScan2(state.range(0), state.range(1),
[](int k, const PTuple<int, MyTuple> tp) { tp; });
} }
pop.close(); pop.close();
...@@ -100,7 +99,6 @@ static void BM_PBPTreeKeyScan(benchmark::State &state) { ...@@ -100,7 +99,6 @@ static void BM_PBPTreeKeyScan(benchmark::State &state) {
BENCHMARK(BM_PBPTreeKeyScan)->Apply(KeyRangeArguments); BENCHMARK(BM_PBPTreeKeyScan)->Apply(KeyRangeArguments);
static void BM_PBPTreeScan(benchmark::State &state) { static void BM_PBPTreeScan(benchmark::State &state) {
pool<root> pop; pool<root> pop;
if (access(path.c_str(), F_OK) != 0) { if (access(path.c_str(), F_OK) != 0) {
...@@ -115,11 +113,10 @@ static void BM_PBPTreeScan(benchmark::State &state) { ...@@ -115,11 +113,10 @@ static void BM_PBPTreeScan(benchmark::State &state) {
for (auto _ : state) { for (auto _ : state) {
/* Scan via PTuple iterator */ /* Scan via PTuple iterator */
auto eIter = pTable.end(); auto eIter = pTable.end();
auto iter = pTable.select( auto iter = pTable.select([&](const PTuple<int, MyTuple> &tp) {
[&](const PTuple<int, MyTuple> &tp) { return (tp.get<0>() >= state.range(0)) && (tp.get<0>() <= state.range(1)) &&
return (tp.get<0>() >= state.range(0)) && (tp.get<0>() <= state.range(1)) && (tp.get<3>() >= state.range(2)) && (tp.get<3>() <= state.range(3));
(tp.get<3>() >= state.range(2)) && (tp.get<3>() <= state.range(3)); });
});
for (; iter != eIter; iter++) { for (; iter != eIter; iter++) {
iter; iter;
//(*iter).get<0>(); //(*iter).get<0>();
...@@ -128,9 +125,8 @@ static void BM_PBPTreeScan(benchmark::State &state) { ...@@ -128,9 +125,8 @@ static void BM_PBPTreeScan(benchmark::State &state) {
transaction::run(pop, [&] { delete_persistent<PTableType>(pop.root()->pTable); }); transaction::run(pop, [&] { delete_persistent<PTableType>(pop.root()->pTable); });
pop.close(); pop.close();
std::experimental::filesystem::remove_all(path); pmempool_rm(path.c_str(), 0);
} }
BENCHMARK(BM_PBPTreeScan)->Apply(NonKeyRangeArguments); BENCHMARK(BM_PBPTreeScan)->Apply(NonKeyRangeArguments);
BENCHMARK_MAIN(); BENCHMARK_MAIN();
...@@ -18,175 +18,211 @@ ...@@ -18,175 +18,211 @@
#ifndef DBIS_TREES_COMMON_HPP #ifndef DBIS_TREES_COMMON_HPP
#define DBIS_TREES_COMMON_HPP #define DBIS_TREES_COMMON_HPP
#include <unistd.h>
#include <chrono> #include <chrono>
#include <iostream> #include <iostream>
#include <numeric>
#include <unistd.h> #include <libpmempool.h>
#include <experimental/filesystem> #include <libpmemobj++/container/array.hpp>
#include <libpmemobj++/pool.hpp>
#include <libpmemobj++/persistent_ptr.hpp>
#include <libpmemobj++/make_persistent.hpp> #include <libpmemobj++/make_persistent.hpp>
#include <libpmemobj++/persistent_ptr.hpp>
#include <libpmemobj++/pool.hpp>
#include <libpmemobj++/transaction.hpp> #include <libpmemobj++/transaction.hpp>
#include <numeric>
#define UNIT_TESTS #define UNIT_TESTS
#include "benchmark/benchmark.h"
#include "PBPTree.hpp" #include "PBPTree.hpp"
#include "benchmark/benchmark.h"
using namespace dbis::pbptrees; using namespace dbis::pbptrees;
using pmem::obj::delete_persistent; using pmem::obj::delete_persistent;
using pmem::obj::make_persistent; using pmem::obj::make_persistent;
using pmem::obj::pool;
using pmem::obj::persistent_ptr; using pmem::obj::persistent_ptr;
using pmem::obj::pool;
using pmem::obj::transaction; using pmem::obj::transaction;
/*=== Types and constants ===*/ /*=== Types and constants ===*/
/* Customization section */ /* Customization section */
using MyTuple = std::tuple <int, int, double>; using MyTuple = std::tuple<int, int, double>;
using MyKey = unsigned long long; using MyKey = unsigned long long;
constexpr auto TARGET_BRANCH_SIZE = 512; constexpr auto TARGET_BRANCH_SIZE = 512;
constexpr auto TARGET_LEAF_SIZE = 256; //< 512B best performance constexpr auto TARGET_LEAF_SIZE = 512;
constexpr auto TARGET_DEPTH = 1; constexpr auto TARGET_DEPTH = 1;
constexpr auto IS_HYBRID = 0; constexpr auto IS_HYBRID = 0;
const std::string path = dbis::gPmemPath + "tree_benchSp.data"; constexpr auto MOVE_TO_RIGHT = 0; ///< for balance direction
constexpr auto POOL_SIZE = 1024 * 1024 * 1024 * 4ull; //< 1GB const std::string path = dbis::gPmemPath + "tree_bench.data";
constexpr auto POOL_SIZE = 1024 * 1024 * 1024 * 4ull; //< 4GB
constexpr auto LAYOUT = "Tree"; constexpr auto LAYOUT = "Tree";
constexpr auto NODE_PTR_SIZE = 24; ///< 24 Byte (8-tag + 16-pptr)
/* wBPTree pre-calculations */ /* wBPTree pre-calculations */
template<unsigned int N> template <unsigned int KEYS>
constexpr unsigned int getBranchKeyswBPTree() { constexpr unsigned int getBranchKeyswBPTree() {
constexpr auto keys = getBranchKeyswBPTree<N-1>(); constexpr auto CL_h = ((KEYS + 1 + 7) / 8) * 8 + ((KEYS + 63) / 64) * 8;
constexpr auto CL_h = keys + ((keys + 63) / 64) * 8; constexpr auto CL = ((CL_h + 63) / 64) * 64; ///< rounding up
constexpr auto CL = ((CL_h + 63) / 64) * 64; constexpr auto SIZE = CL + KEYS * (sizeof(MyKey) + NODE_PTR_SIZE) +
constexpr auto SIZE = CL + keys * (sizeof(MyKey) + 24) + 24; //< CacheLine structure & n keys & n+1 children NODE_PTR_SIZE; ///< CacheLine structure & n keys & n+1 children
return (SIZE <= TARGET_BRANCH_SIZE)? keys : ((TARGET_BRANCH_SIZE - CL - 24) / (sizeof(MyKey) + 24)); if constexpr (SIZE <= TARGET_BRANCH_SIZE)
return KEYS;
else
return getBranchKeyswBPTree<KEYS - 1>();
} }
template<>
constexpr unsigned int getBranchKeyswBPTree<1>() { constexpr size_t getBranchKeyswBPTree() {
return ((TARGET_BRANCH_SIZE - 64 - 24) / (sizeof(MyKey) + 24)); constexpr auto KEYS = ((TARGET_BRANCH_SIZE - 64 - NODE_PTR_SIZE) / (sizeof(MyKey) + NODE_PTR_SIZE));
return getBranchKeyswBPTree<KEYS>();
} }
template<unsigned int N>
constexpr unsigned int getLeafKeyswBPTree() { template <size_t KEYS>
constexpr auto keys = getLeafKeyswBPTree<N-1>(); constexpr size_t getLeafKeyswBPTree() {
constexpr auto CL_h = keys + ((keys + 63) / 64) * 8; constexpr auto CL_h = ((KEYS + 1 + 7) / 8) * 8 + ((KEYS + 63) / 64) * 8 + 32;
constexpr auto CL = ((CL_h + 63) / 64) * 64; constexpr auto CL = ((CL_h + 63) / 64) * 64;
constexpr auto SIZE = CL + 32 + keys * (sizeof(MyKey) + sizeof(MyTuple)); constexpr auto SIZE = CL + KEYS * (sizeof(MyKey) + sizeof(MyTuple));
return (SIZE <= TARGET_LEAF_SIZE)? keys : ((TARGET_LEAF_SIZE - CL - 32) / (sizeof(MyKey) + sizeof(MyTuple))); if constexpr (SIZE <= TARGET_LEAF_SIZE)
return KEYS;
else
return getLeafKeyswBPTree<KEYS - 1>();
// return SIZE <= TARGET_LEAF_SIZE ? KEYS : getLeafKeyswBPTree<KEYS-1>();
} }
template<>
constexpr unsigned int getLeafKeyswBPTree<1>() { constexpr size_t getLeafKeyswBPTree() {
return ((TARGET_LEAF_SIZE - 64 - 32) / (sizeof(MyKey) + sizeof(MyTuple))); constexpr auto KEYS = ((TARGET_LEAF_SIZE - 64) / (sizeof(MyKey) + sizeof(MyTuple)));
return getLeafKeyswBPTree<KEYS>();
} }
/* PBPTree pre-calculations */ /* PBPTree pre-calculations */
template<unsigned int N> constexpr size_t getBranchKeysPBPTree() {
constexpr unsigned int getBranchKeysPBPTree() {
return ((TARGET_BRANCH_SIZE - 28) / (sizeof(MyKey) + 24)); return ((TARGET_BRANCH_SIZE - 28) / (sizeof(MyKey) + 24));
} }
template<unsigned int N>
constexpr unsigned int getLeafKeysPBPTree() { constexpr size_t getLeafKeysPBPTree() {
return ((TARGET_LEAF_SIZE - 36) / (sizeof(MyKey) + sizeof(MyTuple))); return ((TARGET_LEAF_SIZE - 64) / (sizeof(MyKey) + sizeof(MyTuple)));
} }
/* FPTree pre-calculations */ /* FPTree pre-calculations */
template<unsigned int N> constexpr size_t getBranchKeysFPTree() {
constexpr unsigned int getBranchKeysFPTree() { return ((TARGET_BRANCH_SIZE - 28) / (sizeof(MyKey) + NODE_PTR_SIZE));
return ((TARGET_BRANCH_SIZE - 28) / (sizeof(MyKey) + 24));
} }
template<unsigned int N>
constexpr unsigned int getLeafKeysFPTree() { template <size_t KEYS>
constexpr auto keys = getLeafKeysFPTree<N-1>(); constexpr size_t getLeafKeysFPTree() {
constexpr auto CL_h = keys + ((keys + 63) / 64) * 8; constexpr auto CL_h = ((KEYS + 7) / 8) * 8 + ((KEYS + 63) / 64) * 8 + 32;
constexpr auto CL = ((CL_h + 63) / 64) * 64; constexpr auto CL = ((CL_h + 63) / 64) * 64;
constexpr auto SIZE = CL + 32 + keys * (sizeof(MyKey) + sizeof(MyTuple)); constexpr auto SIZE = CL + KEYS * (sizeof(MyKey) + sizeof(MyTuple));
return (SIZE <= TARGET_LEAF_SIZE)? keys : ((TARGET_LEAF_SIZE - CL - 32) / (sizeof(MyKey) + sizeof(MyTuple))); if constexpr (SIZE <= TARGET_LEAF_SIZE)
return KEYS;
else
return getLeafKeysFPTree<KEYS - 1>();
} }
template<>
constexpr unsigned int getLeafKeysFPTree<1>() { constexpr size_t getLeafKeysFPTree() {
return ((TARGET_LEAF_SIZE - 64 - 32) / (sizeof(MyKey) + sizeof(MyTuple))); constexpr auto KEYS = ((TARGET_LEAF_SIZE - 64) / (sizeof(MyKey) + sizeof(MyTuple)));
return getLeafKeysFPTree<KEYS>();
} }
/* BitPBPTree pre-calculations */ /* BitPBPTree pre-calculations */
template<unsigned int N> template <size_t KEYS>
constexpr unsigned int getBranchKeysBitPBPTree() { constexpr size_t getBranchKeysBitPBPTree() {
constexpr auto keys = getBranchKeysBitPBPTree<N-1>(); constexpr auto wordBits = sizeof(unsigned long) * 8;
constexpr auto word = sizeof(unsigned long) * 8; constexpr auto BM = (KEYS + wordBits - 1) / wordBits * 8; ///< round to necessary words
constexpr auto BM = (keys + word - 1) / word * 8; constexpr auto SIZE = BM + KEYS * (sizeof(MyKey) + NODE_PTR_SIZE) +
constexpr auto SIZE = BM + keys * (sizeof(MyKey) + 24) + 24; //< bitmap structure & n keys & n+1 children NODE_PTR_SIZE; ///< bitmap structure & n keys & n+1 children
return (SIZE <= TARGET_BRANCH_SIZE)? keys : ((TARGET_BRANCH_SIZE - BM - 24) / (sizeof(MyKey) + 24)); if constexpr (SIZE <= TARGET_BRANCH_SIZE)
return KEYS;
else
return getBranchKeyswBPTree<KEYS - 1>();
} }
template<>
constexpr unsigned int getBranchKeysBitPBPTree<1>() { constexpr size_t getBranchKeysBitPBPTree() {
return ((TARGET_BRANCH_SIZE - sizeof(unsigned long) - 24) / (sizeof(MyKey) + 24)); constexpr auto KEYS = (TARGET_BRANCH_SIZE - sizeof(unsigned long) - NODE_PTR_SIZE) /
(sizeof(MyKey) + NODE_PTR_SIZE);
return getBranchKeysBitPBPTree<KEYS>();
} }
template<unsigned int N> template <size_t KEYS>
constexpr unsigned int getLeafKeysBitPBPTree() { constexpr size_t getLeafKeysBitPBPTree() {
constexpr auto keys = getLeafKeysBitPBPTree<N-1>(); constexpr auto CL_h = ((KEYS + 63) / 64) * 8 + 32;
constexpr auto word = sizeof(unsigned long) * 8; constexpr auto CL = ((CL_h + 63) / 64) * 64;
constexpr auto BM = (keys + word - 1) / word * 8; constexpr auto SIZE = CL + KEYS * (sizeof(MyKey) + sizeof(MyTuple));
constexpr auto SIZE = BM + 32 + keys * (sizeof(MyKey) + sizeof(MyTuple)); if constexpr (SIZE <= TARGET_LEAF_SIZE)
return (SIZE <= TARGET_LEAF_SIZE)? keys : ((TARGET_LEAF_SIZE - BM - 32) / (sizeof(MyKey) + sizeof(MyTuple))); return KEYS;
else
return getLeafKeysBitPBPTree<KEYS - 1>();
} }
template<>
constexpr unsigned int getLeafKeysBitPBPTree<1>() { constexpr size_t getLeafKeysBitPBPTree() {
return ((TARGET_LEAF_SIZE - sizeof(unsigned long) - 32) / (sizeof(MyKey) + sizeof(MyTuple))); constexpr auto KEYS = ((TARGET_LEAF_SIZE - 64) / (sizeof(MyKey) + sizeof(MyTuple)));
return getLeafKeysBitPBPTree<KEYS>();
} }
/* Power of function */ /* Power of function */
constexpr uint64_t ipow(uint64_t base, int exp, uint64_t result = 1) { constexpr uint64_t ipow(uint64_t base, int exp, uint64_t result = 1) {
return exp < 1 ? result : ipow(base*base, exp/2, (exp % 2) ? result*base : result); return exp < 1 ? result : ipow(base * base, exp / 2, (exp % 2) ? result * base : result);
} }