-
Notifications
You must be signed in to change notification settings - Fork 17
/
benchmark_ringbuffer.py
135 lines (102 loc) · 3.52 KB
/
benchmark_ringbuffer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# License: MIT
# Copyright © 2022 Frequenz Energy-as-a-Service GmbH
"""
Performance test for the `Ringbuffer` class
"""
import random
from datetime import datetime, timedelta
import numpy as np
from frequenz.sdk.util.ringbuffer import (
ArrayContainer,
ListContainer,
OrderedRingBuffer,
RingBuffer,
)
MINUTES_IN_29_DAYS = 29 * 24 * 60
def fill_buffer(days, buffer):
"""Fill the given buffer up to the given amount of days, one sample per
minute"""
random.seed(0)
basetime = datetime(2022, 1, 1)
for day in range(days):
# Push in random order
for i in random.sample(range(24 * 60), 24 * 60):
buffer.update(basetime + timedelta(days=day, minutes=i, seconds=i % 3), i)
# Fills a buffer completely up and then gets the data for each of the 29 days
def test_days(days, buffer):
print(".", end="", flush=True)
fill_buffer(days, buffer)
basetime = datetime(2022, 1, 1)
for day in range(days):
minutes = buffer.window(
basetime + timedelta(days=day), basetime + timedelta(days=day + 1)
)
# Takes a buffer, fills it up and then excessively gets the data for each day to
# calculate the average/median.
def test_slices(days, buffer):
print(".", end="", flush=True)
fill_buffer(days, buffer)
# Chose uneven starting point so that for the first/last window data has to
# be copied
basetime = datetime(2022, 1, 1, 0, 5, 13, 88)
total = 0
for _ in range(5):
for day in range(days):
minutes = buffer.window(
basetime + timedelta(days=day), basetime + timedelta(days=day + 1)
)
total += np.average(minutes)
(f"{basetime + timedelta(days=day)} average {np.average(minutes)}")
(f"{basetime + timedelta(days=day)} median {np.median(minutes)}")
# print(total)
# Fills a buffer completely up and then gets the data for each of the 29 days
def test_29_days_list():
test_days(29, OrderedRingBuffer([0] * MINUTES_IN_29_DAYS, 60))
def test_29_days_array():
test_days(
29,
OrderedRingBuffer(
np.empty(
shape=MINUTES_IN_29_DAYS,
),
60,
),
)
def test_29_days_slicing_list():
test_slices(29, OrderedRingBuffer([0] * MINUTES_IN_29_DAYS, 60))
def test_29_days_slicing_array():
test_slices(
29,
OrderedRingBuffer(
np.empty(
shape=MINUTES_IN_29_DAYS,
),
60,
),
)
import timeit
num_runs = 40
print(f" {''.join(['='] * (num_runs + 1))}")
print("Array: ", end="")
duration_array = timeit.Timer(test_29_days_array).timeit(number=num_runs)
print("\nList: ", end="")
duration_list = timeit.Timer(test_29_days_list).timeit(number=num_runs)
print("")
print(
f"Time to fill 29 days with data:\n\t"
+ f"Array: {duration_array/num_runs} seconds\n\t"
+ f"List: {duration_list/num_runs} seconds\n\t"
+ f"Diff: {duration_array/num_runs - duration_list/num_runs}"
)
print(f" {''.join(['='] * (num_runs + 1))}")
print("Array: ", end="")
duration_array = timeit.Timer(test_29_days_slicing_array).timeit(number=num_runs)
print("\nList: ", end="")
duration_list = timeit.Timer(test_29_days_slicing_list).timeit(number=num_runs)
print("")
print(
f"Filling 29 days and running average & mean on every day:\n\t"
+ f"Array: {duration_array/num_runs} seconds\n\t"
+ f"List: {duration_list/num_runs} seconds\n\t"
+ f"Diff: {duration_array/num_runs - duration_list/num_runs}"
)