Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
d4cd5c0
Load and save the NOAA GFS sample store
trexfeathers Oct 26, 2026
ea013bb
Load a fixed-length unicode variable from a Zarr store
trexfeathers Oct 26, 2026
f679954
Benchmark saving a cube to Zarr
trexfeathers Oct 26, 2026
680d6c7
Benchmark loading and realising a Zarr store
trexfeathers Oct 26, 2026
2452565
Record PR 7 in the design document
trexfeathers Oct 26, 2026
833a108
Record the preview pull request number
trexfeathers Oct 26, 2026
d2d04bf
Skip the GFS sample tests when the sample is absent
trexfeathers Oct 26, 2026
2decf75
Settle the grid-mapping question, and record the companion issues
trexfeathers Oct 26, 2026
13e191d
Pin the iris-test-data version carrying the Zarr sample
trexfeathers Oct 27, 2026
dadeac3
Record the test-data release that unblocks PR 7's tests
trexfeathers Oct 27, 2026
cbb30a8
Action review: drop the custom skipper, parametrise the save benchmark
trexfeathers Oct 27, 2026
f07bc80
Benchmark a time constraint on Zarr too
trexfeathers Oct 27, 2026
a4948c6
Record the stored unicode fixtures, and why a generated test cannot p…
trexfeathers Oct 27, 2026
d365fc6
Read fixed-length unicode from stored Zarr stores
trexfeathers Oct 27, 2026
a5cbc4b
Say that PR 7 is red, and why that was chosen
trexfeathers Oct 27, 2026
9d2a396
Record the pull request PR 7 was raised as
trexfeathers Oct 27, 2026
e10a0fa
Pin the test-data version carrying the unicode fixtures
trexfeathers Oct 27, 2026
93eaede
Record the release that takes PR 7 green
trexfeathers Oct 27, 2026
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
2 changes: 1 addition & 1 deletion .github/workflows/benchmarks_run.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ jobs:
env:
IRIS_TEST_DATA_LOC_PATH: benchmarks
IRIS_TEST_DATA_PATH: benchmarks/iris-test-data
IRIS_TEST_DATA_VERSION: "2.30"
IRIS_TEST_DATA_VERSION: "2.32"
# Lets us manually bump the cache to rebuild
ENV_CACHE_BUILD: "1"
TEST_DATA_CACHE_BUILD: "2"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:

env:
# NOTE: IRIS_TEST_DATA_VERSION is also set in benchmarks_run.yml
IRIS_TEST_DATA_VERSION: "2.30"
IRIS_TEST_DATA_VERSION: "2.32"
ENV_NAME: "ci-tests"

steps:
Expand Down
19 changes: 14 additions & 5 deletions benchmarks/benchmarks/generate_data/um_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#
# This file is part of Iris and is released under the BSD license.
# See LICENSE in the root of the repository for full licensing details.
"""Generate FF, PP and NetCDF files based on a minimal synthetic FF file.
"""Generate FF, PP, NetCDF and Zarr files based on a minimal synthetic FF file.

