Commit bd237439 authored by Philipp Götze's avatar Philipp Götze

Adapted TableInfo and improved benchmarks a bit

parent 3717f05d
......@@ -7,10 +7,10 @@ Please see the file [COPYING](COPYING) for license information.
### TODOs:
- [ ] Tests
- [ ] Get rid of expensive transactions
- [ ] Improve benchmarks
- [x] Improve benchmarks
- [ ] Describe usage
### Installation ###
For emulating a persistent memory device and further information see [http://pmem.io](http://pmem.io/2016/02/22/pm-emulation.html).
We use the C++17 standard, thus, you need a very recent C++ compiler and CMake (3.2 or newer) build environment.
......@@ -29,4 +29,4 @@ make test
### Usage ###
TODO
The test cases and benchmarks use the directory _/mnt/pmem/test_ for storing data. Thus, make sure the pmem device is mounted at _/mnt/pmem_ and the subfolder _test_ has write permissions for everybody. Alternatively, you can change the directory in [common.h](src/bench/common.h).
......@@ -43,7 +43,7 @@ if (BUILD_BENCHMARKS)
endif()
# C++ compiler flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall -Wno-deprecated -g -O0 -Wsign-compare")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -Wall -Wno-deprecated -g -O2 -Wsign-compare")
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-local-typedefs -Wno-#pragma-messages")
elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
......@@ -108,7 +108,6 @@ include_directories("${PROJECT_SOURCE_DIR}")
include_directories("${THIRD_PARTY_DIR}")
set(core_sources
core/TableInfo.cpp
core/PTableInfo.cpp
${THIRD_PARTY_DIR}/fmt
${THIRD_PARTY_DIR}/catch
......
This diff is collapsed.
include(../../cmake/Testing.cmake.in)
if (BUILD_BENCHMARKS)
do_test(insert)
do_test(scan)
do_test(point)
endif()
......@@ -17,21 +17,65 @@
* along with PTable. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PTABLE_COMMON_H
#define PTABLE_COMMON_H
#include <chrono>
#include <unistd.h>
#include "PTable.hpp"
using namespace ptable;
using nvml::obj::make_persistent;
using nvml::obj::p;
using nvml::obj::persistent_ptr;
using nvml::obj::pool;
using nvml::obj::transaction;
using MyTuple = std::tuple<int, int, std::string, double>;
using PTableType = PTable<MyTuple, int>;
const auto tuples = 1000 * 1000;
using PTableType = ptable::PTable<MyTuple, int>;
using Vector = std::vector<int>;
using VectorVector = std::vector<Vector>;
const int hibit(int n) noexcept;
template <size_t SIZE>
static inline VectorVector *createPointVector(VectorVector *v);
struct root {
persistent_ptr<PTableType> pTable;
};
const std::string path = "/mnt/pmem/test/benchdb.db";
const auto NUM_TUPLES = 100 * 1000;
const auto POOL_SIZE = 1024 * 1024 * 256;
const auto ALIGNMENT = hibit(NUM_TUPLES) + 1;
VectorVector pv;
const auto POINT_ACCESS = *createPointVector<NUM_TUPLES>(&pv);
const VectorVector KEY_RANGES = {
Vector{NUM_TUPLES / 2 - NUM_TUPLES / 2000, NUM_TUPLES / 2 + NUM_TUPLES / 2000}, // 0,1%
Vector{NUM_TUPLES / 2 - NUM_TUPLES / 400, NUM_TUPLES / 2 + NUM_TUPLES / 400}, // 0,5%
Vector{NUM_TUPLES / 2 - NUM_TUPLES / 200, NUM_TUPLES / 2 + NUM_TUPLES / 200}, // 1,0%
Vector{NUM_TUPLES / 2 - NUM_TUPLES / 40, NUM_TUPLES / 2 + NUM_TUPLES / 40}, // 5,0%
Vector{NUM_TUPLES / 2 - NUM_TUPLES / 20, NUM_TUPLES / 2 + NUM_TUPLES / 20}, // 10,0%
Vector{0, NUM_TUPLES-1} //100,0%
};
int hibit(int n) {
const VectorVector NON_KEY_RANGES = {
Vector{NUM_TUPLES / 2 - NUM_TUPLES / 1000, NUM_TUPLES / 2 + NUM_TUPLES / 1000,
NUM_TUPLES / 2, NUM_TUPLES / 2 + NUM_TUPLES / 500}, // 0,1%
Vector{NUM_TUPLES / 2 - NUM_TUPLES / 200, NUM_TUPLES / 2 + NUM_TUPLES / 200,
NUM_TUPLES / 2, NUM_TUPLES / 2 + NUM_TUPLES / 100}, // 0,5%
Vector{NUM_TUPLES / 2 - NUM_TUPLES / 100, NUM_TUPLES / 2 + NUM_TUPLES / 100,
NUM_TUPLES / 2, NUM_TUPLES / 2 + NUM_TUPLES / 50}, // 1,0%
Vector{NUM_TUPLES / 2 - NUM_TUPLES / 20, NUM_TUPLES / 2 + NUM_TUPLES / 20,
NUM_TUPLES / 2, NUM_TUPLES / 2 + NUM_TUPLES / 10}, // 5,0%
Vector{NUM_TUPLES / 2 - NUM_TUPLES / 10, NUM_TUPLES / 2 + NUM_TUPLES / 10,
NUM_TUPLES / 2, NUM_TUPLES / 2 + NUM_TUPLES / 5}, // 10,0%
Vector{0, NUM_TUPLES - 1, 0, NUM_TUPLES - 1} //100,0%
};
const int hibit(int n) noexcept {
n |= (n >> 1);
n |= (n >> 2);
n |= (n >> 4);
......@@ -40,41 +84,38 @@ int hibit(int n) {
return n - (n >> 1);
}
int main() {
template<size_t SIZE>
static inline VectorVector *createPointVector(VectorVector *v) {
if (SIZE >= 100) {
createPointVector<SIZE / 10>(v);
v->emplace_back(Vector{SIZE, SIZE / 2});
}
return v;
}
void insert (pool<root> &pop, const std::string &path, size_t entries) {
using namespace ptable;
std::chrono::high_resolution_clock::time_point start, end;
std::vector<typename std::chrono::duration<int64_t, std::micro>::rep> measures;
struct root {
persistent_ptr<PTableType> pTable;
};
pool<root> pop;
const std::string path = "/mnt/pmem/test/benchdb.db";
std::remove(path.c_str());
if (access(path.c_str(), F_OK) != 0) {
pop = pool<root>::create(path, LAYOUT, 1 << 30);
transaction::exec_tx(pop, [&] {
auto tInfo = TableInfo("MyTable", {
ColumnInfo("a", ColumnInfo::Int_Type),
ColumnInfo("b", ColumnInfo::Int_Type),
ColumnInfo("c", ColumnInfo::String_Type),
ColumnInfo("d", ColumnInfo::Double_Type)
});
auto alignment = hibit(tuples) + 1;
pop.get_root()->pTable =
make_persistent<PTableType>(tInfo, Dimensions({{0, {10, alignment}}, {3, {10, alignment}}}));
});
} else {
std::cerr << "WARNING: Table already exists" << std::endl;
pop = pool<root>::open(path, LAYOUT);
}
pop = pool<root>::create(path, LAYOUT, POOL_SIZE);
transaction::exec_tx(pop, [&] {
const auto tInfo = ptable::VTableInfo("MyTable", {
{"a", Int_Type},
{"b", Int_Type},
{"c", String_Type},
{"d", Double_Type}
}, Int_Type);
const auto dims = Dimensions({
{0, {10, ALIGNMENT}},
{3, {10, ALIGNMENT}}
});
pop.get_root()->pTable = make_persistent<PTableType>(tInfo, dims);
});
auto pTable = pop.get_root()->pTable;
auto &pTable = pop.get_root()->pTable;
for (unsigned int i = 0; i < tuples; i++) {
for (auto i = 0u; i < entries; i++) {
auto tup = MyTuple(i + 1,
(i + 1) * 100,
fmt::format("String #{0}", i),
......@@ -88,10 +129,11 @@ int main() {
auto avg = std::accumulate(measures.begin(), measures.end(), 0) / measures.size();
auto minmax = std::minmax_element(std::begin(measures), std::end(measures));
std::cout << "\nInsert Statistics in µs: "
<< "\n\tAvg: \t" << avg
<< "\n\tMin: \t" << *minmax.first
<< "\n\tMax: \t" << *minmax.second << '\n';
PLOG("\nInsert Statistics in µs: "
<< "\n\tAvg: \t" << avg
<< "\n\tMin: \t" << *minmax.first
<< "\n\tMax: \t" << *minmax.second);
}
pop.close();
}
\ No newline at end of file
#endif /* PTABLE_COMMON_H */
\ No newline at end of file
......@@ -18,26 +18,13 @@
*/
#include <unistd.h>
#include "benchmark/benchmark.h"
#include "fmt/format.h"
#include "PTable.hpp"
#include "common.h"
using namespace ptable;
using nvml::obj::make_persistent;
using nvml::obj::p;
using nvml::obj::persistent_ptr;
using nvml::obj::pool;
using nvml::obj::transaction;
using MyTuple = std::tuple<int, int, std::string, double>;
using PTableType = PTable<MyTuple, int>;
static void BM_PointQuery(benchmark::State& state) {
struct root {
persistent_ptr<PTableType> pTable;
};
pool<root> pop;
......@@ -46,17 +33,7 @@ static void BM_PointQuery(benchmark::State& state) {
std::remove(path.c_str());
if (access(path.c_str(), F_OK) != 0) {
pop = pool<root>::create(path, LAYOUT, 1 << 30);
transaction::exec_tx(pop, [&] {
auto tInfo = TableInfo("MyTable", {
ColumnInfo("a", ColumnInfo::Int_Type),
ColumnInfo("b", ColumnInfo::Int_Type),
ColumnInfo("c", ColumnInfo::String_Type),
ColumnInfo("d", ColumnInfo::Double_Type)
});
pop.get_root()->pTable =
make_persistent<PTableType>(tInfo, Dimensions({{0, {10, 17}}, {3, {10, 17}}}));
});
insert(pop, path, state.range(1));
} else {
std::cerr << "WARNING: Table already exists" << std::endl;
pop = pool<root>::open(path, LAYOUT);
......@@ -64,14 +41,6 @@ static void BM_PointQuery(benchmark::State& state) {
auto pTable = pop.get_root()->pTable;
for (auto i = 0; i < state.range(0); i++) {
auto tup = MyTuple(i + 1,
(i + 1) * 100,
fmt::format("String #{0}", i),
(i + 1) * 1.0);
pTable->insert(i + 1, tup);
}
for (auto _ : state) {
auto ptp = pTable->getByKey(state.range(1));
if (ptp.getNode() != nullptr) ptp.createTuple();
......@@ -80,11 +49,9 @@ static void BM_PointQuery(benchmark::State& state) {
pop.close();
std::remove(path.c_str());
}
BENCHMARK(BM_PointQuery)
->Args({100,50})
->Args({1000,500})
->Args({10000,5000})
->Args({100000,50000});
// ->Args({1000000,500000});
static void VectorArguments(benchmark::internal::Benchmark* b) {
for (const auto &arg : POINT_ACCESS) b->Args(arg);
}
BENCHMARK(BM_PointQuery)->Apply(VectorArguments);
BENCHMARK_MAIN();
......@@ -18,31 +18,20 @@
*/
#include <unistd.h>
#include "benchmark/benchmark.h"
#include "PTable.hpp"
#include "common.h"
using namespace ptable;
using nvml::obj::make_persistent;
using nvml::obj::p;
using nvml::obj::persistent_ptr;
using nvml::obj::pool;
using nvml::obj::transaction;
using MyTuple = std::tuple<int, int, std::string, double>;
using PTableType = PTable<MyTuple, int>;
const std::string path = "/mnt/pmem/test/benchdb.db";
static void BM_RangeScan(benchmark::State& state) {
struct root {
persistent_ptr<PTableType> pTable;
};
static void BM_RangeScan(benchmark::State &state) {
pool<root> pop;
if (access(path.c_str(), F_OK) != 0) {
throw PTableException("ERROR: Table not found");
insert(pop, path, NUM_TUPLES);
} else {
PLOG("Warning: " << path << " already exists");
pop = pool<root>::open(path, LAYOUT);
}
......@@ -50,31 +39,26 @@ static void BM_RangeScan(benchmark::State& state) {
/* RangeScan using Block iterator */
for (auto _ : state) {
auto iter = pTable->rangeScan(ColumnRangeMap({{0, std::make_pair<int, int>(state.range(0), state.range(1))}/*,
{2, std::make_pair<std::string, std::string>("String #1", "String #9")}*/}));
auto iter = pTable->rangeScan(ColumnRangeMap({{0, {state.range(0), state.range(1)}}}));
for (const auto &tp: iter) {
tp;
}
}
pop.close();
}
BENCHMARK(BM_RangeScan)
->Args({499500,500500}) // 0,1%
->Args({497500,502500}) // 0,5%
->Args({495000,505000}) // 1,0%
->Args({475000,525000}) // 5,0%
->Args({450000,550000});// 10,0%
static void BM_NonKeyRangeScan(benchmark::State& state) {
struct root {
persistent_ptr<PTableType> pTable;
};
static void KeyRangeArguments(benchmark::internal::Benchmark* b) {
for (const auto &arg : KEY_RANGES) b->Args(arg);
}
BENCHMARK(BM_RangeScan)->Apply(KeyRangeArguments);
static void BM_NonKeyRangeScan(benchmark::State &state) {
pool<root> pop;
if (access(path.c_str(), F_OK) != 0) {
std::cerr << "ERROR: Table not found" << std::endl;
return;
insert(pop, path, NUM_TUPLES);
} else {
PLOG("Warning: " << path << " already exists");
pop = pool<root>::open(path, LAYOUT);
}
......@@ -82,42 +66,38 @@ static void BM_NonKeyRangeScan(benchmark::State& state) {
/* RangeScan using Block iterator */
for (auto _ : state) {
auto iter = pTable->rangeScan(ColumnRangeMap({{0, std::make_pair<int, int>(state.range(0), state.range(1))},
{3, std::make_pair<double, double>(state.range(2), state.range(3))}}));
auto iter = pTable->rangeScan(ColumnRangeMap({{0, {state.range(0), state.range(1)}},
{3, {(double)state.range(2), (double)state.range(3)}}}));
for (const auto &tp: iter) {
tp;
}
}
pop.close();
}
BENCHMARK(BM_NonKeyRangeScan)
->Args({499000,501000, 500000, 502000}) // 0,1%
->Args({495000,505000, 500000, 510000}) // 0,5%
->Args({490000,510000, 500000, 520000}) // 1,0%
->Args({450000,550000, 500000, 600000}) // 5,0%
->Args({400000,600000, 500000, 700000});// 10,0%
static void BM_PBPTreeScan(benchmark::State& state) {
struct root {
persistent_ptr<PTableType> pTable;
};
static void NonKeyRangeArguments(benchmark::internal::Benchmark* b) {
for (const auto &arg : NON_KEY_RANGES) b->Args(arg);
}
BENCHMARK(BM_NonKeyRangeScan)->Apply(NonKeyRangeArguments);
static void BM_PBPTreeScan(benchmark::State &state) {
pool<root> pop;
if (access(path.c_str(), F_OK) != 0) {
std::cerr << "ERROR: Table not found" << std::endl;
return;
insert(pop, path, NUM_TUPLES);
} else {
PLOG("Warning: " << path << " already exists");
pop = pool<root>::open(path, LAYOUT);
}
auto pTable = pop.get_root()->pTable;
for (auto _ : state) {
/* Scan via PTuple iterator */
/* Scan via PTuple iterator */
auto eIter = pTable->end();
auto iter = pTable->select(
[](const PTuple<MyTuple, int> &tp) {
return (tp.get<0>() >= 800) && (tp.get<0>() <= 900);
return (tp.get<0>() >= KEY_RANGES[0][0]) && (tp.get<0>() <= KEY_RANGES[0][0]);
});
for (; iter != eIter; iter++) {
(*iter).get<0>();
......@@ -125,6 +105,7 @@ static void BM_PBPTreeScan(benchmark::State& state) {
}
pop.close();
std::remove(path.c_str());
}
BENCHMARK(BM_PBPTreeScan);
......
......@@ -23,47 +23,9 @@
using namespace ptable;
std::string PTableInfo::generateTypeDef() const {
std::ostringstream os;
bool first = true;
os << "TuplePtr<Tuple<";
for (auto& col : *mColumns) {
if (first)
first = false;
else
os << ", ";
os << col.getType();
}
os << ">>";
return os.str();
}
std::string PTableInfo::typeSignature() const {
std::ostringstream os;
os << "[";
for (auto& col : *mColumns) {
switch (col.getType()) {
case ColumnInfo::Void_Type:
os << "V";
break;
case ColumnInfo::Int_Type:
os << "i";
break;
case ColumnInfo::Double_Type:
os << "d";
break;
case ColumnInfo::String_Type:
os << "S";
break;
}
}
os << "]";
return os.str();
}
int PTableInfo::findColumnByName(const std::string& colName) const {
for (std::size_t i = 0; i < (*mColumns).size(); i++) {
if (mColumns->at(i).getName() == colName) return (int)i;
for (std::size_t i = 0; i < (*columns).size(); i++) {
if (columns->at(i).getName() == colName) return (int)i;
}
return -1;
}
\ No newline at end of file
......@@ -20,7 +20,7 @@
#ifndef PTableInfo_hpp_
#define PTableInfo_hpp_
#include "TableInfo.hpp"
#include "VTableInfo.hpp"
#include "PString.hpp"
#include <libpmemobj++/allocator.hpp>
......@@ -45,102 +45,79 @@ namespace ptable {
class PColumnInfo {
public:
PColumnInfo(pool_base pop) : PColumnInfo(pop, "", ColumnInfo::ColumnType::Void_Type) {}
PColumnInfo(pool_base pop) : PColumnInfo(pop, "", Void_Type) {}
PColumnInfo(pool_base pop, const std::string &n, ColumnInfo::ColumnType ct) : mColType(ct) {
PColumnInfo(pool_base pop, const std::string &n, ColumnType ct) : type(ct) {
transaction::exec_tx(pop, [&] {
mColName = make_persistent<char[]>(n.length() + 1);
strcpy(mColName.get(), n.c_str());
name = make_persistent<char[]>(n.length() + 1);
strcpy(name.get(), n.c_str());
});
}
const std::string getName() const { return mColName.get(); }
const std::string getName() const { return name.get(); }
const ColumnInfo::ColumnType getType() const { return mColType.get_ro(); }
const ColumnType getType() const { return type.get_ro(); }
private:
persistent_ptr<char[]> mColName;
p<ColumnInfo::ColumnType> mColType;
persistent_ptr<char[]> name;
p<ColumnType> type;
};
using ColumnInitList = std::initializer_list<std::pair<std::string, ColumnInfo::ColumnType>>;
class PTableInfo {
public:
using PTableInfoPtr = persistent_ptr<PTableInfo>;
using ColumnVector = std::vector<PColumnInfo, nvml::obj::allocator<PColumnInfo>>;
using ColumnIterator = ColumnVector::const_iterator;
using PColumnVector = std::vector<PColumnInfo, nvml::obj::allocator<PColumnInfo>>;
using PColumnIterator = PColumnVector::const_iterator;
PTableInfo() {}
PTableInfo(const TableInfo &_tInfo, ColumnInfo::ColumnType keyType = ColumnInfo::Void_Type) : mKeyType(keyType) {
PTableInfo(const VTableInfo &_tInfo, ColumnType _keyType = Void_Type) : keyType(_keyType) {
auto pop = pool_by_vptr(this);
transaction::exec_tx(pop, [&] {
mName.set(const_cast<std::string *>(&_tInfo.tableName()));
mColumns = make_persistent<ColumnVector>();
name.set(const_cast<std::string *>(&_tInfo.name));
columns = make_persistent<PColumnVector>();
for (const auto &c : _tInfo)
mColumns->push_back(PColumnInfo(pop, c.getName(), c.getType()));
columns->push_back(PColumnInfo(pop, c.first, c.second));
});
}
PTableInfo(const std::string &name, ColumnInitList columns,
ColumnInfo::ColumnType keyType = ColumnInfo::Void_Type) : mKeyType(keyType) {
PTableInfo(const std::string &_name, ColumnInitList _columns, ColumnType _keyType = Void_Type) :
keyType(_keyType) {
auto pop = pool_by_vptr(this);
transaction::exec_tx(pop, [&] {
mName.set(const_cast<std::string *>(&name));
mColumns = make_persistent<ColumnVector>();
for (const auto &c : columns)
mColumns->push_back(PColumnInfo(pop, c.first, c.second));
name.set(const_cast<std::string *>(&_name));
columns = make_persistent<PColumnVector>();
for (const auto &c : _columns)
columns->push_back(PColumnInfo(pop, c.first, c.second));
});
}
PTableInfo(const std::string &name, const ColumnVector &columns,
ColumnInfo::ColumnType keyType = ColumnInfo::Void_Type) : mKeyType(keyType) {
auto pop = pool_by_vptr(this);
transaction::exec_tx(pop, [&] {
mName.set(const_cast<std::string *>(&name));
mColumns = make_persistent<ColumnVector>(columns.begin(), columns.end());
});
}
const std::string tableName() const { return std::string(mName.data()); }
std::string typeSignature() const;
const std::string tableName() const { return std::string(name.data()); }
std::string generateTypeDef() const;
ColumnInfo::ColumnType typeOfKey() const { return mKeyType.get_ro(); }
ColumnType typeOfKey() const { return keyType.get_ro(); }
int findColumnByName(const std::string &colName) const;
const PColumnInfo &columnInfo(int pos) const { return mColumns->at(pos); }
const std::size_t numColumns() const { return mColumns->size(); }
const PColumnInfo &columnInfo(int pos) const { return columns->at(pos); }
void setColumns(const ColumnVector vec) {
auto pop = pool_by_vptr(this);
transaction::exec_tx(pop, [&] {
delete_persistent<ColumnVector>(mColumns);
mColumns = make_persistent<ColumnVector>(vec.cbegin(), vec.cend());
});
}
const std::size_t numColumns() const { return columns->size(); }
PTableInfoPtr makeShared() const {
void setColumns(const PColumnVector vec) {
auto pop = pool_by_vptr(this);
PTableInfoPtr tInfo_ptr = nullptr;
transaction::exec_tx(pop, [&] {
tInfo_ptr = make_persistent<PTableInfo>(std::string(mName.data()), *mColumns, mKeyType.get_ro());
delete_persistent<PColumnVector>(columns);
columns = make_persistent<PColumnVector>(vec.cbegin(), vec.cend());
});
return tInfo_ptr;
}
ColumnIterator begin() const { return mColumns->begin(); }
ColumnIterator end() const { return mColumns->end(); }
PColumnIterator begin() const { return columns->begin(); }
PColumnIterator end() const { return columns->end(); }
// private:
PString mName;
persistent_ptr<ColumnVector> mColumns;
p<ColumnInfo::ColumnType> mKeyType;
PString name;
persistent_ptr<PColumnVector> columns;
p<ColumnType> keyType;
};
} /* namespace ptable */
......
/*
* Copyright (C) 2017 DBIS Group - TU Ilmenau, All Rights Reserved.
*