Skip to content

Commit 0bb4403

Browse files
Fix: solve import issues for performance tests (#22)
* Update test_get_downstream_nodes Co-authored-by: jaapschoutenalliander <jaap.schouten@alliander.com> Signed-off-by: Thijs Baaijen <13253091+Thijss@users.noreply.github.com> * Update performance tests Co-authored-by: jaapschoutenalliander <jaap.schouten@alliander.com> Signed-off-by: Thijs Baaijen <13253091+Thijss@users.noreply.github.com> --------- Signed-off-by: Thijs Baaijen <13253091+Thijss@users.noreply.github.com> Co-authored-by: jaapschoutenalliander <jaap.schouten@alliander.com>
1 parent 76fadb3 commit 0bb4403

File tree

7 files changed

+127
-123
lines changed

7 files changed

+127
-123
lines changed

tests/performance/_constants.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,18 @@
66
"dtype = [('id', '<i8'), ('test_int', '<i8'), ('test_float', '<f8'), ('test_str', '<U50'), ('test_bool', '?')]; "
77
)
88

9-
SETUP_CODES = {
10-
"structured": "import numpy as np;" + NUMPY_DTYPE + "input_array = np.zeros({array_size}, dtype=dtype)",
11-
"rec": "import numpy as np;" + NUMPY_DTYPE + "input_array = np.recarray(({array_size},),dtype=dtype)",
12-
"fancy": "from tests.conftest import FancyTestArray; input_array=FancyTestArray.zeros({array_size});"
13-
+ "import numpy as np;input_array.id = np.arange({array_size})",
9+
ARRAY_SETUP_CODES = {
10+
"structured": "import numpy as np;" + NUMPY_DTYPE + "input_array = np.zeros({size}, dtype=dtype)",
11+
"rec": "import numpy as np;" + NUMPY_DTYPE + "input_array = np.recarray(({size},),dtype=dtype)",
12+
"fancy": "from tests.conftest import FancyTestArray; input_array=FancyTestArray.zeros({size});"
13+
+ "import numpy as np;input_array.id = np.arange({size})",
1414
}
1515

1616
GRAPH_SETUP_CODES = {
17-
"rustworkx": "from power_grid_model_ds.model.grids.base import Grid;"
18-
+ "from power_grid_model_ds.data_source.generator.grid_generators import RadialGridGenerator;"
19-
+ "from power_grid_model_ds.model.graphs.models import RustworkxGraphModel;"
20-
+ "grid=RadialGridGenerator(nr_nodes={graph_size}, grid_class=Grid, graph_model=RustworkxGraphModel).run()",
17+
"rustworkx": "from power_grid_model_ds import Grid;"
18+
+ "from power_grid_model_ds.generators import RadialGridGenerator;"
19+
+ "from power_grid_model_ds.graph_models import RustworkxGraphModel;"
20+
+ "grid=RadialGridGenerator(nr_nodes={size}, grid_class=Grid, graph_model=RustworkxGraphModel).run()",
2121
}
2222

2323
SINGLE_REPEATS = 1000

tests/performance/_helpers.py

Lines changed: 29 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -4,100 +4,57 @@
44

55
import inspect
66
import timeit
7-
from typing import Generator
7+
from itertools import product
8+
from typing import Generator, Union
89

9-
from tests.performance._constants import GRAPH_SETUP_CODES, SETUP_CODES
10-
11-
12-
def do_performance_test(code_to_test: str | dict[str, str], array_sizes: list[int], repeats: int):
13-
"""Run the performance test for the given code."""
1410

11+
def do_performance_test(
12+
code_to_test: Union[str, dict[str, str], list[str]],
13+
size_list: list[int],
14+
repeats: int,
15+
setup_codes: dict[str, str],
16+
):
17+
"""Generalized performance test runner."""
1518
print(f"{'-' * 20} {inspect.stack()[1][3]} {'-' * 20}")
1619

17-
for array_size in array_sizes:
20+
for size in size_list:
21+
formatted_setup_codes = {key: code.format(size=size) for key, code in setup_codes.items()}
1822
if isinstance(code_to_test, dict):
19-
code_to_test_list = [code_to_test[variant].format(array_size=array_size) for variant in SETUP_CODES]
20-
else:
21-
code_to_test_list = [code_to_test.format(array_size=array_size)] * len(SETUP_CODES)
22-
print(f"\n\tArray size: {array_size}\n")
23-
setup_codes = [setup_code.format(array_size=array_size) for setup_code in SETUP_CODES.values()]
24-
timings = _get_timings(setup_codes, code_to_test_list, repeats)
25-
26-
if code_to_test == "pass":
27-
_print_timings(timings, list(SETUP_CODES.keys()), setup_codes)
23+
code_to_test_list = [code_to_test[variant].format(size=size) for variant in setup_codes]
24+
test_generator = zip(formatted_setup_codes.items(), code_to_test_list)
25+
elif isinstance(code_to_test, list):
26+
code_to_test_list = [code.format(size=size) for code in code_to_test]
27+
test_generator = product(formatted_setup_codes.items(), code_to_test_list)
2828
else:
29-
_print_timings(timings, list(SETUP_CODES.keys()), code_to_test_list)
30-
print()
29+
test_generator = product(formatted_setup_codes.items(), [code_to_test.format(size=size)])
3130

31+
print(f"\n\tsize: {size}\n")
3232

33-
def do_graph_test(code_to_test: str | dict[str, str], graph_sizes: list[int], repeats: int):
34-
"""Run the performance test for the given code."""
33+
timings = _get_timings(test_generator, repeats=repeats)
34+
_print_timings(timings)
3535

36-
print(f"{'-' * 20} {inspect.stack()[1][3]} {'-' * 20}")
37-
38-
for graph_size in graph_sizes:
39-
if isinstance(code_to_test, dict):
40-
code_to_test_list = [code_to_test[variant] for variant in GRAPH_SETUP_CODES]
41-
else:
42-
code_to_test_list = [code_to_test] * len(GRAPH_SETUP_CODES)
43-
print(f"\n\tGraph size: {graph_size}\n")
44-
setup_codes = [setup_code.format(graph_size=graph_size) for setup_code in GRAPH_SETUP_CODES.values()]
45-
timings = _get_timings(setup_codes, code_to_test_list, repeats)
46-
47-
if code_to_test == "pass":
48-
_print_graph_timings(timings, list(GRAPH_SETUP_CODES.keys()), setup_codes)
49-
else:
50-
_print_graph_timings(timings, list(GRAPH_SETUP_CODES.keys()), code_to_test_list)
5136
print()
5237

5338

54-
def _print_test_code(code: str | dict[str, str], repeats: int):
55-
print(f"{'-' * 40}")
56-
if isinstance(code, dict):
57-
for variant, code_variant in code.items():
58-
print(f"{variant}")
59-
print(f"\t{code_variant} (x {repeats})")
60-
return
61-
print(f"{code} (x {repeats})")
62-
63-
64-
def _print_graph_timings(timings: Generator, graph_types: list[str], code_list: list[str]):
65-
for graph_type, timing, code in zip(graph_types, timings, code_list):
66-
if ";" in code:
67-
code = code.split(";")[-1]
68-
69-
code = code.replace("\n", " ").replace("\t", " ")
70-
code = f"{graph_type}: " + code
71-
72-
if isinstance(timing, Exception):
73-
print(f"\t\t{code.ljust(100)} | Not supported")
74-
continue
75-
print(f"\t\t{code.ljust(100)} | {sum(timing):.2f}s")
76-
77-
78-
def _print_timings(timings: Generator, array_types: list[str], code_list: list[str]):
79-
for array, timing, code in zip(array_types, timings, code_list):
80-
if ";" in code:
81-
code = code.split(";")[-1]
82-
83-
code = code.replace("\n", " ").replace("\t", " ")
84-
array_name = f"{array}_array"
85-
code = code.replace("input_array", array_name)
39+
def _print_timings(timings: Generator):
40+
for key, code, timing in timings:
41+
code = code.split(";")[-1].replace("\n", " ").replace("\t", " ")
42+
code = f"{key}: {code}"
8643

8744
if isinstance(timing, Exception):
8845
print(f"\t\t{code.ljust(100)} | Not supported")
8946
continue
9047
print(f"\t\t{code.ljust(100)} | {sum(timing):.2f}s")
9148

9249

93-
def _get_timings(setup_codes: list[str], test_codes: list[str], repeats: int):
50+
def _get_timings(test_generator, repeats: int):
9451
"""Return a generator with the timings for each array type."""
95-
for setup_code, test_code in zip(setup_codes, test_codes):
52+
for (key, setup_code), test_code in test_generator:
9653
if test_code == "pass":
97-
yield timeit.repeat(setup_code, number=repeats)
54+
yield key, "intialise", timeit.repeat(setup_code, number=repeats)
9855
else:
9956
try:
100-
yield timeit.repeat(test_code, setup_code, number=repeats)
57+
yield key, test_code, timeit.repeat(test_code, setup_code, number=repeats)
10158
# pylint: disable=broad-exception-caught
10259
except Exception as error: # noqa
103-
yield error
60+
yield key, test_code, error

tests/performance/array_performance_tests.py

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,24 @@
1111

1212
import logging
1313

14-
from tests.performance._constants import ARRAY_SIZES_LARGE, ARRAY_SIZES_SMALL, LOOP_REPEATS, SINGLE_REPEATS
14+
from tests.performance._constants import (
15+
ARRAY_SETUP_CODES,
16+
ARRAY_SIZES_LARGE,
17+
ARRAY_SIZES_SMALL,
18+
LOOP_REPEATS,
19+
SINGLE_REPEATS,
20+
)
1521
from tests.performance._helpers import do_performance_test
1622

1723
logging.basicConfig(level=logging.INFO)
1824

1925

2026
def perftest_initialize():
21-
do_performance_test("pass", ARRAY_SIZES_LARGE, SINGLE_REPEATS)
27+
do_performance_test("pass", ARRAY_SIZES_LARGE, SINGLE_REPEATS, ARRAY_SETUP_CODES)
2228

2329

2430
def perftest_slice():
25-
do_performance_test("input_array[0:10]", ARRAY_SIZES_LARGE, SINGLE_REPEATS)
31+
do_performance_test("input_array[0:10]", ARRAY_SIZES_LARGE, SINGLE_REPEATS, ARRAY_SETUP_CODES)
2632

2733

2834
def perftest_set_attr():
@@ -31,77 +37,77 @@ def perftest_set_attr():
3137
"rec": "input_array.id = 1",
3238
"fancy": "input_array.id = 1",
3339
}
34-
do_performance_test(code_to_test, ARRAY_SIZES_LARGE, SINGLE_REPEATS)
40+
do_performance_test(code_to_test, ARRAY_SIZES_LARGE, SINGLE_REPEATS, ARRAY_SETUP_CODES)
3541

