Skip to content

Commit 027501f

Browse files
authored
Merge c957f5b into d3ec617
2 parents d3ec617 + c957f5b commit 027501f

File tree

17 files changed

+321
-162
lines changed

17 files changed

+321
-162
lines changed

benchmarks/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ repeats _between_ `setup()` calls using the `repeat` attribute.
118118
`warmup_time = 0` is also advisable since ASV performs independent re-runs to
119119
estimate run-time, and these will still be subject to the original problem.
120120

121+
### Custom benchmarks
122+
123+
Iris benchmarking implements custom benchmark types, such as a `tracemalloc`
124+
benchmark to measure memory growth. See [custom_bms/](./custom_bms) for more
125+
detail.
126+
121127
### Scaling / non-Scaling Performance Differences
122128

123129
**(We no longer advocate the below for benchmarks run during CI, given the

benchmarks/asv.conf.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,12 @@
5353
"command_comment": [
5454
"We know that the Nox command takes care of installation in each",
5555
"environment, and in the case of Iris no specialised uninstall or",
56-
"build commands are needed to get it working."
56+
"build commands are needed to get it working.",
57+
58+
"We do however need to install the custom benchmarks for them to be",
59+
"usable."
5760
],
5861
"install_command": [],
5962
"uninstall_command": [],
60-
"build_command": []
63+
"build_command": ["python {conf_dir}/custom_bms/install.py"]
6164
}

benchmarks/benchmarks/__init__.py

Lines changed: 0 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -37,111 +37,6 @@ def disable_repeat_between_setup(benchmark_object):
3737
return benchmark_object
3838

3939

