Commit 3df06a80 authored by Philipp Götze's avatar Philipp Götze

Added PCM and other changes for DaMoN paper

parent 0777e409
Pipeline #545 failed with stages
in 2 minutes and 16 seconds
......@@ -18,7 +18,8 @@ endif()
option(ENABLE_LOG "enables log output for e.g. debugging" OFF)
option(BUILD_TEST_CASES "build tests for functionality of structures" ON )
option(BUILD_GOOGLE_BENCH "build google benchmark" OFF)
option(BUILD_BENCHMARKS "build benchmarks for structures" ON )
option(BUILD_BENCHMARKS "build benchmarks for structures" OFF)
option(ENABLE_PCM "enables performance counter monitor" OFF)
################################################################################
# End of customization section #
......@@ -27,6 +28,9 @@ option(BUILD_BENCHMARKS "build benchmarks for structures" ON )
if(ENABLE_LOG)
add_definitions("-DENABLE_LOG")
endif()
if(ENABLE_PCM)
add_definitions("-DENABLE_PCM")
endif()
# Benchmark test requires benchmark library
if (BUILD_BENCHMARKS)
......@@ -102,7 +106,7 @@ add_subdirectory(src/pbptrees) # Persistent versions of B⁺-Tree, contains also
# - Remake of the wB+Tree
add_subdirectory(src/ptable) # BDCC-based analytical table structure
add_subdirectory(src/pskiplists)
add_subdirectory(src/pskiplists)
#########################
# Unit test using Catch #
#########################
......
......@@ -56,6 +56,7 @@ const std::string path = dbis::gPmemPath + "tree_bench.data";
constexpr auto POOL_SIZE = 1024 * 1024 * 1024 * 4ull; //< 4GB
constexpr auto LAYOUT = "Tree";
constexpr auto NODE_PTR_SIZE = 24; ///< 24 Byte (8-tag + 16-pptr)
constexpr auto L3 = 14080 * 1024;
/* wBPTree pre-calculations */
template <unsigned int KEYS>
......@@ -239,7 +240,7 @@ class HybridWrapper {
inline void recover(T &tree) const { recover(tree, Int2Type<isHybrid>()); }
};
auto hybridWrapperPtr = new HybridWrapper<TreeType, IS_HYBRID>();
auto hybridWrapperPtr = std::make_unique<HybridWrapper<TreeType, IS_HYBRID>>();
auto &hybridWrapper = *hybridWrapperPtr;
/*=== Insert Function ===*/
......
......@@ -18,7 +18,6 @@
#include "common.hpp"
#include "utils/PersistEmulation.hpp"
constexpr auto L3 = 30 * 1024 * 1024;
constexpr auto ArraySize = L3 / TARGET_LEAF_SIZE;
using ArrayType = pmem::obj::array<pptr<TreeType::LeafNode>, ArraySize>;
......
......@@ -18,11 +18,31 @@
#include <libpmemobj++/container/array.hpp>
#include "common.hpp"
#include "utils/PersistEmulation.hpp"
#ifdef ENABLE_PCM
#include <cpucounters.h>
#endif
uint64_t pmmwrites = 0;
uint64_t pmmreads = 0;
uint64_t modBytes = 0; ///< modified Bytes
constexpr auto ArraySize = 4 * L3 / 256;//TARGET_LEAF_SIZE;
void prepare(const persistent_ptr<TreeType> tree);
/* Get benchmarks on Tree */
static void BM_TreeErase(benchmark::State &state) {
#ifdef ENABLE_PCM
PCM *pcm_ = PCM::getInstance();
auto s = pcm_->program();
if (s != PCM::Success) {
std::cerr << "Error creating PCM instance: " << s << std::endl;
if (s == PCM::PMUBusy)
pcm_->resetPMU();
else
exit(0);
}
#endif
std::cout << "BRANCHKEYS: " << BRANCHKEYS << " -> " << sizeof(TreeType::BranchNode)
<< "\nLEAFKEYS: " << LEAFKEYS << " -> " << sizeof(TreeType::LeafNode) << "\n";
......@@ -47,12 +67,12 @@ static void BM_TreeErase(benchmark::State &state) {
transaction::run(pop, [&] { pop.root()->tree = make_persistent<TreeType>(alloc_class); });
}
const auto tree = pop.root()->tree;
auto tree = pop.root()->tree;
prepare(tree);
auto &treeRef = *tree;
tree.flush(pop);
auto leaf = treeRef.rootNode.leaf;
constexpr auto L3 = 30 * 1024 * 1024;
constexpr auto ArraySize = L3 / TARGET_LEAF_SIZE;
leaf.flush(pop);
pptr<pmem::obj::array<pptr<TreeType::LeafNode>, ArraySize>> leafArray;
transaction::run(pop, [&] {
......@@ -65,17 +85,17 @@ static void BM_TreeErase(benchmark::State &state) {
});
pop.drain();
/* BENCHMARKING */
for (auto _ : state) {
state.PauseTiming();
std::cout.setstate(std::ios_base::failbit);
const auto leafNodePos = std::rand() % ArraySize;
auto leafNode = (*leafArray)[leafNodePos];
const auto pos = treeRef.lookupPositionInLeafNode(leafNode, KEYPOS);
// const auto pos = dbis::BitOperations::getFreeZero(leafNode->bits.get_ro());
const auto pos = treeRef.lookupPositionInLeafNode(leaf, KEYPOS);
// const auto pos = dbis::BitOperations::getFreeZero(leaf->bits.get_ro());
#ifdef ENABLE_PCM
SocketCounterState before_sstate;
SocketCounterState after_sstate;
#endif
/// Lambda function for measured part (needed twice)
auto benchmark = [&pop, &treeRef, &pos](pptr<TreeType::LeafNode> &leafNode) {
auto &leafRef = *leafNode;
dbis::PersistEmulation::getBytesWritten();
state.ResumeTiming();
benchmark::DoNotOptimize(*leafNode);
// transaction::run(pop, [&] {
......@@ -86,22 +106,68 @@ static void BM_TreeErase(benchmark::State &state) {
// pop.flush(leafRef.bits);
// pop.flush(&leafRef.slot.get_ro(),
// sizeof(leafRef.slot.get_ro()) + sizeof(leafRef.bits.get_ro()));
// pop.flush(&leafRef.bits.get_ro(),
// sizeof(leafRef.bits.get_ro()) + sizeof(leafRef.fp.get_ro()));
// pop.flush(&leafRef.keys.get_ro()[pos], sizeof(MyKey));
// pop.flush(&leafRef.values.get_ro()[pos], sizeof(MyTuple));
pop.flush(&leafRef.keys.get_ro()[pos], (LEAFKEYS - 1 - pos) * sizeof(MyKey));
pop.flush(&leafRef.values.get_ro()[pos], (LEAFKEYS - 1 - pos) * sizeof(MyTuple));
pop.drain();
// leaf.persist(pop);
// leafNode.persist(pop);
benchmark::DoNotOptimize(*leafNode);
};
/// BENCHMARK Writes
if (pmmwrites == 0) {
auto &leafNode = (*leafArray)[0];
// auto &leafRef = *leafNode;
benchmark::DoNotOptimize(*leaf);
state.PauseTiming();
dbis::PersistEmulation::getBytesWritten();
#ifdef ENABLE_PCM
before_sstate = getSocketCounterState(1);
#endif
benchmark(leafNode);
#ifdef ENABLE_PCM
after_sstate = getSocketCounterState(1);
pmmreads = getBytesReadFromPMM(before_sstate, after_sstate);
pmmwrites = getBytesWrittenToPMM(before_sstate, after_sstate);
#endif
modBytes = dbis::PersistEmulation::getBytesWritten();
*leafNode = *leaf; ///< reset the modified node
state.ResumeTiming();
leafNode.flush(pop);
// pop.flush((char *)((uintptr_t)&*leafNode - 64), 64); //< flush header
pop.drain();
}
/// BENCHMARK Timing
/// avoid output to stdout during benchmark
std::cout.setstate(std::ios_base::failbit);
std::srand(std::time(nullptr));
for (auto _ : state) {
const auto leafNodePos = std::rand() % ArraySize;
auto leafNode = (*leafArray)[leafNodePos];
auto &leafRef = *leafNode;
auto start = std::chrono::high_resolution_clock::now();
benchmark(leafNode);
auto end = std::chrono::high_resolution_clock::now();
leafRef = *leaf; ///< reset the modified node
leafNode.flush(pop);
pop.drain();
auto elapsed_seconds =
std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
state.SetIterationTime(elapsed_seconds.count());
}
// treeRef.printLeafNode(0, leaf);
std::cout.clear();
std::cout << "Writes:" << dbis::PersistEmulation::getBytesWritten() << '\n';
std::cout << "Iterations:" << state.iterations() << '\n';
std::cout << "PMM Reads:" << pmmreads << '\n';
std::cout << "Writes:" << modBytes << '\n';
std::cout << "PMM Writes:" << pmmwrites << '\n';
std::cout << "Elements:" << ELEMENTS << '\n';
transaction::run(pop, [&] { delete_persistent<TreeType>(tree); });
......@@ -109,7 +175,7 @@ static void BM_TreeErase(benchmark::State &state) {
pmempool_rm(path.c_str(), 0);
}
BENCHMARK(BM_TreeErase);
BENCHMARK(BM_TreeErase)->UseManualTime();
BENCHMARK_MAIN();
/* preparing inserts */
......
......@@ -15,21 +15,23 @@
* If not, see <http://www.gnu.org/licenses/>.
*/
#include "common.hpp"
#include <cstdlib>
#include <ctime>
#include <libpmemobj++/container/array.hpp>
#include <thread>
#include "common.hpp"
constexpr auto L3 = 30 * 1024 * 1024;
constexpr auto ArraySize = L3 / TARGET_LEAF_SIZE;
constexpr auto ArraySize = 4 * L3 / 256; //TARGET_LEAF_SIZE;
/* Get benchmarks on Tree */
static void BM_TreeGet(benchmark::State &state) {
std::cout << "BRANCHKEYS: " << BRANCHKEYS << " - " << sizeof(TreeType::BranchNode)
<< "\nLEAFKEYS: " << LEAFKEYS << " - " << sizeof(TreeType::LeafNode) << "\n";
using LeafArray = pmem::obj::array<pptr<TreeType::LeafNode>, ArraySize>;
struct root {
persistent_ptr<TreeType> tree;
pptr<TreeType> tree;
pptr<LeafArray> leafArray;
};
pool<root> pop;
......@@ -38,19 +40,19 @@ static void BM_TreeGet(benchmark::State &state) {
if (access(path.c_str(), F_OK) != 0) {
pop = pool<root>::create(path, LAYOUT, POOL_SIZE);
alloc_class =
pop.ctl_set<struct pobj_alloc_class_desc>("heap.alloc_class.128.desc", TreeType::AllocClass);
pop.ctl_set<struct pobj_alloc_class_desc>("heap.alloc_class.new.desc", TreeType::AllocClass);
transaction::run(pop, [&] { pop.root()->tree = make_persistent<TreeType>(alloc_class); });
} else {
LOG("Warning: " << path << " already exists");
pmempool_rm(path.c_str(), 0);
pop = pool<root>::create(path, LAYOUT, POOL_SIZE);
alloc_class =
pop.ctl_set<struct pobj_alloc_class_desc>("heap.alloc_class.128.desc", TreeType::AllocClass);
pop.ctl_set<struct pobj_alloc_class_desc>("heap.alloc_class.new.desc", TreeType::AllocClass);
transaction::run(pop, [&] { pop.root()->tree = make_persistent<TreeType>(alloc_class); });
}
/*
/// DRAM considerations
/*
struct alignas(64) DRAMLeafNode {
DRAMLeafNode() : numKeys(0), nextLeaf(nullptr), prevLeaf(nullptr) {}
DRAMLeafNode(const TreeType::LeafNode &other)
......@@ -61,22 +63,56 @@ static void BM_TreeGet(benchmark::State &state) {
// values(other.values.get_ro()),
{}
unsigned int numKeys; ///< the number of currently stored keys - 0x10
DRAMLeafNode *nextLeaf; ///< pointer to the subsequent sibling - 0x18
DRAMLeafNode *prevLeaf; ///< pointer to the preceding sibling - 0x28
char padding[44]; ///< padding to align keys to 64 byte - 0x38
size_t numKeys; ///< the number of currently stored keys - 0x00
DRAMLeafNode *nextLeaf; ///< pointer to the subsequent sibling - 0x08
DRAMLeafNode *prevLeaf; ///< pointer to the preceding sibling - 0x10
char padding[40]; ///< padding to align keys to 64 byte - 0x18
std::array<MyKey, LEAFKEYS> keys; ///< the actual keys - 0x40
std::array<MyTuple, LEAFKEYS> values; ///< the actual values
};*/
}; */
/*
static constexpr auto SlotSize = ((LEAFKEYS+1 + 7) / 8) * 8;
static constexpr auto HashSize = ((LEAFKEYS + 7) / 8) * 8;
static constexpr auto BitsetSize = ((LEAFKEYS + 63) / 64) * 8;
static constexpr auto SearchSize = BitsetSize +16;
static constexpr auto PaddingSize = (64 - SearchSize % 64) % 64;
struct alignas(64) DRAMLeafNode {
DRAMLeafNode() : nextLeaf(nullptr), prevLeaf(nullptr) {
//slot[0] = 0;
}
DRAMLeafNode(const TreeType::LeafNode &other)
: //slot(other.slot.get_ro()),
bits(other.bits.get_ro()),
//fp(other.fp.get_ro()),
nextLeaf(nullptr),
prevLeaf(nullptr),
keys(other.keys.get_ro())
// values(other.values.get_ro()),
{}
//std::array<uint8_t, LEAFKEYS+1> slot;
std::bitset<LEAFKEYS> bits;
//std::array<uint8_t, LEAFKEYS> fp;
DRAMLeafNode *nextLeaf;
DRAMLeafNode *prevLeaf;
char padding[PaddingSize];
std::array<MyKey, LEAFKEYS> keys;
std::array<MyTuple, LEAFKEYS> values;
};
*/
const auto tree = pop.root()->tree;
auto &tree = pop.root()->tree;
insert(tree, 0);
auto &treeRef = *tree;
auto leaf = treeRef.rootNode.leaf;
tree.flush(pop);
auto &leafArray = pop.root()->leafArray;
auto &leaf = treeRef.rootNode.leaf;
leaf.flush(pop);
pptr<pmem::obj::array<pptr<TreeType::LeafNode>, ArraySize>> leafArray;
transaction::run(pop, [&] {
leafArray = make_persistent<pmem::obj::array<pptr<TreeType::LeafNode>, ArraySize>>();
leafArray = make_persistent<LeafArray>();
for (int i = 0; i < ArraySize; ++i) {
auto &a = *leafArray;
a[i] = make_persistent<TreeType::LeafNode>(allocation_flag::class_id(alloc_class.class_id),
......@@ -85,36 +121,57 @@ static void BM_TreeGet(benchmark::State &state) {
});
pop.drain();
/// DRAM considerations
/*
std::unique_ptr<std::array<DRAMLeafNode *, ArraySize>> leafArray(
new std::array<DRAMLeafNode *, ArraySize>);
for (int i = 0; i < ArraySize; ++i) {
auto &a = *leafArray;
a[i] = new DRAMLeafNode(*leaf);
}*/
}
*/
std::srand(std::time(nullptr));
using namespace std::chrono_literals;
std::this_thread::sleep_for(2s);
/* BENCHMARKING */
for (auto _ : state) {
const auto leafNodePos = std::rand() % ArraySize;
const auto leafNode = (*leafArray)[leafNodePos];
const auto key = (long long unsigned int)KEYPOS;
auto start = std::chrono::high_resolution_clock::now();
benchmark::DoNotOptimize(*leafNode);
treeRef.lookupPositionInLeafNode(leafNode, KEYPOS);
/// DRAM considerations
// auto pos = 0u;
// const auto &nodeRef = *leafNode;
// const auto hash = (uint8_t)(key & 0xFF);
// const auto &keys = nodeRef.keys;
// const auto num = nodeRef.numKeys;
// const auto &slots = nodeRef.slot;
// const auto &bits = nodeRef.bits;
// const auto &hashs = nodeRef.fp;
// for (; pos < LEAFKEYS; ++pos)
// if (bits.test(pos) && keys[pos] == key) break;
// for (; pos < num && keys[pos] != key; ++pos);
// auto pos = dbis::binarySearch<false>(keys, 0, num-1, key);
// benchmark::DoNotOptimize(pos);
benchmark::DoNotOptimize(*leafNode);
auto end = std::chrono::high_resolution_clock::now();
auto elapsed_seconds =
std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
state.SetIterationTime(elapsed_seconds.count());
}
/* BENCHMARKING */
for (auto _ : state) {
state.PauseTiming();
const auto leafNodePos = std::rand() % ArraySize;
const auto leafNode = (*leafArray)[leafNodePos];
const auto key = (long long unsigned int)KEYPOS;
state.ResumeTiming();
benchmark::DoNotOptimize(*leafNode);
treeRef.lookupPositionInLeafNode(leafNode, KEYPOS);
// dbis::binarySearch<false>(leaf->keys.get_ro(), 0, leaf->numKeys.get_ro()-1, key);
benchmark::DoNotOptimize(*leafNode);
}
// treeRef.printBranchNode(0, treeRef.rootNode.branch);
std::cout << "Elements:" << ELEMENTS << '\n';
// treeRef.printBranchNode(0, treeRef.rootNode.branch);
std::cout << "Elements:" << ELEMENTS << '\n';
transaction::run(pop, [&] { delete_persistent<TreeType>(tree); });
pop.close();
pmempool_rm(path.c_str(), 0);
transaction::run(pop, [&] { delete_persistent<TreeType>(tree); });
pop.close();
pmempool_rm(path.c_str(), 0);
}
BENCHMARK(BM_TreeGet);
BENCHMARK(BM_TreeGet)->UseManualTime();
BENCHMARK_MAIN();
......@@ -3,31 +3,54 @@
*
* This file is part of our NVM-based Data Structures repository.
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with this program.
* If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libpmemobj++/container/array.hpp>
#include "common.hpp"
#include "utils/PersistEmulation.hpp"
#ifdef ENABLE_PCM
#include <cpucounters.h>
#endif
void prepare(const persistent_ptr<TreeType> tree);
uint64_t pmmwrites = 0;
uint64_t pmmreads = 0;
uint64_t modBytes = 0; ///< modified Bytes
constexpr auto ArraySize = 4 * L3 / 256;
/* Get benchmarks on Tree */
static void BM_TreeInsert(benchmark::State &state) {
std::cout << "BRANCHKEYS: " << BRANCHKEYS << " -> " << sizeof(TreeType::BranchNode)
<< "\nLEAFKEYS: " << LEAFKEYS << " -> " << sizeof(TreeType::LeafNode) << "\n";
#ifdef ENABLE_PCM
PCM *pcm_ = PCM::getInstance();
auto s = pcm_->program();
if (s != PCM::Success) {
std::cerr << "Error creating PCM instance: " << s << std::endl;
if (s == PCM::PMUBusy)
pcm_->resetPMU();
else
exit(0);
}
#endif
std::cout << "BRANCHKEYS: " << BRANCHKEYS << " -> "
<< sizeof(TreeType::BranchNode) << "\nLEAFKEYS: " << LEAFKEYS
<< " -> " << sizeof(TreeType::LeafNode) << "\n";
struct root {
persistent_ptr<TreeType> tree;
pptr<TreeType> tree;
};
pool<root> pop;
......@@ -35,84 +58,134 @@ static void BM_TreeInsert(benchmark::State &state) {
pobj_alloc_class_desc alloc_class;
if (access(path.c_str(), F_OK) != 0) {
pop = pool<root>::create(path, LAYOUT, POOL_SIZE);
alloc_class = pop.ctl_set<struct pobj_alloc_class_desc>("heap.alloc_class.new.desc",
TreeType::AllocClass);
transaction::run(pop, [&] { pop.root()->tree = make_persistent<TreeType>(alloc_class); });
alloc_class = pop.ctl_set<struct pobj_alloc_class_desc>(
"heap.alloc_class.new.desc", TreeType::AllocClass);
transaction::run(pop, [&] {
pop.root()->tree = make_persistent<TreeType>(alloc_class);
});
} else {
LOG("Warning: " << path << " already exists");
pmempool_rm(path.c_str(), 0);
pop = pool<root>::create(path, LAYOUT, POOL_SIZE);
alloc_class = pop.ctl_set<struct pobj_alloc_class_desc>("heap.alloc_class.new.desc",
TreeType::AllocClass);
transaction::run(pop, [&] { pop.root()->tree = make_persistent<TreeType>(alloc_class); });
alloc_class = pop.ctl_set<struct pobj_alloc_class_desc>(
"heap.alloc_class.new.desc", TreeType::AllocClass);
transaction::run(pop, [&] {
pop.root()->tree = make_persistent<TreeType>(alloc_class);
});
}
const auto tree = pop.root()->tree;
auto tree = pop.root()->tree;
prepare(tree);
auto &treeRef = *tree;
tree.flush(pop);
auto leaf = treeRef.rootNode.leaf;
constexpr auto L3 = 30 * 1024 * 1024;
constexpr auto ArraySize = L3 / TARGET_LEAF_SIZE;
leaf.flush(pop);
pptr<pmem::obj::array<pptr<TreeType::LeafNode>, ArraySize>> leafArray;
transaction::run(pop, [&] {
leafArray = make_persistent<pmem::obj::array<pptr<TreeType::LeafNode>, ArraySize>>();
for (int i = 0; i < ArraySize; ++i) {
auto &a = *leafArray;
a[i] = make_persistent<TreeType::LeafNode>(allocation_flag::class_id(alloc_class.class_id),
*leaf);
a[i] = make_persistent<TreeType::LeafNode>(
allocation_flag::class_id(alloc_class.class_id), *leaf);
}
});
pop.drain();
const auto reqTup = MyTuple(KEYPOS, KEYPOS * 100, KEYPOS * 1.0);
const auto pos = treeRef.lookupPositionInLeafNode(leaf, KEYPOS);
//const auto pos = dbis::BitOperations::getFreeZero(leaf->bits.get_ro());
/* BENCHMARKING */
for (auto _ : state) {
state.PauseTiming();
std::cout.setstate(std::ios_base::failbit);
const auto leafNodePos = std::rand() % ArraySize;
auto leafNode = (*leafArray)[leafNodePos];
const auto pos = treeRef.lookupPositionInLeafNode(leafNode, KEYPOS);
// const auto pos = dbis::BitOperations::getFreeZero(leafNode->bits.get_ro());
#ifdef ENABLE_PCM
SocketCounterState before_sstate;
SocketCounterState after_sstate;
#endif
/// Lambda function for measured part (needed twice)
auto benchmark = [&pop, &treeRef, &reqTup, &pos](
const pptr<TreeType::LeafNode> &leafNode) {
auto &leafRef = *leafNode;
dbis::PersistEmulation::getBytesWritten();
state.ResumeTiming();
//const auto pos = treeRef.lookupPositionInLeafNode(leafNode, KEYPOS);
// const auto pos = dbis::BitOperations::getFreeZero(leafNode->bits.get_ro());
benchmark::DoNotOptimize(*leafNode);
// transaction::run(pop, [&] {
treeRef.insertInLeafNodeAtPosition(leafNode, pos, KEYPOS, reqTup);
// treeRef.insertInLeafNodeAtLastPosition(leafNode, KEYPOS, reqTup);
//});
pop.flush(leafRef.numKeys);
// pop.flush(leafRef.bits);
// pop.flush(&leafRef.bits.get_ro(), sizeof(leafRef.bits.get_ro()) +
// sizeof(leafRef.fp.get_ro()));
// pop.flush(&leafRef.bits.get_ro(),
// sizeof(leafRef.bits.get_ro()) + sizeof(leafRef.fp.get_ro()));
// pop.flush(&leafRef.slot.get_ro(),
// sizeof(leafRef.slot.get_ro()) + sizeof(leafRef.bits.get_ro()));
// pop.flush(&leafRef.keys.get_ro()[(ELEMENTS-1)/2], sizeof(MyKey) * (ELEMENTS+3)/2);
// pop.flush(&leafRef.values.get_ro()[(ELEMENTS-1)/2], sizeof(MyTuple) * (ELEMENTS+3)/2);
pop.flush(&leafRef.keys.get_ro()[pos], sizeof(MyKey) * (ELEMENTS-pos));
pop.flush(&leafRef.values.get_ro()[pos], sizeof(MyTuple) * (ELEMENTS-pos));
// sizeof(leafRef.slot.get_ro()) + sizeof(leafRef.bits.get_ro()));
// pop.flush(&leafRef.keys.get_ro()[LEAFKEYS-1], sizeof(MyKey));
// pop.flush(&leafRef.values.get_ro()[LEAFKEYS-1], sizeof(MyTuple));
pop.flush(&leafRef.keys.get_ro()[pos], sizeof(MyKey) * (ELEMENTS - pos));
pop.flush(&leafRef.values.get_ro()[pos], sizeof(MyTuple) * (ELEMENTS - pos));
pop.drain();
// leafNode.persist(pop);
benchmark::DoNotOptimize(*leafNode);
state.PauseTiming();
benchmark::ClobberMemory();
};
/// BENCHMARK Writes
if (pmmwrites == 0) {
auto &leafNode = (*leafArray)[0];
// auto &leafRef = *leafNode;
dbis::PersistEmulation::getBytesWritten();
#ifdef ENABLE_PCM
before_sstate = getSocketCounterState(1);
#endif
benchmark(leafNode);
#ifdef ENABLE_PCM
after_sstate = getSocketCounterState(1);
pmmreads = getBytesReadFromPMM(before_sstate, after_sstate);
pmmwrites = getBytesWrittenToPMM(before_sstate, after_sstate);
#endif
modBytes = dbis::PersistEmulation::getBytesWritten();
*leafNode = *leaf; ///< reset the modified node
leafNode.flush(pop);
// pop.flush((char *)((uintptr_t)&*leafNode - 64), 64); //< flush header
pop.drain();
}
/// BENCHMARK Timing
/// avoid output to stdout during benchmark
std::cout.setstate(std::ios_base::failbit);
std::srand(std::time(nullptr));
for (auto _ : state) {
const auto leafNodePos = std::rand() % ArraySize;
auto leafNode = (*leafArray)[leafNodePos];
auto &leafRef = *leafNode;
auto start = std::chrono::high_resolution_clock::now();
benchmark(leafNode);
auto end = std::chrono::high_resolution_clock::now();
leafRef = *leaf; ///< reset the modified node
leafNode.flush(pop);
// pop.flush((char *)((uintptr_t)&*leafNode - 64), 64); //< flush header
pop.drain();
state.ResumeTiming();
auto elapsed_seconds =
std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
state.SetIterationTime(elapsed_seconds.count());
}
/// Evaluation & cleanup
// treeRef.printLeafNode(0, leafNode);
std::cout.clear();
std::cout << "Writes:" << dbis::PersistEmulation::getBytesWritten() << '\n';