32 #include <system_error>
34 #include <unordered_set>
42 template <
typename A,
typename B>
43 struct hash<tuple<A, B>> {
44 std::size_t operator()(
const tuple<A, B>& t)
const {
45 auto a = std::hash<A>()(get<0>(t));
46 auto b = std::hash<B>()(get<1>(t));
48 return a ^ (
b + 0x9e3779b9 + (a << 6) + (a >> 2));
52 template <
typename A,
typename B>
53 std::ostream&
operator<<(std::ostream& out,
const tuple<A, B>& t) {
54 return out <<
"[" << get<0>(t) <<
"," << get<1>(t) <<
"]";
61 const bool DEBUG =
false;
67 EXPECT_EQ(3, test_set::max_keys_per_node);
77 if (
DEBUG) t.printTree();
175 for (
int i = 0;
i < 10;
i++) {
193 for (
int i = 0;
i < N;
i++) {
204 for (
int j = 0;
j < N;
j++) {
219 for (
int i = N;
i >= 0;
i--) {
229 for (
int j = 0;
j < N;
j++) {
242 std::vector<int>
data;
243 for (
int i = 0;
i < N;
i++) {
246 std::random_device rd;
247 std::mt19937 generator(rd());
249 shuffle(
data.begin(),
data.end(), generator);
251 for (
int i = 0;
i < N;
i++) {
257 for (
int i = 0;
i < N;
i++) {
269 std::vector<int>
data;
270 for (
int i = 0;
i < N;
i++) {
273 std::random_device rd;
274 std::mt19937 generator(rd());
276 shuffle(
data.begin(),
data.end(), generator);
278 for (
int i = 0;
i < N;
i++) {
284 for (
int i = 0;
i < N;
i++) {
297 for (
int i = 0;
i < N;
i++) {
300 for (
int i = 0;
i < N;
i++) {
310 for (
int i = 0;
i < N;
i++) {
338 TEST(BTreeSet, IteratorEmpty) {
345 TEST(BTreeSet, IteratorBasic) {
351 for (
int i = 0;
i <= N;
i++) {
370 TEST(BTreeSet, IteratorStress) {
377 std::vector<int>
data;
378 for (
int i = 0;
i < N;
i++) {
381 std::random_device rd;
382 std::mt19937 generator(rd());
384 shuffle(
data.begin(),
data.end(), generator);
387 for (
int i = 0;
i < N;
i++) {
407 for (
int i = 0;
i < 10;
i++) {
413 auto a = t.lower_bound(5);
416 auto b = t.upper_bound(5);
428 a = t.lower_bound(5);
431 b = t.upper_bound(5);
438 TEST(BTreeSet, BoundaryEmpty) {
448 EXPECT_EQ(t.lower_bound(3), t.upper_bound(3));
449 EXPECT_EQ(t.lower_bound(5), t.upper_bound(5));
452 EXPECT_EQ(t.lower_bound(3), t.upper_bound(3));
453 EXPECT_EQ(t.lower_bound(5), t.upper_bound(5));
457 EXPECT_EQ(t.lower_bound(3), t.upper_bound(3));
458 EXPECT_NE(t.lower_bound(5), t.upper_bound(5));
464 for (
int N = 0; N < 100; N++) {
466 std::vector<int>
data;
468 for (
int i = 0;
i < N;
i++) {
472 auto t = test_set::load(
data.begin(),
data.end());
511 for (
int i = 0;
i < 100;
i++) {
516 auto chunks = t.getChunks(20);
520 for (
const auto& cur : chunks) {
522 std::cout <<
i <<
", ";
528 for (
const auto& chunk : chunks) {
529 for (
auto current : chunk) {
536 TEST(BTreeSet, ChunkSplitStress) {
539 for (
int i = 0;
i < 1000;
i++) {
541 std::vector<int>
data;
542 for (
int j = 0;
j <
i;
j++) {
545 std::random_device rd;
546 std::mt19937 generator(rd());
548 shuffle(
data.begin(),
data.end(), generator);
557 for (
int j = 1;
j < 100;
j++) {
558 auto chunks = t.getChunks(
j);
561 if (chunks.empty())
continue;
567 for (
const auto& chunk : chunks) {
568 for (
auto current : chunk) {
579 using Entry = std::tuple<int, int>;
581 std::vector<Entry>
getData(
unsigned numEntries) {
582 std::vector<Entry> res(numEntries);
584 for (
unsigned i = 0;
i < numEntries;
i++) {
587 std::random_device rd;
588 std::mt19937 generator(rd());
590 shuffle(res.begin(), res.end(), generator);
601 return std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
604 template <
typename Op>
605 long time(
const std::string& name,
const Op& operation) {
606 std::cout <<
"\t" << std::setw(30) << std::setiosflags(std::ios::left) << name
607 << std::resetiosflags(std::ios::left) <<
" ... " << std::flush;
612 std::cout <<
" done [" << std::setw(5) <<
time <<
"ms]\n";
616 template <
typename C>
623 template <
typename A,
typename B,
typename C,
typename D>
624 struct reserver<
std::unordered_set<A, B, C, D>> {
630 #define checkPerformance(set_type, name, in, out) \
632 std::cout << "Testing: " << name << " ..\n"; \
634 time("filling set", [&]() { \
635 reserver<set_type>()(set, in.size()); \
636 for (const auto& cur : in) { \
640 EXPECT_EQ(in.size(), set.size()); \
642 time("full scan", [&]() { \
643 for (auto it = set.begin(); it != set.end(); ++it) { \
647 EXPECT_EQ(in.size(), (size_t)counter); \
648 bool allPresent = true; \
649 time("membership in", [&]() { \
650 for (const auto& cur : in) { \
651 allPresent = (set.find(cur) != set.end()) && allPresent; \
654 EXPECT_TRUE(allPresent); \
655 bool allMissing = true; \
656 time("membership out", [&]() { \
657 for (const auto& cur : out) { \
658 allMissing = (set.find(cur) == set.end()) && allMissing; \
661 EXPECT_TRUE(allMissing); \
662 bool allFound = true; \
663 time("lower_boundaries", [&]() { \
664 for (const auto& cur : in) { \
665 allFound = (set.lower_bound(cur) == set.find(cur)) && allFound; \
668 EXPECT_TRUE(allFound); \
670 time("upper_boundaries", [&]() { \
671 for (const auto& cur : in) { \
672 allFound = (set.upper_bound(cur) == (++set.find(cur))) && allFound; \
675 EXPECT_TRUE(allFound); \
677 time("boundaries on missing elements", [&]() { \
678 for (const auto& cur : out) { \
679 allFound = (set.lower_bound(cur) == set.upper_bound(cur)) && allFound; \
682 EXPECT_TRUE(allFound); \
683 set_type a(in.begin(), in.end()); \
684 set_type b(out.begin(), out.end()); \
685 time("merge two sets", [&]() { a.insert(b.begin(), b.end()); }); \
686 std::cout << "\tDone!\n\n"; \
689 TEST(Performance, Basic) {
694 std::cout <<
"Generating Test-Data ...\n";
695 std::vector<Entry> in;
696 std::vector<Entry> out;
697 time(
"generating data", [&]() {
699 for (std::size_t
i = 0;
i <
data.size();
i += 2) {
700 in.push_back(
data[
i]);
701 out.push_back(
data[
i + 1]);
705 using t1 = std::set<Entry>;
708 using t2 = btree_set<Entry, detail::comparator<Entry>, std::allocator<Entry>, 256, detail::linear_search>;
711 using t3 = btree_set<Entry, detail::comparator<Entry>, std::allocator<Entry>, 256, detail::binary_search>;
715 TEST(Performance, Load) {
719 std::vector<int>
data;
720 for (
int i = 0;
i < N;
i++) {
725 time(
"conventional load", [&]() { btree_set<int> t(
data.begin(),
data.end()); });
741 std::vector<entry_t> list;
744 for (
int i = 0;
i < N;
i++) {
749 for (
int dup = 1; dup < 4; dup++) {
751 std::vector<entry_t> full;
752 for (
int i = 0;
i < dup;
i++) {
753 for (
const auto& cur : list) {
759 std::random_device rd;
760 std::mt19937 generator(rd());
762 std::shuffle(full.begin(), full.end(), generator);
766 #pragma omp parallel for // schedule(static,1)
767 for (
auto it = full.begin(); it < full.end(); ++it) {
776 std::set<entry_t> should(full.begin(), full.end());
777 std::set<entry_t> is(res.
begin(), res.
end());
779 for (
const auto& cur : should) {
783 for (
const auto& cur : res) {
784 EXPECT_TRUE(should.find(cur) != should.end()) <<
"Additional: " << cur <<
"\n"
785 <<
"Contained: " << res.contains(cur) <<
"\n";
788 std::vector<entry_t> extra;
789 for (
const auto& cur : is) {
790 if (should.find(cur) == should.end()) extra.push_back(cur);
792 EXPECT_TRUE(extra.empty()) <<
"Extra elments: " << extra <<
"\n";
794 std::vector<entry_t> missing;
795 for (
const auto& cur : should) {
796 if (is.find(cur) == is.end()) missing.push_back(cur);
798 EXPECT_TRUE(missing.empty()) <<
"Missing elments: " << missing <<
"\n";
809 TEST(BTreeSet, ParallelScaling) {
811 using op_context_type = test_set::operation_hints;
819 std::vector<int>
data;
820 for (
int i = 0;
i < N;
i++) {
823 std::vector<int> data2 =
data;
824 std::random_device rd;
825 std::mt19937 generator(rd());
827 std::shuffle(
data.begin(),
data.end(), generator);
828 std::shuffle(data2.begin(), data2.end(), generator);
830 for (
int i = 1;
i <= 8;
i++) {
833 omp_set_num_threads(
i);
835 double start = omp_get_wtime();
839 op_context_type ctxt;
842 for (
int i = 0;
i < N;
i++) {
843 t.insert(
data[
i], ctxt);
844 t.insert(data2[
i], ctxt);
848 double end = omp_get_wtime();
850 std::cout <<
"Number of threads: " <<
i <<
"[" << (end - start) <<
"ms]\n";