3642

3743
def perftest_set_field():
38-
do_performance_test("input_array['id'] = 1", ARRAY_SIZES_LARGE, SINGLE_REPEATS)
44+
do_performance_test("input_array['id'] = 1", ARRAY_SIZES_LARGE, SINGLE_REPEATS, ARRAY_SETUP_CODES)
3945

4046

4147
def perftest_loop_slice_1():
42-
code_to_test = "for i in range({array_size}): input_array[i]"
43-
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, LOOP_REPEATS)
48+
code_to_test = "for i in range({size}): input_array[i]"
49+
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, LOOP_REPEATS, ARRAY_SETUP_CODES)
4450

4551

4652
def perftest_loop_data_slice_1():
4753
code_to_test = {
48-
"structured": "for i in range({array_size}): input_array[i]",
49-
"rec": "for i in range({array_size}): input_array[i]",
50-
"fancy": "for i in range({array_size}): input_array.data[i]",
54+
"structured": "for i in range({size}): input_array[i]",
55+
"rec": "for i in range({size}): input_array[i]",
56+
"fancy": "for i in range({size}): input_array.data[i]",
5157
}
52-
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, LOOP_REPEATS)
58+
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, LOOP_REPEATS, ARRAY_SETUP_CODES)
5359

5460

5561
def perftest_loop_slice():
56-
code_to_test = "for i in range({array_size}): input_array[i:i+1]"
57-
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, LOOP_REPEATS)
62+
code_to_test = "for i in range({size}): input_array[i:i+1]"
63+
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, LOOP_REPEATS, ARRAY_SETUP_CODES)
5864