NOTE: uses the Mule package, so depends on an environment with Mule installed.
"""
Expand Down Expand Up @@ -122,12 +122,13 @@ def add_field(level_: int, time_step_: int) -> None:
ff_path = save_paths.get("FF", None)
pp_path = save_paths.get("PP", None)
nc_path = save_paths.get("NetCDF", None)
zarr_path = save_paths.get("Zarr", None)

if ff_path:
new_ff.to_file(ff_path)
if pp_path:
fields_to_pp_file(str(pp_path), new_ff.fields)
if nc_path:
if nc_path or zarr_path:
temp_ff_path = None
# Need an Iris Cube from the FF content.
if ff_path:
Expand All @@ -139,12 +140,18 @@ def add_field(level_: int, time_step_: int) -> None:
new_ff.to_file(temp_ff_path.name)
ff_cube = load_cube(temp_ff_path.name)

save_cube(ff_cube, nc_path, zlib=compress)
if nc_path:
save_cube(ff_cube, nc_path, zlib=compress)
if zarr_path:
# Zarr's own spelling of compression. The Zarr saver rejects
# netCDF keywords such as zlib= rather than translating them.
compressors = "auto" if compress else None
save_cube(ff_cube, zarr_path, mode="w", compressors=compressors)
if temp_ff_path:
temp_ff_path.close()


FILE_EXTENSIONS = {"FF": "", "PP": ".pp", "NetCDF": ".nc"}
FILE_EXTENSIONS = {"FF": "", "PP": ".pp", "NetCDF": ".nc", "Zarr": ".zarr"}


def create_um_files(
Expand Down Expand Up @@ -177,7 +184,9 @@ def create_um_files(
for file_type in file_types:
file_ext = FILE_EXTENSIONS[file_type]
save_path = (save_dir / f"{compress}").with_suffix(file_ext)
files_exist = files_exist and save_path.is_file()
# exists() not is_file(): a Zarr store is a directory, so is_file()
# is always False for one and REUSE_DATA would never hold.
files_exist = files_exist and save_path.exists()
save_paths[file_type] = str(save_path)

if not REUSE_DATA or not files_exist:
Expand Down
4 changes: 2 additions & 2 deletions benchmarks/benchmarks/load/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class LoadAndRealise:
params = (
[(50, 50, 2), (1280, 960, 5), (2, 2, 1000)],
[False, True],
["FF", "PP", "NetCDF"],
["FF", "PP", "NetCDF", "Zarr"],
)
param_names = ["xyz", "compressed", "file_format"]

Expand Down Expand Up @@ -78,7 +78,7 @@ def time_stash_constraint(self, _, __, ___) -> None:


class TimeConstraint:
params = ([3, 20], ["FF", "PP", "NetCDF"])
params = ([3, 20], ["FF", "PP", "NetCDF", "Zarr"])
param_names = ["time_dim_len", "file_format"]

def setup_cache(self) -> dict:
Expand Down
31 changes: 22 additions & 9 deletions benchmarks/benchmarks/save.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,48 @@

from .generate_data.ugrid import make_cube_like_2d_cubesphere

#: Target name and save keywords per format. Zarr needs mode="w" because its
#: saver defaults to mode="w-" and raises FileExistsError on a target that
#: exists - and ASV calls a timing function many times between setup() calls.
SAVE_TARGETS = {
"NetCDF": ("tmp.nc", {}),
"Zarr": ("tmp.zarr", {"mode": "w"}),
}

class NetcdfSave:
params = [[50, 600], [False, True]]
param_names = ["cubesphere-N", "is_unstructured"]

def setup(self, n_cubesphere, is_unstructured):
class Save:
params = [[50, 600], [False, True], list(SAVE_TARGETS)]
param_names = ["cubesphere-N", "is_unstructured", "file_format"]

def setup(self, n_cubesphere, is_unstructured, file_format):
self.cube = make_cube_like_2d_cubesphere(
n_cube=n_cubesphere, with_mesh=is_unstructured
)
self.save_target, self.save_kwargs = SAVE_TARGETS[file_format]

def _save_data(self, cube, do_copy=True):
if do_copy:
# Copy the cube, to avoid distorting the results by changing it
# Because we known that older Iris code realises lazy coords
cube = cube.copy()
save(cube, "tmp.nc")
save(cube, self.save_target, **self.save_kwargs)

def _save_mesh(self, cube):
# In this case, we are happy that the mesh is *not* modified
save_mesh(cube.mesh, "mesh.nc")

def time_netcdf_save_cube(self, n_cubesphere, is_unstructured):
def time_save_cube(self, n_cubesphere, is_unstructured, file_format):
self._save_data(self.cube)

def time_netcdf_save_mesh(self, n_cubesphere, is_unstructured):
if is_unstructured:
def time_save_mesh(self, n_cubesphere, is_unstructured, file_format):
# iris.mesh.save_mesh is defined in iris.fileformats.netcdf.saver and
# writes netCDF only, so there is nothing to time for Zarr. A cube
# that *has* a mesh still saves it through time_save_cube, with
# is_unstructured=True.
if is_unstructured and file_format == "NetCDF":
self._save_mesh(self.cube)

def tracemalloc_netcdf_save(self, n_cubesphere, is_unstructured):
def tracemalloc_save(self, n_cubesphere, is_unstructured, file_format):
# Don't need to copy the cube here since track_ benchmarks don't
# do repeats between self.setup() calls.
self._save_data(self.cube, do_copy=False)
Loading
Loading