tree_erase.cpp 6.43 KB
Newer Older
1
/*
2
 * Copyright (C) 2017-2020 DBIS Group - TU Ilmenau, All Rights Reserved.
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 *
 * 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 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/>.
 */

#include <libpmemobj++/container/array.hpp>
#include "common.hpp"
#include "utils/PersistEmulation.hpp"
21
22
23
24
25
26
27
28
#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;
29
30
31
32
33

void prepare(const persistent_ptr<TreeType> tree);

/* Get benchmarks on Tree */
static void BM_TreeErase(benchmark::State &state) {
34
35
36
37
38
39
40
41
42
43
44
45
    #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

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  std::cout << "BRANCHKEYS: " << BRANCHKEYS << " -> " << sizeof(TreeType::BranchNode)
            << "\nLEAFKEYS: " << LEAFKEYS << " -> " << sizeof(TreeType::LeafNode) << "\n";

  struct root {
    persistent_ptr<TreeType> tree;
  };

  pool<root> pop;

  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); });
  } 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); });
  }

70
  auto tree = pop.root()->tree;
71
72
  prepare(tree);
  auto &treeRef = *tree;
73
  tree.flush(pop);
74
  auto leaf = treeRef.rootNode.leaf;
75
  leaf.flush(pop);
76
77
78
79
80
81
82
83
84
85
86
87

  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);
    }
  });
  pop.drain();

88
  const auto pos = treeRef.lookupPositionInLeafNode(leaf, KEYPOS);
89
  // const auto pos = leaf->bits.get_ro().getFreeZero();
90
91
92
93
94
95
96
97

#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) {
98
99
100
101
102
103
104
    auto &leafRef = *leafNode;
    benchmark::DoNotOptimize(*leafNode);

    // transaction::run(pop, [&] {
    treeRef.eraseFromLeafNodeAtPosition(leafNode, pos, KEYPOS);
    //});

105
106
    pop.flush(leafRef.numKeys);
    // pop.flush(leafRef.bits);
107
108
    // pop.flush(&leafRef.slot.get_ro(),
    //           sizeof(leafRef.slot.get_ro()) + sizeof(leafRef.bits.get_ro()));
109
110
    // pop.flush(&leafRef.bits.get_ro(),
    //           sizeof(leafRef.bits.get_ro()) + sizeof(leafRef.fp.get_ro()));
111
112
    // pop.flush(&leafRef.keys.get_ro()[pos], sizeof(MyKey));
    // pop.flush(&leafRef.values.get_ro()[pos], sizeof(MyTuple));
113
114
    pop.flush(&leafRef.keys.get_ro()[pos], (LEAFKEYS - 1 - pos) * sizeof(MyKey));
    pop.flush(&leafRef.values.get_ro()[pos], (LEAFKEYS - 1 - pos) * sizeof(MyTuple));
115
    pop.drain();
116
117
118
    // leafNode.persist(pop);

    benchmark::DoNotOptimize(*leafNode);
119
    benchmark::ClobberMemory();
120
121
122
123
124
125
  };

 /// BENCHMARK Writes
  if (pmmwrites == 0) {
    auto &leafNode = (*leafArray)[0];
    // auto &leafRef = *leafNode;
126

127
128
129
130
131
132
133
134
135
136
137
    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();
138
    *leafNode = *leaf;  ///< reset the modified node
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
    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());
164
165
166
167
  }

  // treeRef.printLeafNode(0, leaf);
  std::cout.clear();
168
169
170
171
  std::cout << "Iterations:" << state.iterations() << '\n';
  std::cout << "PMM Reads:" << pmmreads << '\n';
  std::cout << "Writes:" << modBytes << '\n';
  std::cout << "PMM Writes:" << pmmwrites << '\n';
172
173
174
175
176
177
178
  std::cout << "Elements:" << ELEMENTS << '\n';

  transaction::run(pop, [&] { delete_persistent<TreeType>(tree); });
  pop.close();
  pmempool_rm(path.c_str(), 0);
}

179
BENCHMARK(BM_TreeErase)->UseManualTime();
180
181
182
183
184
185
186
187
188
189
BENCHMARK_MAIN();

/* preparing inserts */
void prepare(const persistent_ptr<TreeType> tree) {
  auto &treeRef = *tree;
  for (auto j = 1; j < LEAFKEYS + 1; ++j) {
    auto tup = MyTuple(j, j * 100, j * 1.0);
    treeRef.insert(j, tup);
  }
}