mirror of
https://github.com/mfocko/blog.git
synced 2024-11-25 22:31:56 +01:00
118 lines
2.7 KiB
Python
118 lines
2.7 KiB
Python
#!/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()
|