From d853a5644117b6f8657aedb0b74a87dac470293e Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Mon, 20 May 2024 09:06:13 +0100 Subject: [PATCH 1/5] add memory benchmarks --- benchmarks/benchmarks/merge_concat.py | 9 +++++++++ benchmarks/benchmarks/regridding.py | 27 +++++++++++++++++++++++++++ benchmarks/benchmarks/stats.py | 17 ++++++++++++++++- benchmarks/benchmarks/trajectory.py | 18 ++++++++++++++++++ 4 files changed, 70 insertions(+), 1 deletion(-) diff --git a/benchmarks/benchmarks/merge_concat.py b/benchmarks/benchmarks/merge_concat.py index 315d90f5757..a5c8ed7205d 100644 --- a/benchmarks/benchmarks/merge_concat.py +++ b/benchmarks/benchmarks/merge_concat.py @@ -8,6 +8,7 @@ from iris.cube import CubeList +from . import TrackAddedMemoryAllocation from .generate_data.stock import realistic_4d_w_everything @@ -33,6 +34,10 @@ def setup(self): def time_merge(self): _ = self.cube_list.merge_cube() + @TrackAddedMemoryAllocation.decorator + def track_mem_merge(self): + _ = self.cube_list.merge_cube() + class Concatenate: # TODO: Improve coverage. @@ -50,3 +55,7 @@ def setup(self): def time_concatenate(self): _ = self.cube_list.concatenate_cube() + + @TrackAddedMemoryAllocation.decorator + def track_mem_merge(self): + _ = self.cube_list.concatenate_cube() diff --git a/benchmarks/benchmarks/regridding.py b/benchmarks/benchmarks/regridding.py index b311c947176..a0f2359c59e 100644 --- a/benchmarks/benchmarks/regridding.py +++ b/benchmarks/benchmarks/regridding.py @@ -14,6 +14,8 @@ from iris.analysis import AreaWeighted, PointInCell from iris.coords import AuxCoord +from . import TrackAddedMemoryAllocation + class HorizontalChunkedRegridding: def setup(self) -> None: @@ -52,6 +54,23 @@ def time_regrid_area_w_new_grid(self) -> None: out.data + @TrackAddedMemoryAllocation.decorator + def track_mem_regrid_area_w(self) -> None: + for _ in range(3): + # Regrid the chunked cube + out = self.cube.regrid(self.template_cube, self.scheme_area_w) + # Realise data + out.data + + + @TrackAddedMemoryAllocation.decorator + def track_mem_regrid_area_w_new_grid(self) -> None: + for _ in range(3): + # Regrid the chunked cube + out = self.chunked_cube.regrid(self.template_cube, self.scheme_area_w) + # Realise data + out.data + class CurvilinearRegridding: def setup(self) -> None: # Prepare a cube and a template @@ -93,3 +112,11 @@ def time_regrid_pic(self) -> None: out = self.cube.regrid(self.template_cube, self.scheme_pic) # Realise the data out.data + + @TrackAddedMemoryAllocation.decorator + def track_mem_regrid_pic(self) -> None: + for _ in range(3): + # Regrid the cube onto the template. + out = self.cube.regrid(self.template_cube, self.scheme_pic) + # Realise the data + out.data diff --git a/benchmarks/benchmarks/stats.py b/benchmarks/benchmarks/stats.py index 0530431900a..c66349e64fc 100644 --- a/benchmarks/benchmarks/stats.py +++ b/benchmarks/benchmarks/stats.py @@ -8,6 +8,8 @@ from iris.analysis.stats import pearsonr import iris.tests +from . import TrackAddedMemoryAllocation + class PearsonR: def setup(self): @@ -30,9 +32,22 @@ def setup(self): def time_real(self): pearsonr(self.cube_a, self.cube_b, weights=self.weights) + @TrackAddedMemoryAllocation.decorator + def time_real(self): + for _ in range(3): + pearsonr(self.cube_a, self.cube_b, weights=self.weights) + def time_lazy(self): for cube in self.cube_a, self.cube_b: cube.data = cube.lazy_data() result = pearsonr(self.cube_a, self.cube_b, weights=self.weights) - result.data + + @TrackAddedMemoryAllocation.decorator + def time_lazy(self): + for _ in range(3): + for cube in self.cube_a, self.cube_b: + cube.data = cube.lazy_data() + + result = pearsonr(self.cube_a, self.cube_b, weights=self.weights) + result.data diff --git a/benchmarks/benchmarks/trajectory.py b/benchmarks/benchmarks/trajectory.py index ec2958b6a8e..90f9cb3963a 100644 --- a/benchmarks/benchmarks/trajectory.py +++ b/benchmarks/benchmarks/trajectory.py @@ -13,6 +13,8 @@ import iris from iris.analysis.trajectory import interpolate +from . import TrackAddedMemoryAllocation + class TrajectoryInterpolation: def setup(self) -> None: @@ -33,8 +35,24 @@ def time_trajectory_linear(self) -> None: # Realise the data out_cube.data + @TrackAddedMemoryAllocation.decorator + def track_trajectory_linear(self) -> None: + for _ in range(3): + # Regrid the cube onto the template. + out_cube = interpolate(self.cube, self.sample_points, method="linear") + # Realise the data + out_cube.data + def time_trajectory_nearest(self) -> None: # Regrid the cube onto the template. out_cube = interpolate(self.cube, self.sample_points, method="nearest") # Realise the data out_cube.data + + @TrackAddedMemoryAllocation.decorator + def track_trajectory_nearest(self) -> None: + for _ in range(3): + # Regrid the cube onto the template. + out_cube = interpolate(self.cube, self.sample_points, method="nearest") + # Realise the data + out_cube.data From 1d30f4e9a391eb0e46fa8f97cd34968d51e5210f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 20 May 2024 08:13:15 +0000 Subject: [PATCH 2/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- benchmarks/benchmarks/regridding.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/benchmarks/benchmarks/regridding.py b/benchmarks/benchmarks/regridding.py index a0f2359c59e..c83a7c09c58 100644 --- a/benchmarks/benchmarks/regridding.py +++ b/benchmarks/benchmarks/regridding.py @@ -53,7 +53,6 @@ def time_regrid_area_w_new_grid(self) -> None: # Realise data out.data - @TrackAddedMemoryAllocation.decorator def track_mem_regrid_area_w(self) -> None: for _ in range(3): @@ -62,7 +61,6 @@ def track_mem_regrid_area_w(self) -> None: # Realise data out.data - @TrackAddedMemoryAllocation.decorator def track_mem_regrid_area_w_new_grid(self) -> None: for _ in range(3): @@ -71,6 +69,7 @@ def track_mem_regrid_area_w_new_grid(self) -> None: # Realise data out.data + class CurvilinearRegridding: def setup(self) -> None: # Prepare a cube and a template From cb73485611937c6a818e52a2a6edf47d5bc0bdbe Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Mon, 20 May 2024 10:20:59 +0100 Subject: [PATCH 3/5] fix memory benchmarks --- benchmarks/benchmarks/stats.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benchmarks/benchmarks/stats.py b/benchmarks/benchmarks/stats.py index c66349e64fc..f1b394c6620 100644 --- a/benchmarks/benchmarks/stats.py +++ b/benchmarks/benchmarks/stats.py @@ -33,7 +33,7 @@ def time_real(self): pearsonr(self.cube_a, self.cube_b, weights=self.weights) @TrackAddedMemoryAllocation.decorator - def time_real(self): + def track_real(self): for _ in range(3): pearsonr(self.cube_a, self.cube_b, weights=self.weights) @@ -44,7 +44,7 @@ def time_lazy(self): result = pearsonr(self.cube_a, self.cube_b, weights=self.weights) @TrackAddedMemoryAllocation.decorator - def time_lazy(self): + def track_lazy(self): for _ in range(3): for cube in self.cube_a, self.cube_b: cube.data = cube.lazy_data() From 7a22d5813056a316bb93d152fcdee7ffbabb6783 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Mon, 20 May 2024 11:27:59 +0100 Subject: [PATCH 4/5] generalise benchmark repeats --- benchmarks/benchmarks/__init__.py | 27 ++++++++++++++++++++++ benchmarks/benchmarks/merge_concat.py | 4 ++-- benchmarks/benchmarks/regridding.py | 33 ++++++++++++--------------- benchmarks/benchmarks/stats.py | 14 +++++------- benchmarks/benchmarks/trajectory.py | 22 ++++++++---------- 5 files changed, 60 insertions(+), 40 deletions(-) diff --git a/benchmarks/benchmarks/__init__.py b/benchmarks/benchmarks/__init__.py index 1eccf6478f0..0bbf383f2fe 100644 --- a/benchmarks/benchmarks/__init__.py +++ b/benchmarks/benchmarks/__init__.py @@ -114,6 +114,33 @@ def _wrapper(*args, **kwargs): decorated_func.unit = "Mb" return _wrapper + @staticmethod + def decorator_repeating(repeats=3): + """Benchmark to track growth in resident memory during execution. + + Tracks memory for repeated calls of decorated function. + + Intended for use on ASV ``track_`` benchmarks. Applies the + :class:`TrackAddedMemoryAllocation` context manager to the benchmark + code, sets the benchmark ``unit`` attribute to ``Mb``. + + """ + + def decorator(decorated_func): + def _wrapper(*args, **kwargs): + assert decorated_func.__name__[:6] == "track_" + # Run the decorated benchmark within the added memory context + # manager. + with TrackAddedMemoryAllocation() as mb: + for _ in range(repeats): + decorated_func(*args, **kwargs) + return mb.addedmem_mb() + + decorated_func.unit = "Mb" + return _wrapper + + return decorator + def on_demand_benchmark(benchmark_object): """Disable these benchmark(s) unless ON_DEMAND_BENCHARKS env var is set. diff --git a/benchmarks/benchmarks/merge_concat.py b/benchmarks/benchmarks/merge_concat.py index a5c8ed7205d..1a18f92ce9e 100644 --- a/benchmarks/benchmarks/merge_concat.py +++ b/benchmarks/benchmarks/merge_concat.py @@ -34,7 +34,7 @@ def setup(self): def time_merge(self): _ = self.cube_list.merge_cube() - @TrackAddedMemoryAllocation.decorator + @TrackAddedMemoryAllocation.decorator_repeating() def track_mem_merge(self): _ = self.cube_list.merge_cube() @@ -56,6 +56,6 @@ def setup(self): def time_concatenate(self): _ = self.cube_list.concatenate_cube() - @TrackAddedMemoryAllocation.decorator + @TrackAddedMemoryAllocation.decorator_repeating() def track_mem_merge(self): _ = self.cube_list.concatenate_cube() diff --git a/benchmarks/benchmarks/regridding.py b/benchmarks/benchmarks/regridding.py index c83a7c09c58..4cfda05ad17 100644 --- a/benchmarks/benchmarks/regridding.py +++ b/benchmarks/benchmarks/regridding.py @@ -53,21 +53,19 @@ def time_regrid_area_w_new_grid(self) -> None: # Realise data out.data - @TrackAddedMemoryAllocation.decorator + @TrackAddedMemoryAllocation.decorator_repeating() def track_mem_regrid_area_w(self) -> None: - for _ in range(3): - # Regrid the chunked cube - out = self.cube.regrid(self.template_cube, self.scheme_area_w) - # Realise data - out.data + # Regrid the chunked cube + out = self.cube.regrid(self.template_cube, self.scheme_area_w) + # Realise data + out.data - @TrackAddedMemoryAllocation.decorator + @TrackAddedMemoryAllocation.decorator_repeating() def track_mem_regrid_area_w_new_grid(self) -> None: - for _ in range(3): - # Regrid the chunked cube - out = self.chunked_cube.regrid(self.template_cube, self.scheme_area_w) - # Realise data - out.data + # Regrid the chunked cube + out = self.chunked_cube.regrid(self.template_cube, self.scheme_area_w) + # Realise data + out.data class CurvilinearRegridding: @@ -112,10 +110,9 @@ def time_regrid_pic(self) -> None: # Realise the data out.data - @TrackAddedMemoryAllocation.decorator + @TrackAddedMemoryAllocation.decorator_repeating() def track_mem_regrid_pic(self) -> None: - for _ in range(3): - # Regrid the cube onto the template. - out = self.cube.regrid(self.template_cube, self.scheme_pic) - # Realise the data - out.data + # Regrid the cube onto the template. + out = self.cube.regrid(self.template_cube, self.scheme_pic) + # Realise the data + out.data diff --git a/benchmarks/benchmarks/stats.py b/benchmarks/benchmarks/stats.py index f1b394c6620..7307625bdc5 100644 --- a/benchmarks/benchmarks/stats.py +++ b/benchmarks/benchmarks/stats.py @@ -32,10 +32,9 @@ def setup(self): def time_real(self): pearsonr(self.cube_a, self.cube_b, weights=self.weights) - @TrackAddedMemoryAllocation.decorator + @TrackAddedMemoryAllocation.decorator_repeating() def track_real(self): - for _ in range(3): - pearsonr(self.cube_a, self.cube_b, weights=self.weights) + pearsonr(self.cube_a, self.cube_b, weights=self.weights) def time_lazy(self): for cube in self.cube_a, self.cube_b: @@ -43,11 +42,10 @@ def time_lazy(self): result = pearsonr(self.cube_a, self.cube_b, weights=self.weights) - @TrackAddedMemoryAllocation.decorator + @TrackAddedMemoryAllocation.decorator_repeating() def track_lazy(self): - for _ in range(3): - for cube in self.cube_a, self.cube_b: - cube.data = cube.lazy_data() + for cube in self.cube_a, self.cube_b: + cube.data = cube.lazy_data() - result = pearsonr(self.cube_a, self.cube_b, weights=self.weights) + result = pearsonr(self.cube_a, self.cube_b, weights=self.weights) result.data diff --git a/benchmarks/benchmarks/trajectory.py b/benchmarks/benchmarks/trajectory.py index 90f9cb3963a..a31552eb9a8 100644 --- a/benchmarks/benchmarks/trajectory.py +++ b/benchmarks/benchmarks/trajectory.py @@ -35,13 +35,12 @@ def time_trajectory_linear(self) -> None: # Realise the data out_cube.data - @TrackAddedMemoryAllocation.decorator + @TrackAddedMemoryAllocation.decorator_repeating() def track_trajectory_linear(self) -> None: - for _ in range(3): - # Regrid the cube onto the template. - out_cube = interpolate(self.cube, self.sample_points, method="linear") - # Realise the data - out_cube.data + # Regrid the cube onto the template. + out_cube = interpolate(self.cube, self.sample_points, method="linear") + # Realise the data + out_cube.data def time_trajectory_nearest(self) -> None: # Regrid the cube onto the template. @@ -49,10 +48,9 @@ def time_trajectory_nearest(self) -> None: # Realise the data out_cube.data - @TrackAddedMemoryAllocation.decorator + @TrackAddedMemoryAllocation.decorator_repeating() def track_trajectory_nearest(self) -> None: - for _ in range(3): - # Regrid the cube onto the template. - out_cube = interpolate(self.cube, self.sample_points, method="nearest") - # Realise the data - out_cube.data + # Regrid the cube onto the template. + out_cube = interpolate(self.cube, self.sample_points, method="nearest") + # Realise the data + out_cube.data From 2a6991828fb4bda324d6f0233208497f891c6bde Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Mon, 20 May 2024 11:33:10 +0100 Subject: [PATCH 5/5] fix indent --- benchmarks/benchmarks/stats.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/benchmarks/benchmarks/stats.py b/benchmarks/benchmarks/stats.py index 7307625bdc5..1f5262bf4c0 100644 --- a/benchmarks/benchmarks/stats.py +++ b/benchmarks/benchmarks/stats.py @@ -41,6 +41,7 @@ def time_lazy(self): cube.data = cube.lazy_data() result = pearsonr(self.cube_a, self.cube_b, weights=self.weights) + result.data @TrackAddedMemoryAllocation.decorator_repeating() def track_lazy(self): @@ -48,4 +49,4 @@ def track_lazy(self): cube.data = cube.lazy_data() result = pearsonr(self.cube_a, self.cube_b, weights=self.weights) - result.data + result.data