Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 29 additions & 34 deletions benchmarks/benchmarks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
# See COPYING and COPYING.LESSER in the root of the repository for full
# licensing details.
"""Common code for benchmarks."""
from functools import wraps
from os import environ
import resource

Expand Down Expand Up @@ -54,8 +53,20 @@ class TrackAddedMemoryAllocation:
other_call()
result = mb.addedmem_mb()

Attributes
----------
RESULT_MINIMUM_MB : float
The smallest result that should ever be returned, in Mb. Results
fluctuate from run to run (usually within 1Mb) so if a result is
sufficiently small this noise will produce a before-after ratio over
AVD's detection threshold and be treated as 'signal'. Results
smaller than this value will therefore be returned as equal to this
value, ensuring fractionally small noise / no noise at all.

"""

RESULT_MINIMUM_MB = 5.0

@staticmethod
def process_resident_memory_mb():
return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / 1024.0
Expand All @@ -69,48 +80,32 @@ def __exit__(self, *_):

def addedmem_mb(self):
"""Return measured memory growth, in Mb."""
return self.mb_after - self.mb_before
result = self.mb_after - self.mb_before
# Small results are too vulnerable to noise being interpreted as signal.
result = max(self.RESULT_MINIMUM_MB, result)
return result

@staticmethod
def decorator(changed_params: list = None):
def decorator(decorated_func):
"""
Decorates this benchmark to track growth in resident memory during execution.

Intended for use on ASV ``track_`` benchmarks. Applies the
:class:`TrackAddedMemoryAllocation` context manager to the benchmark
code, sets the benchmark ``unit`` attribute to ``Mb``. Optionally
replaces the benchmark ``params`` attribute with ``changed_params`` -
useful to avoid testing very small memory volumes, where the results
are vulnerable to noise.

Parameters
----------
changed_params : list
Replace the benchmark's ``params`` attribute with this list.
code, sets the benchmark ``unit`` attribute to ``Mb``.

