-
Notifications
You must be signed in to change notification settings - Fork 5
/
test_performance.py
160 lines (136 loc) · 5.8 KB
/
test_performance.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# %%
from __future__ import annotations
import os
import timeit
from cityseer import rustalgos
from cityseer.tools import graphs, io
def test_local_centrality_time(primal_graph):
"""
NOTE - rust built in development mode will be slow - build via PDM install instead
Keep in mind there are several extraneous variables:
e.g. may be fairly dramatic differences in timing on larger graphs and larger search distances
originally based on node_harmonic and node_betweenness:
OLD VERSION with trim maps:
Timing: 10.490865555 for 10000 iters
version with numba typed list - faster and removes arcane full vs. trim maps workflow
8.24 for 10000 iters
version with node_edge_map Dict - tad slower but worthwhile for cleaner and more intuitive code
8.88 for 10000 iters
version with shortest path tree algo simplified to nodes and non-angular only
8.19 for 10000 iters
version with jitclasses and float32
<7 for 10000 iters
without jitclasses again
5.2 for 10000 iters
without proto funcs (cacheing)
5.15
computing all closeness and with rust
~4.58 for 10000 iterations with hashmap metrics
~4.09 for 10000 iterations with vec metrics
~3.72 for 10000 iterations for single closeness vs all five
~2.16 for 10000 iterations with vecs instead of hashmaps in closest path tree
~2.14 for 10000 iterations with vecs converted to numpy
~3.05 for 10000 iterations with both closeness and betweenness
notes:
- Segments of unreachable code used to add to timing: this seems to have been fixed in more recent versions of numba
- Separating the logic into functions results in ever so slightly slower times...
though this may be due to function setup at invocation (x10000) which wouldn't be incurred in real scenarios...?
- Tests on using a List(Dict('x', 'y', etc.) structure proved almost four times slower, so sticking with arrays
- Experiments with golang proved too complex re: bindings...
- Ended up with rust
Rust
shortest_path_tree_wrapper: 0.28707868605852127 for 10000 iterations
node_cent_wrapper: 3.1882867829408497 for 10000 iterations
segment_cent_wrapper: 5.971783181885257 for 10000 iterations
Heap
shortest_path_tree_wrapper: 0.2747780899517238 for 10000 iterations
node_cent_wrapper: 3.095424270024523 for 10000 iterations
segment_cent_wrapper: 5.882331402972341 for 10000 iterations
Split functions
dijkstra_tree_shortest_wrapper: 0.11545719904825091 for 10000 iterations
dijkstra_tree_simplest_wrapper: 0.10305578005500138 for 10000 iterations
dijkstra_tree_segment_wrapper: 0.2831501439213753 for 10000 iterations
node_cent_wrapper: 3.0920922509394586 for 10000 iterations
segment_cent_wrapper: 5.607312946114689 for 10000 iterations
"""
if "GITHUB_ACTIONS" in os.environ:
return
os.environ["CITYSEER_QUIET_MODE"] = "1"
# load the test graph
_nodes_gdf, _edges_gdf, network_structure = io.network_structure_from_nx(primal_graph, 3395)
# needs a large enough beta so that distance thresholds aren't encountered
distances, _betas = rustalgos.pair_distances_and_betas(distances=[5000])
def dijkstra_tree_shortest_wrapper():
network_structure.dijkstra_tree_shortest(
src_idx=0,
max_dist=5000,
)
# prime the function
dijkstra_tree_shortest_wrapper()
iters = 10000
# time and report
func_time = timeit.timeit(dijkstra_tree_shortest_wrapper, number=iters)
print(f"dijkstra_tree_shortest_wrapper: {func_time} for {iters} iterations")
assert func_time < 1
def dijkstra_tree_simplest_wrapper():
network_structure.dijkstra_tree_simplest(
src_idx=0,
max_dist=5000,
)
# prime the function
dijkstra_tree_simplest_wrapper()
iters = 10000
# time and report
func_time = timeit.timeit(dijkstra_tree_simplest_wrapper, number=iters)
print(f"dijkstra_tree_simplest_wrapper: {func_time} for {iters} iterations")
assert func_time < 1
def dijkstra_tree_segment_wrapper():
network_structure.dijkstra_tree_segment(
src_idx=0,
max_dist=5000,
)
# prime the function
dijkstra_tree_segment_wrapper()
iters = 10000
# time and report
func_time = timeit.timeit(dijkstra_tree_segment_wrapper, number=iters)
print(f"dijkstra_tree_segment_wrapper: {func_time} for {iters} iterations")
assert func_time < 1
def node_cent_wrapper():
network_structure.local_node_centrality_shortest(
distances=distances,
betas=None,
compute_closeness=True,
compute_betweenness=True,
pbar_disabled=True,
)
# prime the function
node_cent_wrapper()
iters = 10000
# time and report
func_time = timeit.timeit(node_cent_wrapper, number=iters)
print(f"node_cent_wrapper: {func_time} for {iters} iterations")
assert func_time < 5
# node_cent_wrapper: 3.5858502141200006 for 10000 iterations
def segment_cent_wrapper():
network_structure.local_segment_centrality(
distances=distances,
betas=None,
compute_closeness=True,
compute_betweenness=True,
pbar_disabled=True,
)
# prime the function
segment_cent_wrapper()
iters = 10000
# time and report - roughly 9.36s on 4.2GHz i7
func_time = timeit.timeit(segment_cent_wrapper, number=iters)
print(f"segment_cent_wrapper: {func_time} for {iters} iterations")
assert func_time < 8
# segment_cent_wrapper: 6.134561971062794 for 10000 iterations
if __name__ == "__main__":
from cityseer.tools import graphs
from cityseer.tools.mock import mock_graph
G_primal = mock_graph()
G_primal = graphs.nx_simple_geoms(G_primal)
test_local_centrality_time(G_primal)