Skip to content

Cached benchmark file I/O - #1700

Draft
cmdupuis3 wants to merge 22 commits into
UXARRAY:mainfrom
cmdupuis3:cmd/bench_io
Draft

Cached benchmark file I/O#1700
cmdupuis3 wants to merge 22 commits into
UXARRAY:mainfrom
cmdupuis3:cmd/bench_io

Conversation

@cmdupuis3

@cmdupuis3 cmdupuis3 commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

Closes #1698

Overview

This PR is a large-scale overhaul of the benchmarks to support single-loads of files per benchmark suite.

Currently, the ASV benchmark suite runs a new process per benchmark, requiring full-scale loads of files for every single benchmark. There are a limited number of files that are actually used to benchmark, so we end up loading many files dozens of times, running up wallclock time on the benchmark suite as a whole. This PR instead has a unified approach, where a parent process is launched for the whole benchmark suite, uncached files are retrieved into /uxarray/benchmarks/_io_cache/, and benchmarks are spawned on forked processes that inherit visibility into the file cache and some other properties.

Simultaneously, this reorganization of file I/O will help to expand the scope of what most non-I/O benchmarks are able to test, since some of them were artificially restricted to smaller grids. That raises another question about how many benchmarks really need to be run at every resolution, but I think that's out of scope for this PR, since it would alter the actual benchmark suite, rather than just changing how they are run.

General CI runs should see a wallclock improvement for whole benchmark suites. CI benchmark runs are showing improvements of about 19 minutes so far (38min -> 19min). Runs on HPC can expect larger improvements. Larger benchmark suites will benefit more from cached file I/O, while benchmarks run individually won't see much improvement.

Other general speed improvements:

  1. Test processes forking from warm-cache parent process
  2. Async dispatch of tests on file arrival, so large files don't stall tests of smaller files.
  3. Sample generation on parent process for reuse in forked processes; sacrifices a bit of robustness for significant speed gains in geometry routines.

This PR has merged in PR #1708 already, since it is a precondition for the optimizations here to be thread-safe.

PR Checklist

General

  • An issue is created and linked
  • Added appropriate labels (if your uxarray repo permissions allow it)
  • Filled out Overview and Expected Usage (if applicable) sections

Testing & Benchmarking

  • Adequate tests are created if there is new functionality
  • Tests are not too basic (such as simply calling a function and nothing else)
  • Tests cover all major paths in your new functions
  • If this PR could affect performance, ran ASV benchmarks and confirmed they show expected behavior (add a new benchmark if necessary)

Documentation

  • Docstrings have been added to all new functions
  • Docstrings have been updated with any function changes
  • Internal (private) function names start with an underscore (_)

AI Disclosure

AI Usage: Claude Opus 5

  • I take responsibility for all AI-generated content in my PR.
  • I have tested all AI-generated content in my PR.

@cmdupuis3 cmdupuis3 added scalability Related to scalability & performance efforts benchmarking Related to benchmarks, memory usage, and/or time profiling labels Aug 21, 2026
@cmdupuis3 cmdupuis3 self-assigned this Aug 21, 2026
@cmdupuis3 cmdupuis3 added the run-benchmark Run ASV benchmark workflow label Aug 21, 2026
@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [d013907] After [9915b68] Ratio Benchmark (Parameter)
- 469M 337M 0.72 face_bounds.FaceBoundsColdStartRss.track_peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
- 469M 367M 0.78 face_bounds.FaceBoundsColdStartRss.track_peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
- 469M 339M 0.72 face_bounds.FaceBoundsColdStartRss.track_peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
- 469M 339M 0.72 face_bounds.FaceBoundsColdStartRss.track_peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
- 2.87±0ms 2.58±0.01ms 0.9 geometry_samebody.SameBodyConstLat.time_accux_dispatch
- 11.4±0.01s 817±3ms 0.07 import.Imports.timeraw_import_uxarray
- 469M 293M 0.63 import.Imports.track_peakmem_import_uxarray
- 469M 357M 0.76 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('120km', 1)
- 469M 357M 0.76 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('120km', 2)
- 469M 357M 0.76 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('120km', 4)
- 469M 340M 0.72 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('480km', 1)
- 469M 340M 0.73 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('480km', 2)
- 469M 340M 0.73 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('480km', 4)
- 469M 357M 0.76 mpas_ocean.GradientColdStartRss.track_peakmem_gradient('120km')
- 469M 333M 0.71 mpas_ocean.GradientColdStartRss.track_peakmem_gradient('480km')
- 14.4±0.2ms 12.2±0.08ms 0.85 mpas_ocean.NeighborhoodDask.time_mean('480km', 'grid_chunks')
- 10.6±0.3ms 8.92±0.1ms 0.84 mpas_ocean.NeighborhoodDask.time_mean('480km', 'time_chunks')
- 469M 359M 0.77 mpas_ocean.ZonalAveragePeakMem.track_peakmem_zonal_average('120km')
- 469M 342M 0.73 mpas_ocean.ZonalAveragePeakMem.track_peakmem_zonal_average('480km')