"""
if changed_params:
# Must make a copy for re-use safety!
_changed_params = list(changed_params)
else:
_changed_params = None

def _inner_decorator(decorated_func):
@wraps(decorated_func)
def _inner_func(*args, **kwargs):
assert decorated_func.__name__[:6] == "track_"
# Run the decorated benchmark within the added memory context manager.
with TrackAddedMemoryAllocation() as mb:
decorated_func(*args, **kwargs)
return mb.addedmem_mb()

if _changed_params:
# Replace the params if replacement provided.
_inner_func.params = _changed_params
_inner_func.unit = "Mb"
return _inner_func

return _inner_decorator

def _wrapper(*args, **kwargs):
assert decorated_func.__name__[:6] == "track_"
# Run the decorated benchmark within the added memory context
# manager.
with TrackAddedMemoryAllocation() as mb:
decorated_func(*args, **kwargs)
return mb.addedmem_mb()

decorated_func.unit = "Mb"
return _wrapper


def on_demand_benchmark(benchmark_object):
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/benchmarks/cperf/save.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ def _save_data(self, cube):
def time_save_data_netcdf(self, data_type):
self._save_data(self.cube)

@TrackAddedMemoryAllocation.decorator()
@TrackAddedMemoryAllocation.decorator
def track_addedmem_save_data_netcdf(self, data_type):
self._save_data(self.cube)
10 changes: 4 additions & 6 deletions benchmarks/benchmarks/experimental/ugrid/regions_combine.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ class MixinCombineRegions:
# operations on cubesphere-like test data.
params = [4, 500]
param_names = ["cubesphere-N"]
# For use on 'track_addedmem_..' type benchmarks - result is too noisy.
no_small_params = params[1:]

def _parametrised_cache_filename(self, n_cubesphere, content_name):
return f"cube_C{n_cubesphere}_{content_name}.nc"
Expand Down Expand Up @@ -190,7 +188,7 @@ def setup(self, n_cubesphere):
def time_create_combined_cube(self, n_cubesphere):
self.recombine()

@TrackAddedMemoryAllocation.decorator(MixinCombineRegions.no_small_params)
@TrackAddedMemoryAllocation.decorator
def track_addedmem_create_combined_cube(self, n_cubesphere):
self.recombine()

Expand All @@ -203,7 +201,7 @@ class CombineRegionsComputeRealData(MixinCombineRegions):
def time_compute_data(self, n_cubesphere):
_ = self.recombined_cube.data

@TrackAddedMemoryAllocation.decorator(MixinCombineRegions.no_small_params)
@TrackAddedMemoryAllocation.decorator
def track_addedmem_compute_data(self, n_cubesphere):
_ = self.recombined_cube.data

Expand All @@ -220,7 +218,7 @@ def time_save(self, n_cubesphere):
# Save to disk, which must compute data + stream it to file.
save(self.recombined_cube, "tmp.nc")

@TrackAddedMemoryAllocation.decorator(MixinCombineRegions.no_small_params)
@TrackAddedMemoryAllocation.decorator
def track_addedmem_save(self, n_cubesphere):
save(self.recombined_cube, "tmp.nc")

Expand Down Expand Up @@ -248,6 +246,6 @@ def time_stream_file2file(self, n_cubesphere):
# Save to disk, which must compute data + stream it to file.
save(self.recombined_cube, "tmp.nc")

@TrackAddedMemoryAllocation.decorator(MixinCombineRegions.no_small_params)
@TrackAddedMemoryAllocation.decorator
def track_addedmem_stream_file2file(self, n_cubesphere):
save(self.recombined_cube, "tmp.nc")
4 changes: 1 addition & 3 deletions benchmarks/benchmarks/save.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
class NetcdfSave:
params = [[1, 600], [False, True]]
param_names = ["cubesphere-N", "is_unstructured"]
# For use on 'track_addedmem_..' type benchmarks - result is too noisy.
no_small_params = [[600], [True]]

def setup(self, n_cubesphere, is_unstructured):
self.cube = make_cube_like_2d_cubesphere(
Expand All @@ -50,7 +48,7 @@ def time_netcdf_save_mesh(self, n_cubesphere, is_unstructured):
if is_unstructured:
self._save_mesh(self.cube)

@TrackAddedMemoryAllocation.decorator(no_small_params)
@TrackAddedMemoryAllocation.decorator
def track_addedmem_netcdf_save(self, n_cubesphere, is_unstructured):
# Don't need to copy the cube here since track_ benchmarks don't
# do repeats between self.setup() calls.
Expand Down
8 changes: 4 additions & 4 deletions benchmarks/benchmarks/sperf/combine_regions.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ def setup(
def time_create_combined_cube(self, n_cubesphere):
self.recombine()

@TrackAddedMemoryAllocation.decorator()
@TrackAddedMemoryAllocation.decorator
def track_addedmem_create_combined_cube(self, n_cubesphere):
self.recombine()

Expand All @@ -206,7 +206,7 @@ class ComputeRealData(Mixin):
def time_compute_data(self, n_cubesphere):
_ = self.recombined_cube.data

@TrackAddedMemoryAllocation.decorator()
@TrackAddedMemoryAllocation.decorator
def track_addedmem_compute_data(self, n_cubesphere):
_ = self.recombined_cube.data

Expand All @@ -224,7 +224,7 @@ def time_save(self, n_cubesphere):
# Save to disk, which must compute data + stream it to file.
self.save_recombined_cube()

@TrackAddedMemoryAllocation.decorator()
@TrackAddedMemoryAllocation.decorator
def track_addedmem_save(self, n_cubesphere):
self.save_recombined_cube()

Expand Down Expand Up @@ -252,6 +252,6 @@ def time_stream_file2file(self, n_cubesphere):
# Save to disk, which must compute data + stream it to file.
self.save_recombined_cube()

@TrackAddedMemoryAllocation.decorator()
@TrackAddedMemoryAllocation.decorator
def track_addedmem_stream_file2file(self, n_cubesphere):
self.save_recombined_cube()
2 changes: 1 addition & 1 deletion benchmarks/benchmarks/sperf/save.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def _save_mesh(self, cube):
def time_save_cube(self, n_cubesphere, is_unstructured):
self._save_cube(self.cube)

@TrackAddedMemoryAllocation.decorator()
@TrackAddedMemoryAllocation.decorator
def track_addedmem_save_cube(self, n_cubesphere, is_unstructured):
self._save_cube(self.cube)

Expand Down