1
0
Fork 0
mirror of https://github.com/mfocko/blog.git synced 2025-05-08 04:12:59 +02:00
This commit is contained in:
github-actions[bot] 2023-11-28 18:40:59 +00:00
parent dbd784b359
commit 0b9bf3d392
407 changed files with 1120 additions and 338 deletions

View file

@ -0,0 +1,133 @@
#include <bit>
#include <cassert>
#include <chrono>
#include <cstdint>
#include <functional>
#include <iostream>
#include <ranges>
#include <set>
#include <string>
#include <unordered_set>
using elem_t = std::uint64_t;
const elem_t N_ELEMENTS = 10000000;
#define LOOPS 10
template <typename T> struct strategy {
virtual std::string name() const = 0;
virtual T elements() = 0;
template <typename C> void run(C &&s) {
using namespace std;
cout << "\nBenchmarking:\t\t" << name() << '\n';
auto start = chrono::steady_clock::now();
for (auto x : elements()) {
s.insert(x);
}
auto after_insertion = chrono::steady_clock::now();
auto insertion_time =
chrono::duration_cast<chrono::milliseconds>(after_insertion - start);
cout << "Insertion phase:\t" << insertion_time << "\n";
start = chrono::steady_clock::now();
for (int i = 0; i < LOOPS; ++i) {
for (auto x : elements()) {
assert(s.contains(x));
}
}
auto after_lookups = chrono::steady_clock::now();
auto lookup_time =
chrono::duration_cast<chrono::milliseconds>(after_lookups - start);
cout << "Lookup phase:\t\t" << lookup_time << "\n";
}
virtual ~strategy() = default;
};
using iota_t =
decltype(std::views::iota(static_cast<elem_t>(0), static_cast<elem_t>(0)));
struct ascending_ordered_sequence : public strategy<iota_t> {
std::string name() const override { return "ordered sequence (ascending)"; }
iota_t elements() override {
return std::views::iota(static_cast<elem_t>(0), N_ELEMENTS);
}
};
static elem_t reverse(elem_t x) { return static_cast<elem_t>(N_ELEMENTS) - x; }
using reversed_iota_t =
decltype(std::views::iota(static_cast<elem_t>(0), static_cast<elem_t>(0)) |
std::views::transform(reverse));
struct descending_ordered_sequence : public strategy<reversed_iota_t> {
std::string name() const override { return "ordered sequence (descending)"; }
reversed_iota_t elements() override {
return std::views::iota(static_cast<elem_t>(1), N_ELEMENTS + 1) |
std::views::transform(reverse);
}
};
static elem_t attack(elem_t x) { return x << (5 + std::bit_width(x)); }
using attacked_iota_t =
decltype(std::views::iota(static_cast<elem_t>(0), static_cast<elem_t>(0)) |
std::views::transform(attack));
struct progressive_ascending_attack : public strategy<attacked_iota_t> {
std::string name() const override {
return "progressive sequence that self-heals on resize";
}
attacked_iota_t elements() override {
return std::views::iota(static_cast<elem_t>(0), N_ELEMENTS) |
std::views::transform(attack);
}
};
using reversed_attacked_iota_t =
decltype(std::views::iota(static_cast<elem_t>(0), static_cast<elem_t>(0)) |
std::views::transform(reverse) | std::views::transform(attack));
struct progressive_descending_attack
: public strategy<reversed_attacked_iota_t> {
std::string name() const override {
return "progressive sequence that self-heals in the end";
}
reversed_attacked_iota_t elements() override {
return std::views::iota(static_cast<elem_t>(1), N_ELEMENTS + 1) |
std::views::transform(reverse) | std::views::transform(attack);
}
};
static elem_t shift(elem_t x) { return x << 32; }
using shifted_iota_t =
decltype(std::views::iota(static_cast<elem_t>(0), static_cast<elem_t>(0)) |
std::views::transform(shift));
struct hard_attack : public strategy<shifted_iota_t> {
std::string name() const override { return "carefully chosen numbers"; }
shifted_iota_t elements() override {
return std::views::iota(static_cast<elem_t>(0), N_ELEMENTS) |
std::views::transform(shift);
}
};
template <typename C> void run_all(const std::string &note) {
std::cout << "\n«" << note << "»\n";
ascending_ordered_sequence{}.run(C{});
descending_ordered_sequence{}.run(C{});
progressive_ascending_attack{}.run(C{});
progressive_descending_attack{}.run(C{});
hard_attack{}.run(C{});
}
int main() {
run_all<std::unordered_set<elem_t>>("hash table");
run_all<std::set<elem_t>>("red-black tree");
return 0;
}

View file

@ -0,0 +1,118 @@
#!/usr/bin/env python3
from functools import cached_property
from time import monotonic_ns
N_ELEMENTS = 10_000_000
LOOPS = 10
class Strategy:
def __init__(self, data_structure=set):
self._table = data_structure()
@cached_property
def elements(self):
raise NotImplementedError("Implement for each strategy")
@property
def name(self):
raise NotImplementedError("Implement for each strategy")
def run(self):
print(f"\nBenchmarking:\t\t{self.name}")
# Extract the elements here, so that the evaluation of them does not
# slow down the relevant part of benchmark
elements = self.elements
# Insertion phase
start = monotonic_ns()
for x in elements:
self._table.add(x)
after_insertion = monotonic_ns()
print(f"Insertion phase:\t{(after_insertion - start) / 1000000:.2f}ms")
# Lookup phase
start = monotonic_ns()
for _ in range(LOOPS):
for x in elements:
assert x in self._table
after_lookups = monotonic_ns()
print(f"Lookup phase:\t\t{(after_lookups - start) / 1000000:.2f}ms")
class AscendingOrderedSequence(Strategy):
@property
def name(self):
return "ordered sequence (ascending)"
@cached_property
def elements(self):
return [x for x in range(N_ELEMENTS)]
class DescendingOrderedSequence(Strategy):
@property
def name(self):
return "ordered sequence (descending)"
@cached_property
def elements(self):
return [x for x in reversed(range(N_ELEMENTS))]
class ProgressiveAttack(Strategy):
@staticmethod
def _break(n):
return n << max(5, n.bit_length())
class ProgressiveAscendingAttack(ProgressiveAttack):
@property
def name(self):
return "progressive sequence that self-heals on resize"
@cached_property
def elements(self):
return [self._break(x) for x in range(N_ELEMENTS)]
class ProgressiveDescendingAttack(ProgressiveAttack):
@property
def name(self):
return "progressive sequence that self-heals in the end"
@cached_property
def elements(self):
return [self._break(x) for x in reversed(range(N_ELEMENTS))]
class HardAttack(Strategy):
@property
def name(self):
return "carefully chosen numbers"
@cached_property
def elements(self):
return [x << 32 for x in range(N_ELEMENTS)]
STRATEGIES = [
AscendingOrderedSequence,
DescendingOrderedSequence,
ProgressiveAscendingAttack,
ProgressiveDescendingAttack,
HardAttack,
]
def main():
for strategy in STRATEGIES:
strategy().run()
if __name__ == "__main__":
main()

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.