Benchmarks that have stayed the same:

Change Before [d013907] After [9915b68] Ratio Benchmark (Parameter)
195±1ms 193±1ms 0.99 bench_connectivity.Connectivity.time_edge_face('120km')
11.6±0.05ms 11.5±0.06ms 0.99 bench_connectivity.Connectivity.time_edge_face('480km')
193±1ms 190±0.4ms 0.98 bench_connectivity.Connectivity.time_edge_node('120km')
10.8±0.1ms 10.6±0.08ms 0.99 bench_connectivity.Connectivity.time_edge_node('480km')
191±1ms 189±0.4ms 0.99 bench_connectivity.Connectivity.time_face_edge('120km')
11.0±0.02ms 10.8±0.07ms 0.99 bench_connectivity.Connectivity.time_face_edge('480km')
857±6ms 869±8ms 1.01 bench_connectivity.Connectivity.time_face_face('120km')
53.7±0.3ms 52.9±0.2ms 0.98 bench_connectivity.Connectivity.time_face_face('480km')
54.2±0.5μs 54.4±0.7μs 1.01 bench_connectivity.Connectivity.time_face_node('120km')
53.9±1μs 52.3±0.4μs 0.97 bench_connectivity.Connectivity.time_face_node('480km')
416±20μs 382±10μs 0.92 bench_connectivity.Connectivity.time_n_nodes_per_face('120km')
311±10μs 306±9μs 0.98 bench_connectivity.Connectivity.time_n_nodes_per_face('480km')
194±0.8ms 193±1ms 0.99 bench_connectivity.Connectivity.time_node_edge('120km')
11.0±0.06ms 10.8±0.09ms 0.98 bench_connectivity.Connectivity.time_node_edge('480km')
74.7±0.5ms 75.8±0.6ms 1.01 bench_connectivity.Connectivity.time_node_face('120km')
5.11±0.03ms 4.96±0.01ms 0.97 bench_connectivity.Connectivity.time_node_face('480km')
7.63±0.1ms 7.55±0.08ms 0.99 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
2.53±0.03ms 2.48±0.01ms 0.98 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
10.1±10s 9.54±10ms ~0.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
1.54±0.01ms 1.54±0.03ms 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
57.3k 57.3k 1.00 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
12.3k 12.3k 1.00 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
123k 123k 1.00 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
128 128 1.00 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.27M 1.27M 1.00 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
50.1k 50.1k 1.00 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
1.48M 1.48M 1.00 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
712 712 1.00 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.95M 1.95M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
1.94M 1.94M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.1M 2.11M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
35.6k 35.5k 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.23±0.03μs 1.22±0.04μs 0.99 geometry_kernels.AccucrossKernels.time_accucross
2.79±0.03μs 2.75±0.02μs 0.99 geometry_kernels.AccucrossKernels.time_accucross_pair
446±10ns 451±10ns 1.01 geometry_kernels.EFTPrimitives.time_acc_sqrt_re
436±10ns 446±20ns 1.02 geometry_kernels.EFTPrimitives.time_diff_of_products
386±10ns 401±10ns 1.04 geometry_kernels.EFTPrimitives.time_two_prod
390±9ns 391±9ns 1.00 geometry_kernels.EFTPrimitives.time_two_sum
1.63±0.08μs 1.57±0.04μs 0.97 geometry_kernels.GCAConstLatIntersection.time_accux_constlat_kernel
1.18±0.05μs 1.19±0.02μs 1.01 geometry_kernels.GCAConstLatIntersection.time_gca_const_lat_intersection
2.03±0.05μs 2.01±0.06μs 0.99 geometry_kernels.GCAConstLatIntersection.time_try_gca_const_lat_intersection
3.67±0.03μs 3.67±0.02μs 1.00 geometry_kernels.GCAGCAIntersection.time_accux_gca_kernel
1.36±0.02μs 1.33±0.02μs 0.98 geometry_kernels.GCAGCAIntersection.time_gca_gca_intersection
3.80±0.04μs 3.79±0.03μs 1.00 geometry_kernels.GCAGCAIntersection.time_try_gca_gca_intersection
52.5±0.6μs 51.2±0.9μs 0.98 geometry_kernels.OrientPredicates.time_on_minor_arc
53.9±0.6μs 50.6±0.3μs 0.94 geometry_kernels.OrientPredicates.time_orient3d_on_sphere
1.17±0.01ms 1.16±0ms 1.00 geometry_samebody.SameBodyConstLat.time_accux_kernel
1.83±0.09ms 1.72±0ms 0.94 geometry_samebody.SameBodyConstLat.time_fp64_dispatch
143±0.2μs 143±0.7μs 1.00 geometry_samebody.SameBodyConstLat.time_fp64_kernel
failed failed n/a geometry_samebody_gcagca.SameBodyGcaGca.time_accux_dispatch
failed failed n/a geometry_samebody_gcagca.SameBodyGcaGca.time_accux_kernel
failed failed n/a geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_dispatch
failed failed n/a geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_kernel
2.53±0.06ms 2.49±0.01ms 0.98 mpas_ocean.CheckNorm.time_check_norm('120km')
2.07±0.01ms 2.11±0.05ms 1.02 mpas_ocean.CheckNorm.time_check_norm('480km')
823±10ms 836±10ms 1.02 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
52.0±0.4ms 52.6±0.3ms 1.01 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
614±10μs 607±8μs 0.99 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
561±10μs 554±10μs 0.99 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
5.37±0.02ms 5.38±0.1ms 1.00 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('120km')
3.90±0.02ms 3.82±0.01ms 0.98 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('480km')
94.6±0.5ms 94.3±0.2ms 1.00 mpas_ocean.ConstructFaceLatLon.time_welzl('120km')
9.78±0.08ms 9.23±0.4ms 0.94 mpas_ocean.ConstructFaceLatLon.time_welzl('480km')
18.3±0.03ms 18.3±0.03ms 1.00 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
959±20μs 956±9μs 1.00 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
10.9±0.02ms 10.8±0.04ms 1.00 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
671±20μs 636±20μs 0.95 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
586±3ms 578±3ms 0.99 mpas_ocean.CrossSections.time_const_lat('120km', 1)
299±5ms 291±0.2ms 0.97 mpas_ocean.CrossSections.time_const_lat('120km', 2)
152±1ms 152±2ms 0.99 mpas_ocean.CrossSections.time_const_lat('120km', 4)
539±5ms 547±7ms 1.01 mpas_ocean.CrossSections.time_const_lat('480km', 1)
279±0.5ms 265±1ms 0.95 mpas_ocean.CrossSections.time_const_lat('480km', 2)
140±0.6ms 136±1ms 0.97 mpas_ocean.CrossSections.time_const_lat('480km', 4)
24.3±0.02ms 24.0±0.04ms 0.99 mpas_ocean.DualMesh.time_dual_mesh_construction('120km')
2.86±0.02ms 2.81±0.02ms 0.98 mpas_ocean.DualMesh.time_dual_mesh_construction('480km')
61.6±0.6ms 61.8±0.8ms 1.00 mpas_ocean.FaceAreas.time_face_areas('120km')
4.99±5s 7.45±7ms ~0.00 mpas_ocean.FaceAreas.time_face_areas('480km')
229k 229k 1.00 mpas_ocean.FaceAreas.track_nbytes_face_areas('120km')
14.3k 14.3k 1.00 mpas_ocean.FaceAreas.track_nbytes_face_areas('480km')
2.12M 2.13M 1.00 mpas_ocean.FaceAreas.track_peakmem_face_areas('120km')
810k 809k 1.00 mpas_ocean.FaceAreas.track_peakmem_face_areas('480km')
927±9ms 943±4ms 1.02 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
49.5±0.5ms 51.7±0.7ms 1.04 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
83.7±0.7ms 84.8±2ms 1.01 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.02±0.3ms 4.93±0.1ms 0.98 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
175±1ms 174±0.1ms 0.99 mpas_ocean.Gradient.time_gradient('120km')
12.0±0.05ms 11.9±0.03ms 1.00 mpas_ocean.Gradient.time_gradient('480km')
457k 457k 1.00 mpas_ocean.Gradient.track_nbytes_gradient('120km')
28.7k 28.7k 1.00 mpas_ocean.Gradient.track_nbytes_gradient('480km')
4.86M 4.86M 1.00 mpas_ocean.Gradient.track_peakmem_gradient('120km')
313k 313k 1.00 mpas_ocean.Gradient.track_peakmem_gradient('480km')
279±10μs 274±8μs 0.98 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
164±10μs 150±10μs 0.91 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
210±10μs 202±8μs 0.96 mpas_ocean.Integrate.time_integrate('120km')
190±3μs 186±2μs 0.98 mpas_ocean.Integrate.time_integrate('480km')
18.4M 18.4M 1.00 mpas_ocean.Integrate.track_nbytes_integrate('120km')
1.2M 1.2M 1.00 mpas_ocean.Integrate.track_nbytes_integrate('480km')
178±1ms 177±3ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
178±1ms 182±3ms 1.02 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
180±4ms 177±2ms 0.98 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
13.3±0.2ms 12.8±0.04ms 0.96 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
12.9±0.06ms 12.8±0.03ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
12.8±0.05ms 12.8±0.04ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
236±0.8ms 237±1ms 1.00 mpas_ocean.NeighborhoodBuild.time_build('120km', 1.0)
1.26±0s 1.26±0.01s 1.00 mpas_ocean.NeighborhoodBuild.time_build('120km', 15.0)
487±0.8ms 488±1ms 1.00 mpas_ocean.NeighborhoodBuild.time_build('120km', 5.0)
12.8±0.01ms 12.9±0.02ms 1.00 mpas_ocean.NeighborhoodBuild.time_build('480km', 1.0)
24.6±0.2ms 24.5±0.2ms 1.00 mpas_ocean.NeighborhoodBuild.time_build('480km', 15.0)
15.9±0.04ms 16.0±0.1ms 1.01 mpas_ocean.NeighborhoodBuild.time_build('480km', 5.0)
233±2ms 236±1ms 1.01 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 1.0)
1.25±0s 1.24±0s 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 15.0)
485±4ms 485±3ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 5.0)
12.5±0.4ms 12.6±0.07ms 1.01 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 1.0)
24.0±0.05ms 24.0±0.1ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 15.0)
15.7±0.08ms 15.6±0.05ms 0.99 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 5.0)
1.19 1.19 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('120km', 1.0)
612.76 612.76 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('120km', 15.0)
74.17 74.17 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('120km', 5.0)
1.0 1.0 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('480km', 1.0)
37.29 37.29 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('480km', 15.0)
6.57 6.57 1.00 mpas_ocean.NeighborhoodBuild.track_mean_neighbors('480km', 5.0)
728k 728k 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('120km', 1.0)
141M 141M 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('120km', 15.0)
17.4M 17.4M 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('120km', 5.0)
43k 43k 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('480km', 1.0)
563k 563k 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('480km', 15.0)
123k 123k 1.00 mpas_ocean.NeighborhoodBuild.track_nbytes_neighbors('480km', 5.0)
5.72M 5.72M 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('120km', 1.0)
145M 145M 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('120km', 15.0)
21.5M 21.5M 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('120km', 5.0)
362k 362k 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('480km', 1.0)
825k 825k 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('480km', 15.0)
384k 384k 1.00 mpas_ocean.NeighborhoodBuild.track_peakmem_build('480km', 5.0)
47.7±0.4ms 44.7±0.4ms 0.94 mpas_ocean.NeighborhoodDask.time_mean('120km', 'grid_chunks')
22.6±0.1ms 22.6±0.2ms 1.00 mpas_ocean.NeighborhoodDask.time_mean('120km', 'numpy')
43.2±0.5ms 40.4±0.5ms 0.94 mpas_ocean.NeighborhoodDask.time_mean('120km', 'time_chunks')
695±10μs 716±30μs 1.03 mpas_ocean.NeighborhoodDask.time_mean('480km', 'numpy')
5.84M 5.82M 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('120km', 'grid_chunks')
2.75M 2.75M 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('120km', 'numpy')
5.69M 5.67M 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('120km', 'time_chunks')
177k 177k 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'numpy')
544k 524k 0.96 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'time_chunks')
12.2±0.01s 12.3±0.03s 1.01 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('120km', 'mean')
12.9±0.01s 12.9±0.02s 1.00 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('120km', 'median')
219±0.6ms 220±2ms 1.00 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('480km', 'mean')
225±2ms 223±0.4ms 0.99 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('480km', 'median')
1.30±0s 1.30±0s 1.00 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('120km', 'mean')
1.50±0s 1.50±0.01s 1.00 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('120km', 'median')
24.9±0.03ms 24.8±0.02ms 1.00 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('480km', 'mean')
26.2±0.04ms 26.0±0.07ms 0.99 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('480km', 'median')
38.0±0.3ms 38.3±0.1ms 1.01 mpas_ocean.NeighborhoodReduce.time_reduce('120km', 'mean')
234±1ms 232±0.6ms 0.99 mpas_ocean.NeighborhoodReduce.time_reduce('120km', 'median')
437±10μs 428±10μs 0.98 mpas_ocean.NeighborhoodReduce.time_reduce('480km', 'mean')
1.67±0.01ms 1.62±0.01ms 0.97 mpas_ocean.NeighborhoodReduce.time_reduce('480km', 'median')
240k 239k 1.00 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('120km', 'mean')
246k 245k 1.00 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('120km', 'median')
20k 19.3k 0.97 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('480km', 'mean')
20.5k 19.8k 0.97 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('480km', 'median')
421±9μs 407±5μs 0.97 mpas_ocean.PointInPolygon.time_face_search_lonlat('120km')
419±10μs 400±4μs 0.95 mpas_ocean.PointInPolygon.time_face_search_lonlat('480km')
385±10μs 397±7μs 1.03 mpas_ocean.PointInPolygon.time_face_search_xyz('120km')
392±10μs 381±10μs 0.97 mpas_ocean.PointInPolygon.time_face_search_xyz('480km')
128±0.2ms 127±1ms 1.00 mpas_ocean.RemapDownsample.time_bilinear_remapping
16.9±0.1ms 16.9±0.03ms 1.00 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
15.4±0.05ms 15.5±0.2ms 1.01 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
1.43±0.02s 1.43±0s 1.01 mpas_ocean.RemapUpsample.time_bilinear_remapping
26.7±0.2ms 26.0±0.4ms 0.97 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
12.1±0.2ms 11.9±0.3ms 0.98 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
8.56±0.2ms 8.52±0.1ms 0.99 mpas_ocean.ZonalAverage.time_zonal_average('120km')
5.44±0.06ms 5.25±0.1ms 0.97 mpas_ocean.ZonalAverage.time_zonal_average('480km')
6.77±0.03ms 6.66±0.04ms 0.98 quad_hexagon.QuadHexagon.time_open_dataset
5.79±0.03ms 5.69±0.05ms 0.98 quad_hexagon.QuadHexagon.time_open_grid
408 408 1.00 quad_hexagon.QuadHexagon.track_nbytes_open_dataset
392 392 1.00 quad_hexagon.QuadHexagon.track_nbytes_open_grid
73.6k 73.6k 1.00 quad_hexagon.QuadHexagon.track_peakmem_open_dataset
72.7k 72.7k 1.00 quad_hexagon.QuadHexagon.track_peakmem_open_grid