5965

6066
def perftest_loop_set_field():
61-
code_to_test = "for i in range({array_size}): input_array['id'][i] = 1"
62-
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, LOOP_REPEATS)
67+
code_to_test = "for i in range({size}): input_array['id'][i] = 1"
68+
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, LOOP_REPEATS, ARRAY_SETUP_CODES)
6369

6470

6571
def perftest_loop_get_field():
6672
code_to_test = "for row in input_array: row['id']"
67-
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, LOOP_REPEATS)
73+
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, LOOP_REPEATS, ARRAY_SETUP_CODES)
6874

6975

7076
def perftest_loop_data_get_field():
7177
code_to_test = "for row in input_array.data: row['id']"
72-
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, LOOP_REPEATS)
78+
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, LOOP_REPEATS, ARRAY_SETUP_CODES)
7379

7480

7581
def perftest_loop_get_attr():
7682
code_to_test = "for row in input_array: row.id"
77-
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, 100)
83+
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, 100, ARRAY_SETUP_CODES)
7884

7985

8086
def perftest_fancypy_concat():
8187
code_to_test = {
8288
"structured": "import numpy as np;np.concatenate([input_array, input_array])",
8389
"rec": "import numpy as np;np.concatenate([input_array, input_array])",
84-
"fancy": "import power_grid_model_ds._core.fancypy as fp;fp.concatenate(input_array, input_array)",
90+
"fancy": "import power_grid_model_ds.fancypy as fp;fp.concatenate(input_array, input_array)",
8591
}
86-
do_performance_test(code_to_test, ARRAY_SIZES_LARGE, 100)
92+
do_performance_test(code_to_test, ARRAY_SIZES_LARGE, 100, ARRAY_SETUP_CODES)
8793

