Skip to content

Commit d1ee33f

Browse files
committed
Smarter determination of call_repetitions.
[skip ci]
1 parent 62040e5 commit d1ee33f

File tree

3 files changed

+92
-24
lines changed

3 files changed

+92
-24
lines changed

ubench/holder_comparison.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ PYBIND11_SMART_HOLDER_TYPE_CASTERS(hc::nb_sh)
4646

4747
PYBIND11_MODULE(pybind11_ubench_holder_comparison, m) {
4848
using namespace hc;
49+
m.def("sizeof_smart_holder", []() { return sizeof(py::smart_holder); });
4950
wrap_number_bucket<nb_up, std::unique_ptr<nb_up>>(m, "number_bucket_up");
5051
wrap_number_bucket<nb_sp, std::shared_ptr<nb_sp>>(m, "number_bucket_sp");
5152
wrap_number_bucket<nb_pu, padded_unique_ptr<nb_pu>>(m, "number_bucket_pu");

ubench/holder_comparison.py

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,33 @@ def run(args):
5454
num_samples,
5555
selected_holder_type,
5656
)
57+
pflush("sizeof_smart_holder:", m.sizeof_smart_holder())
58+
59+
def find_call_repetitions(
60+
callable,
61+
time_delta_floor=1.0e-6,
62+
target_elapsed_secs_multiplier=1.05, # Empirical.
63+
target_elapsed_secs_tolerance=0.05,
64+
max_iterations=100,
65+
):
66+
td_target = (
67+
call_repetitions_target_elapsed_secs * target_elapsed_secs_multiplier
68+
)
69+
crd = call_repetitions_first_pass
70+
for _ in range(max_iterations):
71+
td = callable(crd)
72+
crd = max(1, int(td_target * crd / max(td, time_delta_floor)))
73+
if abs(td - td_target) / td_target < target_elapsed_secs_tolerance:
74+
return crd
75+
raise RuntimeError("find_call_repetitions failure: max_iterations exceeded.")
5776

5877
for size_exponent in range(
5978
size_exponent_min, size_exponent_max + 1, size_exponent_step
6079
):
6180
data_size = 2 ** size_exponent
6281
pflush(data_size, "data_size")
6382
ratios = collections.defaultdict(list)
64-
call_repetitions_dynamic = None
83+
call_repetitions = None
6584
for _ in range(num_samples):
6685
row_0 = None
6786
for nb_label, nb_type in [
@@ -77,32 +96,27 @@ def run(args):
7796
continue
7897
nb1 = nb_type(data_size)
7998
nb2 = nb_type(data_size)
80-
if call_repetitions_dynamic is None:
99+
100+
def many_sum(call_repetitions):
81101
assert int(round(nb1.sum())) == data_size
82102
t0 = time.time()
83-
for _ in range(call_repetitions_first_pass):
103+
for _ in range(call_repetitions):
84104
nb1.sum()
85-
td_sum = time.time() - t0
86-
call_repetitions_dynamic = max(
87-
call_repetitions_first_pass,
88-
int(
89-
call_repetitions_target_elapsed_secs
90-
* call_repetitions_first_pass
91-
/ max(td_sum, 1.0e-6)
92-
)
93-
+ 1,
94-
)
95-
pflush(call_repetitions_dynamic, "call_repetitions_dynamic")
96-
assert int(round(nb1.sum())) == data_size
97-
t0 = time.time()
98-
for _ in range(call_repetitions_dynamic):
99-
nb1.sum()
100-
td_sum = time.time() - t0
101-
assert nb1.add(nb2) == data_size
102-
t0 = time.time()
103-
for _ in range(call_repetitions_dynamic):
104-
nb1.add(nb2)
105-
td_add = time.time() - t0
105+
return time.time() - t0
106+
107+
def many_add(call_repetitions):
108+
assert nb1.add(nb2) == data_size
109+
t0 = time.time()
110+
for _ in range(call_repetitions):
111+
nb1.add(nb2)
112+
return time.time() - t0
113+
114+
if call_repetitions is None:
115+
call_repetitions = find_call_repetitions(many_sum)
116+
pflush(call_repetitions, "call_repetitions")
117+
118+
td_sum = many_sum(call_repetitions)
119+
td_add = many_add(call_repetitions)
106120
row = [td_sum, td_add]
107121
if row_0 is None:
108122
pflush(" Sum Add ratS ratA")
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# -*- coding: utf-8 -*-
2+
"""Extract mean ratios from holder_comparison.py output."""
3+
4+
from __future__ import absolute_import
5+
from __future__ import division
6+
from __future__ import print_function
7+
8+
import sys
9+
10+
11+
def run(args):
12+
assert len(args) == 1, "log_holder_comparison.txt"
13+
14+
log_lines = open(args[0]).read().splitlines()
15+
16+
for ratx in ("_ratS ", "_ratA "):
17+
print(ratx)
18+
header = None
19+
header_row = None
20+
data_row = None
21+
22+
def show():
23+
if header_row:
24+
if header is None:
25+
print(",".join(header_row))
26+
else:
27+
assert header == header_row
28+
if data_row is not None:
29+
print(",".join(data_row))
30+
return header_row
31+
32+
for line in log_lines:
33+
if line.endswith(" data_size"):
34+
header = show()
35+
flds = line.split()
36+
assert len(flds) == 2
37+
header_row = ["data_size"]
38+
data_row = [flds[0]]
39+
elif line.endswith(" call_repetitions"):
40+
flds = line.split()
41+
assert len(flds) == 2
42+
header_row.append("calls")
43+
data_row.append(flds[0])
44+
elif line[2:].startswith(ratx):
45+
flds = line.split()
46+
assert len(flds) == 4
47+
header_row.append(line[:2])
48+
data_row.append(flds[2])
49+
show()
50+
51+
52+
if __name__ == "__main__":
53+
run(args=sys.argv[1:])

0 commit comments

Comments
 (0)