Benchmarks that have got worse:

Change Before [d013907] After [9915b68] Ratio Benchmark (Parameter)
+ 676k 759k 1.12 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'grid_chunks')

@cmdupuis3

cmdupuis3 commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator Author

In timing the bench_connectivity.Connectivity suite on derecho, I'm finding that with this PR and a full _io_cache, the whole suite takes almost exactly an hour. On the main branch without this PR, just bench_connectivity.Connectivity.time_edge_face and time_face_edge take about 45 minutes each. The Connectivity suite has six tests in total, so the IO cache is actually not being used as extensively as it would be for a full benchmark suite.

asv preimports the benchmark suite before it runs any setup_cache
(asv/runner.py, spawner.preimport() ahead of the run loop), so on a cold
cache bench_connectivity's import-time preload_topologies is what fills
it -- serially, in the forkserver parent, before a single benchmark
starts. CachedFixtures.setup_cache then finds everything already built,
and prime(workers=...) never runs on the path it was written for.

Filling it from the CLI first puts those reads back in the parallel
prime. Worth a second or two on the GitHub runners, which only see the
oQU grids; worth rather more on a machine that can reach the four
dyamond grids on campaign storage.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

benchmarking Related to benchmarks, memory usage, and/or time profiling run-benchmark Run ASV benchmark workflow scalability Related to scalability & performance efforts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Need a holistic approach to file I/O for benchmarks

1 participant