Skip to content

Cached benchmark file I/O - #1700

Open
cmdupuis3 wants to merge 27 commits into
UXARRAY:mainfrom
cmdupuis3:cmd/bench_io
Open

cmdupuis3 wants to merge 27 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 [f2947b9] After [3e239e0] Ratio Benchmark (Parameter)
- 344M 292M 0.85 import.Imports.track_peakmem_import_uxarray

Benchmarks that have stayed the same:

Change Before [f2947b9] After [3e239e0] Ratio Benchmark (Parameter)
5.35±0.07ms 5.38±0.08ms 1.01 bench_connectivity.Connectivity.time_edge_face('120km')
2.00±0.02ms 1.99±0ms 0.99 bench_connectivity.Connectivity.time_edge_face('480km')
4.49±0.08ms 4.44±0.06ms 0.99 bench_connectivity.Connectivity.time_edge_node('120km')
1.60±0.02ms 1.58±0.01ms 0.99 bench_connectivity.Connectivity.time_edge_node('480km')
4.43±0.08ms 4.46±0.06ms 1.01 bench_connectivity.Connectivity.time_face_edge('120km')
1.59±0.02ms 1.60±0.02ms 1.01 bench_connectivity.Connectivity.time_face_edge('480km')
6.34±0.06ms 6.36±0.1ms 1.00 bench_connectivity.Connectivity.time_face_face('120km')
2.36±0.03ms 2.38±0.02ms 1.01 bench_connectivity.Connectivity.time_face_face('480km')
54.5±0.6μs 53.7±0.6μs 0.98 bench_connectivity.Connectivity.time_face_node('120km')
53.4±1μs 53.4±0.6μs 1.00 bench_connectivity.Connectivity.time_face_node('480km')
429±10μs 439±10μs 1.02 bench_connectivity.Connectivity.time_n_nodes_per_face('120km')
374±20μs 367±10μs 0.98 bench_connectivity.Connectivity.time_n_nodes_per_face('480km')
5.68±0.03ms 5.69±0.06ms 1.00 bench_connectivity.Connectivity.time_node_edge('120km')
2.02±0.01ms 2.00±0.01ms 0.99 bench_connectivity.Connectivity.time_node_edge('480km')
82.2±0.8ms 81.9±10ms 1.00 bench_connectivity.Connectivity.time_node_face('120km')
4.98±0.02ms 5.04±0.07ms 1.01 bench_connectivity.Connectivity.time_node_face('480km')
8.34±0.07ms 8.27±0.4ms 0.99 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
2.75±0.06ms 2.71±0.05ms 0.99 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
10.6±10s 9.76±10ms ~0.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
1.59±0.02ms 1.57±0.03ms 0.99 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.98M 1.98M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
1.97M 1.97M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
2.13M 2.13M 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
35.5k 35.5k 1.00 face_bounds.FaceBounds.track_peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
345M 336M 0.98 face_bounds.FaceBoundsColdStartRss.track_peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
366M 368M 1.01 face_bounds.FaceBoundsColdStartRss.track_peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
345M 338M 0.98 face_bounds.FaceBoundsColdStartRss.track_peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
345M 337M 0.98 face_bounds.FaceBoundsColdStartRss.track_peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.19±0.04μs 1.22±0.04μs 1.03 geometry_kernels.AccucrossKernels.time_accucross
2.67±0.03μs 2.79±0.03μs 1.05 geometry_kernels.AccucrossKernels.time_accucross_pair
461±5ns 466±5ns 1.01 geometry_kernels.EFTPrimitives.time_acc_sqrt_re
451±20ns 431±5ns 0.96 geometry_kernels.EFTPrimitives.time_diff_of_products
391±8ns 380±20ns 0.97 geometry_kernels.EFTPrimitives.time_two_prod
391±10ns 391±10ns 1.00 geometry_kernels.EFTPrimitives.time_two_sum
667±20ns 652±0.5ns 0.98 geometry_kernels.GCAConstLatIntersection.time_accux_constlat_kernel
731±9ns 756±30ns 1.03 geometry_kernels.GCAConstLatIntersection.time_gca_const_lat_intersection
791±10ns 791±20ns 1.00 geometry_kernels.GCAConstLatIntersection.time_try_gca_const_lat_intersection
796±10ns 847±100ns 1.06 geometry_kernels.GCAGCAIntersection.time_accux_gca_kernel
932±30ns 921±20ns 0.99 geometry_kernels.GCAGCAIntersection.time_gca_gca_intersection
1.04±0.03μs 1.02±0.02μs 0.98 geometry_kernels.GCAGCAIntersection.time_try_gca_gca_intersection
52.1±0.5μs 50.6±1μs 0.97 geometry_kernels.OrientPredicates.time_on_minor_arc
52.3±0.8μs 51.2±0.5μs 0.98 geometry_kernels.OrientPredicates.time_orient3d_on_sphere
3.09±0.02ms 3.05±0.01ms 0.99 geometry_samebody.SameBodyConstLat.time_accux_dispatch
1.17±0ms 1.16±0ms 0.99 geometry_samebody.SameBodyConstLat.time_accux_kernel
2.29±0.01ms 2.31±0.02ms 1.01 geometry_samebody.SameBodyConstLat.time_fp64_dispatch
148±4μs 146±0.2μs 0.99 geometry_samebody.SameBodyConstLat.time_fp64_kernel
29.6±0.2ms 29.6±0.02ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_dispatch
6.29±0.02ms 6.28±0.01ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_kernel
23.8±0.2ms 23.6±0.04ms 0.99 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_dispatch
860±1μs 864±7μs 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_kernel
880±9ms 874±10ms 0.99 import.Imports.timeraw_import_uxarray
2.54±0.02ms 2.55±0.04ms 1.01 mpas_ocean.CheckNorm.time_check_norm('120km')
2.03±0.02ms 2.05±0.02ms 1.01 mpas_ocean.CheckNorm.time_check_norm('480km')
1.17±0.01ms 1.17±0.02ms 1.00 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
560±10μs 571±10μs 1.02 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
656±7μs 646±10μs 0.98 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
615±10μs 600±20μs 0.97 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
5.44±0.05ms 5.45±0.1ms 1.00 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('120km')
3.87±0.01ms 3.89±0.05ms 1.01 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('480km')
95.6±0.9ms 95.1±0.3ms 1.00 mpas_ocean.ConstructFaceLatLon.time_welzl('120km')
10.3±0.09ms 9.27±0.4ms ~0.90 mpas_ocean.ConstructFaceLatLon.time_welzl('480km')
18.4±0.07ms 18.4±0.06ms 1.00 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
955±10μs 968±20μs 1.01 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
11.1±0.03ms 11.0±0.08ms 0.99 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
653±20μs 647±30μs 0.99 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
615±10ms 612±10ms 0.99 mpas_ocean.CrossSections.time_const_lat('120km', 1)
311±8ms 315±8ms 1.02 mpas_ocean.CrossSections.time_const_lat('120km', 2)
159±3ms 164±7ms 1.03 mpas_ocean.CrossSections.time_const_lat('120km', 4)
555±4ms 558±3ms 1.01 mpas_ocean.CrossSections.time_const_lat('480km', 1)
284±4ms 285±10ms 1.00 mpas_ocean.CrossSections.time_const_lat('480km', 2)
144±4ms 143±0.6ms 0.99 mpas_ocean.CrossSections.time_const_lat('480km', 4)
358M 356M 0.99 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('120km', 1)
356M 356M 1.00 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('120km', 2)
356M 356M 1.00 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('120km', 4)
345M 339M 0.98 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('480km', 1)
345M 339M 0.98 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('480km', 2)
345M 339M 0.98 mpas_ocean.CrossSectionsPeakMem.track_peakmem_const_lat('480km', 4)
24.8±0.5ms 24.7±0.3ms 1.00 mpas_ocean.DualMesh.time_dual_mesh_construction('120km')
2.88±0.04ms 2.99±0.03ms 1.04 mpas_ocean.DualMesh.time_dual_mesh_construction('480km')
14.3±0.4ms 14.7±0.4ms 1.03 mpas_ocean.FaceAreas.time_face_areas('120km')
4.52±0.4ms 4.62±0.1ms 1.02 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.12M 1.00 mpas_ocean.FaceAreas.track_peakmem_face_areas('120km')
715k 715k 1.00 mpas_ocean.FaceAreas.track_peakmem_face_areas('480km')
962±10ms 968±20ms 1.01 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
54.3±2ms 55.1±2ms 1.02 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
83.9±0.5ms 84.2±0.2ms 1.00 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.56±0.4ms 5.19±0.2ms 0.93 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
13.5±0.5ms 13.0±0.2ms 0.97 mpas_ocean.Gradient.time_gradient('120km')
1.80±0.02ms 1.80±0.01ms 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')
3.2M 3.2M 1.00 mpas_ocean.Gradient.track_peakmem_gradient('120km')
204k 204k 1.00 mpas_ocean.Gradient.track_peakmem_gradient('480km')
352M 352M 1.00 mpas_ocean.GradientColdStartRss.track_peakmem_gradient('120km')
345M 331M 0.96 mpas_ocean.GradientColdStartRss.track_peakmem_gradient('480km')
282±10μs 272±3μs 0.97 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
148±2μs 147±5μs 0.99 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
201±3μs 202±2μs 1.01 mpas_ocean.Integrate.time_integrate('120km')
184±2μs 185±10μs 1.00 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')
186±2ms 186±1ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
184±2ms 185±1ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
183±0.8ms 187±2ms 1.02 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
13.7±0.3ms 13.1±0.2ms 0.95 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
13.1±0.09ms 12.7±0.1ms 0.97 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
13.1±0.1ms 12.9±0.5ms 0.98 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
238±1ms 241±1ms 1.01 mpas_ocean.NeighborhoodBuild.time_build('120km', 1.0)
1.27±0s 1.27±0s 1.00 mpas_ocean.NeighborhoodBuild.time_build('120km', 15.0)
490±1ms 496±2ms 1.01 mpas_ocean.NeighborhoodBuild.time_build('120km', 5.0)
12.9±0.06ms 12.9±0.06ms 1.00 mpas_ocean.NeighborhoodBuild.time_build('480km', 1.0)
24.5±0.3ms 24.7±0.04ms 1.01 mpas_ocean.NeighborhoodBuild.time_build('480km', 15.0)
16.1±0.2ms 16.0±0.1ms 1.00 mpas_ocean.NeighborhoodBuild.time_build('480km', 5.0)
234±2ms 235±0.8ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 1.0)
1.25±0s 1.25±0s 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 15.0)
485±3ms 488±2ms 1.01 mpas_ocean.NeighborhoodBuild.time_query_radius('120km', 5.0)
12.6±0.2ms 12.6±0.03ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 1.0)
24.4±0.2ms 24.5±0.4ms 1.00 mpas_ocean.NeighborhoodBuild.time_query_radius('480km', 15.0)
15.7±0.2ms 16.1±0.2ms 1.03 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)
824k 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)
44.2±0.7ms 45.4±0.5ms 1.03 mpas_ocean.NeighborhoodDask.time_mean('120km', 'grid_chunks')
22.7±0.07ms 22.7±0.1ms 1.00 mpas_ocean.NeighborhoodDask.time_mean('120km', 'numpy')
41.4±0.6ms 41.1±0.5ms 0.99 mpas_ocean.NeighborhoodDask.time_mean('120km', 'time_chunks')
12.2±0.2ms 12.9±0.2ms 1.06 mpas_ocean.NeighborhoodDask.time_mean('480km', 'grid_chunks')
676±7μs 666±10μs 0.98 mpas_ocean.NeighborhoodDask.time_mean('480km', 'numpy')
8.70±0.3ms 8.88±0.5ms 1.02 mpas_ocean.NeighborhoodDask.time_mean('480km', 'time_chunks')
5.84M 5.84M 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.67M 5.68M 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('120km', 'time_chunks')
680k 686k 1.01 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'grid_chunks')
177k 176k 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'numpy')
530k 528k 1.00 mpas_ocean.NeighborhoodDask.track_peakmem_mean('480km', 'time_chunks')
12.4±0.01s 12.5±0.06s 1.01 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('120km', 'mean')
13.0±0s 13.1±0.03s 1.00 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('120km', 'median')
223±2ms 223±1ms 1.00 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('480km', 'mean')
226±0.4ms 227±0.5ms 1.01 mpas_ocean.NeighborhoodReduce.time_dataset_reduce('480km', 'median')
1.30±0s 1.30±0.01s 1.00 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('120km', 'mean')
1.50±0s 1.51±0.01s 1.01 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('120km', 'median')
25.7±0.2ms 25.5±0.2ms 0.99 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('480km', 'mean')
26.3±0.09ms 26.2±0.2ms 0.99 mpas_ocean.NeighborhoodReduce.time_neighborhood_reduce('480km', 'median')
38.1±0.3ms 38.3±0.3ms 1.00 mpas_ocean.NeighborhoodReduce.time_reduce('120km', 'mean')
232±0.6ms 232±0.5ms 1.00 mpas_ocean.NeighborhoodReduce.time_reduce('120km', 'median')
587±10μs 549±50μs 0.94 mpas_ocean.NeighborhoodReduce.time_reduce('480km', 'mean')
1.68±0.02ms 1.74±0.05ms 1.04 mpas_ocean.NeighborhoodReduce.time_reduce('480km', 'median')
239k 239k 1.00 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('120km', 'mean')
245k 245k 1.00 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('120km', 'median')
19.4k 19.3k 0.99 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('480km', 'mean')
19.9k 19.8k 0.99 mpas_ocean.NeighborhoodReduce.track_peakmem_reduce('480km', 'median')
437±9μs 447±10μs 1.02 mpas_ocean.PointInPolygon.time_face_search_lonlat('120km')
412±10μs 418±10μs 1.01 mpas_ocean.PointInPolygon.time_face_search_lonlat('480km')
413±20μs 393±10μs 0.95 mpas_ocean.PointInPolygon.time_face_search_xyz('120km')
389±10μs 393±20μs 1.01 mpas_ocean.PointInPolygon.time_face_search_xyz('480km')
129±0.4ms 127±0.6ms 0.99 mpas_ocean.RemapDownsample.time_bilinear_remapping
17.4±0.08ms 17.4±0.2ms 1.00 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
15.7±0.1ms 15.6±0.2ms 0.99 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
1.43±0.01s 1.42±0.01s 1.00 mpas_ocean.RemapUpsample.time_bilinear_remapping
26.9±0.4ms 26.4±0.2ms 0.98 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
12.2±0.1ms 12.9±0.4ms 1.06 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
8.50±0.1ms 8.27±0.07ms 0.97 mpas_ocean.ZonalAverage.time_zonal_average('120km')
5.33±0.08ms 5.20±0.08ms 0.98 mpas_ocean.ZonalAverage.time_zonal_average('480km')
358M 358M 1.00 mpas_ocean.ZonalAveragePeakMem.track_peakmem_zonal_average('120km')
345M 341M 0.99 mpas_ocean.ZonalAveragePeakMem.track_peakmem_zonal_average('480km')
6.84±0.04ms 6.68±0.06ms 0.98 quad_hexagon.QuadHexagon.time_open_dataset
6.08±0.2ms 5.78±0.08ms 0.95 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.1k 72.8k 1.00 quad_hexagon.QuadHexagon.track_peakmem_open_dataset
72.6k 71.9k 0.99 quad_hexagon.QuadHexagon.track_peakmem_open_grid

@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>
@cmdupuis3
cmdupuis3 marked this pull request as ready for review September 17, 2026 22:31
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