Skip to content

Commit db847b4

Browse files
committed
Update ringbuffer benchmark
Signed-off-by: Mathias L. Baumann <[email protected]>
1 parent 352e19c commit db847b4

File tree

1 file changed

+108
-62
lines changed

1 file changed

+108
-62
lines changed

benchmarks/timeseries/benchmark_ringbuffer.py

Lines changed: 108 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ def fill_buffer(
2525
"""Fill the given buffer up to the given amount of days, one sample per minute."""
2626
random.seed(0)
2727
basetime = datetime(2022, 1, 1)
28+
print("..filling", end="", flush=True)
2829

2930
for day in range(days):
3031
# Push in random order
@@ -35,11 +36,8 @@ def fill_buffer(
3536
)
3637

3738

38-
def test_days(days: int, buffer: OrderedRingBuffer[int, Any]) -> None:
39-
"""Fills a buffer completely up and then gets the data for each of the 29 days."""
40-
print(".", end="", flush=True)
41-
42-
fill_buffer(days, buffer, int)
39+
def test_days(days: int, buffer: OrderedRingBuffer[T, Any]) -> None:
40+
"""Gets the data for each of the 29 days."""
4341

4442
basetime = datetime(2022, 1, 1)
4543

@@ -50,119 +48,167 @@ def test_days(days: int, buffer: OrderedRingBuffer[int, Any]) -> None:
5048
)
5149

5250

53-
def test_slices(days: int, buffer: OrderedRingBuffer[T, Any]) -> None:
51+
def test_slices(days: int, buffer: OrderedRingBuffer[T, Any], median: bool) -> None:
5452
"""Benchmark slicing.
5553
5654
Takes a buffer, fills it up and then excessively gets
5755
the data for each day to calculate the average/median.
5856
"""
59-
print(".", end="", flush=True)
60-
fill_buffer(days, buffer, float)
6157

62-
# Chose uneven starting point so that for the first/last window data has to
63-
# be copied
64-
basetime = datetime(2022, 1, 1, 0, 5, 13, 88)
58+
basetime = datetime(2022, 1, 1)
6559

66-
total_avg = 0.0
67-
total_median = 0.0
60+
total = 0.0
6861

69-
for _ in range(5):
62+
for _ in range(3):
7063
for day in range(days):
7164
minutes = buffer.window(
7265
basetime + timedelta(days=day), basetime + timedelta(days=day + 1)
7366
)
7467

75-
total_avg += float(np.average(minutes))
76-
total_median += float(np.median(minutes))
68+
if median:
69+
total += float(np.median(minutes))
70+
else:
71+
total += float(np.average(minutes))
7772

7873

79-
def test_29_days_list() -> None:
74+
def test_29_days_list(num_runs: int) -> dict:
8075
"""Run the 29 day test on the list backend."""
81-
test_days(29, OrderedRingBuffer([0] * MINUTES_IN_29_DAYS, timedelta(minutes=1)))
8276

77+
days = 29
78+
buffer = OrderedRingBuffer([0] * MINUTES_IN_29_DAYS, timedelta(minutes=1))
79+
80+
fill_time = timeit.Timer(lambda: fill_buffer(days, buffer, int)).timeit(number=1)
81+
test_time = timeit.Timer(lambda: test_days(days, buffer)).timeit(number=num_runs)
82+
return {"fill": fill_time, "test": test_time}
8383