8894

8995
def perftest_fancypy_unique():
9096
code_to_test = {
9197
"structured": "import numpy as np;np.unique(input_array)",
9298
"rec": "import numpy as np;np.unique(input_array)",
93-
"fancy": "import power_grid_model_ds._core.fancypy as fp;fp.unique(input_array)",
99+
"fancy": "import power_grid_model_ds.fancypy as fp;fp.unique(input_array)",
94100
}
95-
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, 100)
101+
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, 100, ARRAY_SETUP_CODES)
96102

97103

98104
def perftest_fancypy_sort():
99105
code_to_test = {
100106
"structured": "import numpy as np;np.sort(input_array)",
101107
"rec": "import numpy as np;np.sort(input_array)",
102-
"fancy": "import power_grid_model_ds._core.fancypy as fp;fp.sort(input_array)",
108+
"fancy": "import power_grid_model_ds.fancypy as fp;fp.sort(input_array)",
103109
}
104-
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, 100)
110+
do_performance_test(code_to_test, ARRAY_SIZES_SMALL, 100, ARRAY_SETUP_CODES)
105111

106112

107113
if __name__ == "__main__":

tests/performance/filter_performance_tests.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
#
33
# SPDX-License-Identifier: MPL-2.0
44

5-
from tests.performance._constants import ARRAY_SIZES_LARGE, SINGLE_REPEATS
5+
from tests.performance._constants import ARRAY_SETUP_CODES, ARRAY_SIZES_LARGE, SINGLE_REPEATS
66
from tests.performance._helpers import do_performance_test
77

88
# pylint: disable=missing-function-docstring
@@ -14,7 +14,7 @@ def perftest_get():
1414
"rec": "input_array[np.isin(input_array['id'], 99)]",
1515
"fancy": "try:\n\tinput_array.get(id=99)\nexcept:\n\tpass",
1616
}
17-
do_performance_test(code_to_test, ARRAY_SIZES_LARGE, SINGLE_REPEATS)
17+
do_performance_test(code_to_test, ARRAY_SIZES_LARGE, SINGLE_REPEATS, ARRAY_SETUP_CODES)
1818

1919

2020
def perftest_filter():
@@ -23,16 +23,16 @@ def perftest_filter():
2323
"rec": "input_array[np.isin(input_array['id'], 99)]",
2424
"fancy": "input_array.filter(id=99)",
2525
}
26-
do_performance_test(code_to_test, ARRAY_SIZES_LARGE, SINGLE_REPEATS)
26+
do_performance_test(code_to_test, ARRAY_SIZES_LARGE, SINGLE_REPEATS, ARRAY_SETUP_CODES)
2727