40-
class TrackAddedMemoryAllocation:
41-
"""Measures by how much process resident memory grew, during execution.
42-
43-
Context manager which measures by how much process resident memory grew,
44-
during execution of its enclosed code block.
45-
46-
Obviously limited as to what it actually measures : Relies on the current
47-
process not having significant unused (de-allocated) memory when the
48-
tested codeblock runs, and only reliable when the code allocates a
49-
significant amount of new memory.
50-
51-
Example:
52-
with TrackAddedMemoryAllocation() as mb:
53-
initial_call()
54-
other_call()
55-
result = mb.addedmem_mb()
56-
57-
Attributes
58-
----------
59-
RESULT_MINIMUM_MB : float
60-
The smallest result that should ever be returned, in Mb. Results
61-
fluctuate from run to run (usually within 1Mb) so if a result is
62-
sufficiently small this noise will produce a before-after ratio over
63-
AVD's detection threshold and be treated as 'signal'. Results
64-
smaller than this value will therefore be returned as equal to this
65-
value, ensuring fractionally small noise / no noise at all.
66-
Defaults to 1.0
67-
68-
RESULT_ROUND_DP : int
69-
Number of decimal places of rounding on result values (in Mb).
70-
Defaults to 1
71-
72-
"""
73-
74-
RESULT_MINIMUM_MB = 0.2
75-
RESULT_ROUND_DP = 1 # I.E. to nearest 0.1 Mb
76-
77-
def __enter__(self):
78-
tracemalloc.start()
79-
return self
80-
81-
def __exit__(self, *_):
82-
_, peak_mem_bytes = tracemalloc.get_traced_memory()
83-
tracemalloc.stop()
84-
# Save peak-memory allocation, scaled from bytes to Mb.
85-
self._peak_mb = peak_mem_bytes * (2.0**-20)
86-
87-
def addedmem_mb(self):
88-
"""Return measured memory growth, in Mb."""
89-
result = self._peak_mb
90-
# Small results are too vulnerable to noise being interpreted as signal.
91-
result = max(self.RESULT_MINIMUM_MB, result)
92-
# Rounding makes results easier to read.
93-
result = np.round(result, self.RESULT_ROUND_DP)
94-
return result
95-
96-
@staticmethod
97-
def decorator(decorated_func):
98-
"""Benchmark to track growth in resident memory during execution.
99-
100-
Intended for use on ASV ``track_`` benchmarks. Applies the
101-
:class:`TrackAddedMemoryAllocation` context manager to the benchmark
102-
code, sets the benchmark ``unit`` attribute to ``Mb``.
103-
104-
"""
105-
106-
def _wrapper(*args, **kwargs):
107-
assert decorated_func.__name__[:6] == "track_"
108-
# Run the decorated benchmark within the added memory context
109-
# manager.
110-
with TrackAddedMemoryAllocation() as mb:
111-
decorated_func(*args, **kwargs)
112-
return mb.addedmem_mb()
113-
114-
decorated_func.unit = "Mb"
115-
return _wrapper
116-
117-
@staticmethod
118-
def decorator_repeating(repeats=3):
119-
"""Benchmark to track growth in resident memory during execution.
120-
121-
Tracks memory for repeated calls of decorated function.
122-
123-
Intended for use on ASV ``track_`` benchmarks. Applies the
124-
:class:`TrackAddedMemoryAllocation` context manager to the benchmark
125-
code, sets the benchmark ``unit`` attribute to ``Mb``.
126-
127-
"""
128-
129-
def decorator(decorated_func):
130-
def _wrapper(*args, **kwargs):
131-
assert decorated_func.__name__[:6] == "track_"
132-
# Run the decorated benchmark within the added memory context
133-
# manager.
134-
with TrackAddedMemoryAllocation() as mb:
135-
for _ in range(repeats):
136-
decorated_func(*args, **kwargs)
137-
return mb.addedmem_mb()
138-
139-
decorated_func.unit = "Mb"
140-
return _wrapper
141-
142-
return decorator
143-
144-
14540
def on_demand_benchmark(benchmark_object):
14641
"""Disable these benchmark(s) unless ON_DEMAND_BENCHARKS env var is set.
14742

benchmarks/benchmarks/cperf/save.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from iris import save
88

9-
from .. import TrackAddedMemoryAllocation, on_demand_benchmark
9+
from .. import on_demand_benchmark
1010
from ..generate_data.ugrid import make_cube_like_2d_cubesphere, make_cube_like_umfield
1111
from . import _N_CUBESPHERE_UM_EQUIVALENT, _UM_DIMS_YX
1212

@@ -36,6 +36,5 @@ def _save_data(self, cube):
3636
def time_save_data_netcdf(self, data_type):
3737
self._save_data(self.cube)
3838

39-
@TrackAddedMemoryAllocation.decorator
40-
def track_addedmem_save_data_netcdf(self, data_type):
39+
def tracemalloc_save_data_netcdf(self, data_type):
4140
self._save_data(self.cube)

benchmarks/benchmarks/experimental/ugrid/regions_combine.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD
1919
from iris.experimental.ugrid.utils import recombine_submeshes
2020

21-
from ... import TrackAddedMemoryAllocation
2221
from ...generate_data.ugrid import make_cube_like_2d_cubesphere
2322

2423

@@ -171,8 +170,7 @@ def setup(self, n_cubesphere):
171170
def time_create_combined_cube(self, n_cubesphere):
172171
self.recombine()
173172

174-
@TrackAddedMemoryAllocation.decorator
175-
def track_addedmem_create_combined_cube(self, n_cubesphere):
173+
def tracemalloc_create_combined_cube(self, n_cubesphere):
176174
self.recombine()
177175

178176

@@ -182,8 +180,7 @@ class CombineRegionsComputeRealData(MixinCombineRegions):
182180
def time_compute_data(self, n_cubesphere):
183181
_ = self.recombined_cube.data
184182

185-
@TrackAddedMemoryAllocation.decorator
186-
def track_addedmem_compute_data(self, n_cubesphere):
183+
def tracemalloc_compute_data(self, n_cubesphere):
187184
_ = self.recombined_cube.data
188185

189186

@@ -201,8 +198,7 @@ def time_save(self, n_cubesphere):
201198
# Save to disk, which must compute data + stream it to file.
202199
save(self.recombined_cube, "tmp.nc")
203200

204-
@TrackAddedMemoryAllocation.decorator
205-
def track_addedmem_save(self, n_cubesphere):
201+
def tracemalloc_save(self, n_cubesphere):
206202
save(self.recombined_cube, "tmp.nc")
207203

208204
def track_filesize_saved(self, n_cubesphere):
@@ -229,6 +225,5 @@ def time_stream_file2file(self, n_cubesphere):
229225
# Save to disk, which must compute data + stream it to file.
230226
save(self.recombined_cube, "tmp.nc")
231227

232-
@TrackAddedMemoryAllocation.decorator
233-
def track_addedmem_stream_file2file(self, n_cubesphere):
228+
def tracemalloc_stream_file2file(self, n_cubesphere):
234229
save(self.recombined_cube, "tmp.nc")

benchmarks/benchmarks/merge_concat.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
from iris.cube import CubeList
1010

11-
from . import TrackAddedMemoryAllocation
1211
from .generate_data.stock import realistic_4d_w_everything
1312

1413

@@ -34,10 +33,11 @@ def setup(self):
3433
def time_merge(self):
3534
_ = self.cube_list.merge_cube()
3635

37-
@TrackAddedMemoryAllocation.decorator_repeating()
38-
def track_mem_merge(self):
36+
def tracemalloc_merge(self):
3937
_ = self.cube_list.merge_cube()
4038

39+
tracemalloc_merge.number = 3 # type: ignore[attr-defined]
40+
4141

4242
class Concatenate:
4343
# TODO: Improve coverage.
@@ -56,6 +56,7 @@ def setup(self):
5656
def time_concatenate(self):
5757
_ = self.cube_list.concatenate_cube()
5858

59-
@TrackAddedMemoryAllocation.decorator_repeating()
60-
def track_mem_merge(self):
59+
def tracemalloc_concatenate(self):
6160
_ = self.cube_list.concatenate_cube()
61+
62+
tracemalloc_concatenate.number = 3 # type: ignore[attr-defined]

benchmarks/benchmarks/regridding.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
from iris.analysis import AreaWeighted, PointInCell
1515
from iris.coords import AuxCoord
1616

17-
from . import TrackAddedMemoryAllocation
18-
1917

2018
class HorizontalChunkedRegridding:
2119
def setup(self) -> None:
@@ -53,20 +51,22 @@ def time_regrid_area_w_new_grid(self) -> None:
5351
# Realise data
5452
out.data
5553

56-
@TrackAddedMemoryAllocation.decorator_repeating()
57-
def track_mem_regrid_area_w(self) -> None:
54+
def tracemalloc_regrid_area_w(self) -> None:
5855
# Regrid the chunked cube
5956
out = self.cube.regrid(self.template_cube, self.scheme_area_w)
6057
# Realise data
6158
out.data
6259

63-
@TrackAddedMemoryAllocation.decorator_repeating()
64-
def track_mem_regrid_area_w_new_grid(self) -> None:
60+
tracemalloc_regrid_area_w.number = 3 # type: ignore[attr-defined]
61+
62+
def tracemalloc_regrid_area_w_new_grid(self) -> None:
6563
# Regrid the chunked cube
6664
out = self.chunked_cube.regrid(self.template_cube, self.scheme_area_w)
6765
# Realise data
6866
out.data
6967

68+
tracemalloc_regrid_area_w_new_grid.number = 3 # type: ignore[attr-defined]
69+
7070

7171
class CurvilinearRegridding:
7272
def setup(self) -> None:
@@ -110,9 +110,10 @@ def time_regrid_pic(self) -> None:
110110
# Realise the data
111111
out.data
112112

113-
@TrackAddedMemoryAllocation.decorator_repeating()
114-
def track_mem_regrid_pic(self) -> None:
113+
def tracemalloc_regrid_pic(self) -> None:
115114
# Regrid the cube onto the template.
116115
out = self.cube.regrid(self.template_cube, self.scheme_pic)
117116
# Realise the data
118117
out.data
118+
119+
tracemalloc_regrid_pic.number = 3 # type: ignore[attr-defined]

benchmarks/benchmarks/save.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from iris import save
88
from iris.experimental.ugrid import save_mesh
99

10-
from . import TrackAddedMemoryAllocation, on_demand_benchmark
1110
from .generate_data.ugrid import make_cube_like_2d_cubesphere
1211

1312

@@ -38,8 +37,7 @@ def time_netcdf_save_mesh(self, n_cubesphere, is_unstructured):
3837
if is_unstructured:
3938
self._save_mesh(self.cube)
4039

41-
@TrackAddedMemoryAllocation.decorator
42-
def track_addedmem_netcdf_save(self, n_cubesphere, is_unstructured):
40+
def tracemalloc_netcdf_save(self, n_cubesphere, is_unstructured):
4341
# Don't need to copy the cube here since track_ benchmarks don't
4442
# do repeats between self.setup() calls.
4543
self._save_data(self.cube, do_copy=False)

benchmarks/benchmarks/sperf/combine_regions.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from iris.experimental.ugrid import PARSE_UGRID_ON_LOAD
1414
from iris.experimental.ugrid.utils import recombine_submeshes
1515

16-
from .. import TrackAddedMemoryAllocation, on_demand_benchmark
16+
from .. import on_demand_benchmark
1717
from ..generate_data.ugrid import BENCHMARK_DATA, make_cube_like_2d_cubesphere
1818

1919

@@ -177,8 +177,7 @@ def setup(self, n_cubesphere, imaginary_data=True, create_result_cube=False):
177177
def time_create_combined_cube(self, n_cubesphere):
178178
self.recombine()
179179

180-
@TrackAddedMemoryAllocation.decorator
181-
def track_addedmem_create_combined_cube(self, n_cubesphere):
180+
def tracemalloc_create_combined_cube(self, n_cubesphere):
182181
self.recombine()
183182

184183

@@ -189,8 +188,7 @@ class ComputeRealData(Mixin):
189188
def time_compute_data(self, n_cubesphere):
190189
_ = self.recombined_cube.data
191190

192-
@TrackAddedMemoryAllocation.decorator
193-
def track_addedmem_compute_data(self, n_cubesphere):
191+
def tracemalloc_compute_data(self, n_cubesphere):
194192
_ = self.recombined_cube.data
195193

196194

@@ -208,8 +206,7 @@ def time_save(self, n_cubesphere):
208206
# Save to disk, which must compute data + stream it to file.
209207
self.save_recombined_cube()
210208

211-
@TrackAddedMemoryAllocation.decorator
212-
def track_addedmem_save(self, n_cubesphere):
209+
def tracemalloc_save(self, n_cubesphere):
213210
self.save_recombined_cube()
214211

215212
def track_filesize_saved(self, n_cubesphere):
@@ -235,6 +232,5 @@ def time_stream_file2file(self, n_cubesphere):
235232
# Save to disk, which must compute data + stream it to file.
236233
self.save_recombined_cube()
237234

238-
@TrackAddedMemoryAllocation.decorator
239-
def track_addedmem_stream_file2file(self, n_cubesphere):
235+
def tracemalloc_stream_file2file(self, n_cubesphere):
240236
self.save_recombined_cube()

benchmarks/benchmarks/sperf/save.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from iris import save
1010
from iris.experimental.ugrid import save_mesh
1111

12-
from .. import TrackAddedMemoryAllocation, on_demand_benchmark
12+
from .. import on_demand_benchmark
1313
from ..generate_data.ugrid import make_cube_like_2d_cubesphere
1414

1515

@@ -36,8 +36,7 @@ def _save_mesh(self, cube):
3636
def time_save_cube(self, n_cubesphere, is_unstructured):
3737
self._save_cube(self.cube)
3838

39-
@TrackAddedMemoryAllocation.decorator
40-
def track_addedmem_save_cube(self, n_cubesphere, is_unstructured):
39+
def tracemalloc_save_cube(self, n_cubesphere, is_unstructured):
4140
self._save_cube(self.cube)
4241

4342
def time_save_mesh(self, n_cubesphere, is_unstructured):

0 commit comments

Comments
 (0)