84-
def test_29_days_array() -> None:
84+
85+
def test_29_days_array(num_runs: int) -> dict:
8586
"""Run the 29 day test on the array backend."""
86-
test_days(
87-
29,
88-
OrderedRingBuffer(
89-
np.empty(
90-
shape=MINUTES_IN_29_DAYS,
91-
),
92-
timedelta(minutes=1),
87+
days = 29
88+
buffer = OrderedRingBuffer(
89+
np.empty(
90+
shape=MINUTES_IN_29_DAYS,
9391
),
92+
timedelta(minutes=1),
9493
)
9594

95+
fill_time = timeit.Timer(lambda: fill_buffer(days, buffer, int)).timeit(number=1)
96+
test_time = timeit.Timer(lambda: test_days(days, buffer)).timeit(number=num_runs)
97+
return {"fill": fill_time, "test": test_time}
98+
9699

97-
def test_29_days_slicing_list() -> None:
100+
def test_29_days_slicing_list(num_runs: int) -> dict:
98101
"""Run slicing tests on list backend."""
99-
test_slices(29, OrderedRingBuffer([0] * MINUTES_IN_29_DAYS, timedelta(minutes=1)))
102+
days = 29
103+
buffer = OrderedRingBuffer([0] * MINUTES_IN_29_DAYS, timedelta(minutes=1))
100104

105+
fill_time = timeit.Timer(lambda: fill_buffer(days, buffer, int)).timeit(number=1)
106+
median_test_time = timeit.Timer(
107+
lambda: test_slices(days, buffer, median=True)
108+
).timeit(number=num_runs)
109+
avg_test_time = timeit.Timer(
110+
lambda: test_slices(days, buffer, median=False)
111+
).timeit(number=num_runs)
101112

102-
def test_29_days_slicing_array() -> None:
113+
return {"fill": fill_time, "median": median_test_time, "avg": avg_test_time}
114+
115+
116+
def test_29_days_slicing_array(num_runs: int) -> dict:
103117
"""Run slicing tests on array backend."""
104-
test_slices(
105-
29,
106-
OrderedRingBuffer(
107-
np.empty(
108-
shape=MINUTES_IN_29_DAYS,
109-
),
110-
timedelta(minutes=1),
118+
days = 29
119+
buffer = OrderedRingBuffer(
120+
np.empty(
121+
shape=MINUTES_IN_29_DAYS,
111122
),
123+
timedelta(minutes=1),
112124
)
113125

126+
fill_time = timeit.Timer(lambda: fill_buffer(days, buffer, int)).timeit(number=1)
127+
median_test_time = timeit.Timer(
128+
lambda: test_slices(days, buffer, median=True)
129+
).timeit(number=num_runs)
130+
avg_test_time = timeit.Timer(
131+
lambda: test_slices(days, buffer, median=False)
132+
).timeit(number=num_runs)
133+
134+
return {"fill": fill_time, "median": median_test_time, "avg": avg_test_time}
135+
114136

115137
def main() -> None:
116138
"""Run benchmark.
117139
118140
Result of previous run:
119141
120-
Date: Do 22. Dez 15:03:05 CET 2022
142+
Date: Mi 1. Feb 17:15:02 CET 2023
121143
Result:
122144
123-
=========================================
124-
Array: ........................................
125-
List: ........................................
145+
=====================
146+
Array: ..filling
147+
List: ..filling
126148
Time to fill 29 days with data:
127-
Array: 0.09411649959984061 seconds
128-
List: 0.0906366748000437 seconds
129-
Diff: 0.0034798247997969156
130-
=========================================
131-
Array: ........................................
132-
List: ........................................
133-
Filling 29 days and running average & mean on every day:
134-
Array: 0.09842290654996759 seconds
135-
List: 0.1316629376997298 seconds
136-
Diff: -0.03324003114976222
149+
Array: 7.190492740017362 seconds
150+
List: 7.209744154009968 seconds
151+
Diff: -0.019251413992606103
152+
Day-Slices into 29 days with data:
153+
Array: 0.0001254317001439631 seconds
154+
List: 0.00017958255193661898 seconds
155+
Diff: -5.4150851792655874e-05
156+
=====================
157+
Array: ..filling
158+
List: ..filling
159+
Avg of windows of 29 days and running average & mean on every day:
160+
Array: 0.0007975498505402356 seconds
161+
List: 0.0042349924508016555 seconds
162+
Diff: -0.0034374426002614198
163+
Median of windows of 29 days and running average & mean on every day:
164+
Array: 0.0021774103515781462 seconds
165+
List: 0.004992740901070647 seconds
166+
Diff: -0.0028153305494925005
137167
"""
138-
num_runs = 40
168+
num_runs = 20
139169

140170
print(f" {''.join(['='] * (num_runs + 1))}")
141171
print("Array: ", end="")
142-
duration_array = timeit.Timer(test_29_days_array).timeit(number=num_runs)
172+
array_times = test_29_days_array(num_runs)
173+
143174
print("\nList: ", end="")
144-
duration_list = timeit.Timer(test_29_days_list).timeit(number=num_runs)
175+
176+
list_times = test_29_days_list(num_runs)
145177
print("")
146178

147179
print(
148180
"Time to fill 29 days with data:\n\t"
149-
+ f"Array: {duration_array/num_runs} seconds\n\t"
150-
+ f"List: {duration_list/num_runs} seconds\n\t"
151-
+ f"Diff: {duration_array/num_runs - duration_list/num_runs}"
181+
+ f"Array: {array_times['fill']} seconds\n\t"
182+
+ f"List: {list_times['fill']} seconds\n\t"
183+
+ f"Diff: {array_times['fill'] - list_times['fill']}"
184+
)
185+
186+
print(
187+
"Day-Slices into 29 days with data:\n\t"
188+
+ f"Array: {array_times['test']/num_runs} seconds\n\t"
189+
+ f"List: {list_times['test']/num_runs} seconds\n\t"
190+
+ f"Diff: {array_times['test']/num_runs - list_times['test']/num_runs}"
152191
)
153192

154193
print(f" {''.join(['='] * (num_runs + 1))}")
155194
print("Array: ", end="")
156-
duration_array = timeit.Timer(test_29_days_slicing_array).timeit(number=num_runs)
195+
slicing_array_times = test_29_days_slicing_array(num_runs)
157196
print("\nList: ", end="")
158-
duration_list = timeit.Timer(test_29_days_slicing_list).timeit(number=num_runs)
197+
slicing_list_times = test_29_days_slicing_list(num_runs)
159198
print("")
160199

161200
print(
162-
"Filling 29 days and running average & mean on every day:\n\t"
163-
+ f"Array: {duration_array/num_runs} seconds\n\t"
164-
+ f"List: {duration_list/num_runs} seconds\n\t"
165-
+ f"Diff: {duration_array/num_runs - duration_list/num_runs}"
201+
"Avg of windows of 29 days and running average & mean on every day:\n\t"
202+
+ f"Array: {slicing_array_times['avg']/num_runs} seconds\n\t"
203+
+ f"List: {slicing_list_times['avg']/num_runs} seconds\n\t"
204+
+ f"Diff: {slicing_array_times['avg']/num_runs - slicing_list_times['avg']/num_runs}"
205+
)
206+
207+
print(
208+
"Median of windows of 29 days and running average & mean on every day:\n\t"
209+
+ f"Array: {slicing_array_times['median']/num_runs} seconds\n\t"
210+
+ f"List: {slicing_list_times['median']/num_runs} seconds\n\t"
211+
+ f"Diff: {slicing_array_times['median']/num_runs - slicing_list_times['median']/num_runs}"
166212
)
167213

168214

0 commit comments

Comments
 (0)