2828

2929
def perftest_update_by_id():
3030
code_to_test = {
31-
"structured": "input_array['test_float'][np.isin(input_array['id'], np.arange({array_size}))] = 42.0",
32-
"rec": "input_array['test_float'][np.isin(input_array['id'], np.arange({array_size}))] = 42.0",
33-
"fancy": "input_array.update_by_id(ids=np.arange({array_size}), test_float=42.0, allow_missing = False)",
31+
"structured": "input_array['test_float'][np.isin(input_array['id'], np.arange({size}))] = 42.0",
32+
"rec": "input_array['test_float'][np.isin(input_array['id'], np.arange({size}))] = 42.0",
33+
"fancy": "input_array.update_by_id(ids=np.arange({size}), test_float=42.0, allow_missing = False)",
3434
}
35-
do_performance_test(code_to_test, ARRAY_SIZES_LARGE, SINGLE_REPEATS)
35+
do_performance_test(code_to_test, ARRAY_SIZES_LARGE, SINGLE_REPEATS, ARRAY_SETUP_CODES)
3636

3737

3838
if __name__ == "__main__":

tests/performance/graph_performance_tests.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
#
33
# SPDX-License-Identifier: MPL-2.0
44

5-
from tests.performance._helpers import do_graph_test
5+
from tests.performance._constants import GRAPH_SETUP_CODES
6+
from tests.performance._helpers import do_performance_test
67

78
# pylint: disable=missing-function-docstring
89

@@ -11,40 +12,40 @@
1112

1213

1314
def perftest_initialize():
14-
do_graph_test("pass", [10, 100], 100)
15+
do_performance_test("pass", [10, 100], 100, setup_codes=GRAPH_SETUP_CODES)
1516

1617

1718
def perftest_get_components():
1819
code_to_test = (
19-
"from power_grid_model_ds._core.model.enums.nodes import NodeType;"
20+
"from power_grid_model_ds.enums import NodeType;"
2021
+ "feeder_node_ids=grid.node.filter(node_type=NodeType.SUBSTATION_NODE).id;"
2122
+ "grid.graphs.active_graph.get_components(feeder_node_ids)"
2223
)
23-
do_graph_test(code_to_test, GRAPH_SIZES, 100)
24+
do_performance_test(code_to_test, GRAPH_SIZES, 100, setup_codes=GRAPH_SETUP_CODES)
2425

2526

2627
def perftest_set_feeder_ids():
2728
code_to_test = "grid.set_feeder_ids()"
28-
do_graph_test(code_to_test, GRAPH_SIZES, 100)
29+
do_performance_test(code_to_test, GRAPH_SIZES, 100, setup_codes=GRAPH_SETUP_CODES)
2930

3031

3132
def perftest_delete_node():
3233
code_to_test = "grid.delete_node(grid.node[0]);"
33-
do_graph_test(code_to_test, GRAPH_SIZES, 100)
34+
do_performance_test(code_to_test, GRAPH_SIZES, 100, setup_codes=GRAPH_SETUP_CODES)
3435

3536

3637
def perftest_from_arrays():
3738
code_to_test = "grid.graphs.complete_graph.__class__.from_arrays(grid);"
38-
do_graph_test(code_to_test, GRAPH_SIZES, 100)
39+
do_performance_test(code_to_test, GRAPH_SIZES, 100, setup_codes=GRAPH_SETUP_CODES)
3940

4041

4142
def perftest_add_node():
4243
code_to_test = (
43-
"from power_grid_model_ds._core.model.arrays import NodeArray;"
44+
"from power_grid_model_ds.arrays import NodeArray;"
4445
+ "new_node = NodeArray.zeros(1);"
4546
+ "grid.add_node(node=new_node)"
4647
)
47-
do_graph_test(code_to_test, GRAPH_SIZES, 100)
48+
do_performance_test(code_to_test, GRAPH_SIZES, 100, setup_codes=GRAPH_SETUP_CODES)
4849

4950

5051
if __name__ == "__main__":

0 commit comments

Comments
 (0)