Skip to content

Connectivity benchmarks cold-start - #1633

Open
cmdupuis3 wants to merge 1 commit into
UXARRAY:mainfrom
cmdupuis3:cmd/bench_connectivity_fix
Open

Connectivity benchmarks cold-start#1633
cmdupuis3 wants to merge 1 commit into
UXARRAY:mainfrom
cmdupuis3:cmd/bench_connectivity_fix

Conversation

@cmdupuis3

@cmdupuis3 cmdupuis3 commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator

Closes #1632

Overview

This fix provides a bare-bones Grid that allows for properly cold timing of the connectivity benchmarks, aside from a numba warmup to remove that from timing results.

Example:

[50.00%] · For uxarray commit 5f0e401 <cmd/merge-OFE> (round 2/2):
[50.00%] ·· Benchmarking conda-py3.11-netcdf4-pip+pyfma-setuptools_scm-xarray
[75.00%] ··· bench_connectivity.Connectivity.time_edge_node ok
[75.00%] ··· ============ ==========
resolution
------------ ----------
480km 1.27±0ms
120km 3.99±0ms
30km 100±0ms
15km 434±0ms
7.5km 1.97±0s
3.75km 9.92±0s
============ ==========

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

@cmdupuis3 cmdupuis3 self-assigned this Jul 30, 2026
@cmdupuis3 cmdupuis3 added bug Something isn't working benchmarking Related to benchmarks, memory usage, and/or time profiling labels Jul 30, 2026
@cmdupuis3 cmdupuis3 added this to the Benchmarks milestone Jul 30, 2026
@cmdupuis3 cmdupuis3 added the run-benchmark Run ASV benchmark workflow label Jul 30, 2026
@github-actions

Copy link
Copy Markdown

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [b1436fb] After [9da2b14] Ratio Benchmark (Parameter)
- 521M 338M 0.65 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
- 631M 335M 0.53 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
- 452M 329M 0.73 mpas_ocean.Gradient.peakmem_gradient('480km')

Benchmarks that have stayed the same:

Change Before [b1436fb] After [9da2b14] Ratio Benchmark (Parameter)
243±10ms 239±7ms 0.99 bench_connectivity.Connectivity.time_edge_face('120km')
14.0±0.6ms 13.5±0.08ms 0.96 bench_connectivity.Connectivity.time_edge_face('480km')
230±0.3ms 231±0.5ms 1.00 bench_connectivity.Connectivity.time_edge_node('120km')
12.6±0.07ms 12.6±0.05ms 1.00 bench_connectivity.Connectivity.time_edge_node('480km')
231±0.7ms 230±0.6ms 1.00 bench_connectivity.Connectivity.time_face_edge('120km')
12.9±0.07ms 12.9±0.05ms 1.00 bench_connectivity.Connectivity.time_face_edge('480km')
829±5ms 827±6ms 1.00 bench_connectivity.Connectivity.time_face_face('120km')
51.0±0.4ms 50.9±0.3ms 1.00 bench_connectivity.Connectivity.time_face_face('480km')
59.7±0.8μs 60.0±1μs 1.00 bench_connectivity.Connectivity.time_face_node('120km')
57.8±0.9μs 57.8±0.9μs 1.00 bench_connectivity.Connectivity.time_face_node('480km')
376±8μs 379±6μs 1.01 bench_connectivity.Connectivity.time_n_nodes_per_face('120km')
313±10μs 300±6μs 0.96 bench_connectivity.Connectivity.time_n_nodes_per_face('480km')
232±0.2ms 233±0.3ms 1.00 bench_connectivity.Connectivity.time_node_edge('120km')
13.2±0.2ms 13.1±0.07ms 0.99 bench_connectivity.Connectivity.time_node_edge('480km')
79.2±2ms 79.1±0.6ms 1.00 bench_connectivity.Connectivity.time_node_face('120km')
4.89±0.03ms 4.85±0.04ms 0.99 bench_connectivity.Connectivity.time_node_face('480km')
335M 334M 1.00 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
363M 365M 1.01 face_bounds.FaceBounds.peakmem_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
20.5±0.08μs 20.3±0.1μs 0.99 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
9.76±0.08μs 9.64±0.05μs 0.99 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
9.42±0.1ms 9.46±0.07ms 1.00 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
1.93±0.05ms 1.96±0.03ms 1.02 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
931±6ns 938±3ns 1.01 geometry_kernels.AccucrossKernels.time_accucross
2.39±0.01μs 2.34±0μs 0.98 geometry_kernels.AccucrossKernels.time_accucross_pair
268±0.7ns 276±10ns 1.03 geometry_kernels.EFTPrimitives.time_acc_sqrt_re
262±1ns 262±0.6ns 1.00 geometry_kernels.EFTPrimitives.time_diff_of_products
214±1ns 212±2ns 0.99 geometry_kernels.EFTPrimitives.time_two_prod
212±0.6ns 214±1ns 1.01 geometry_kernels.EFTPrimitives.time_two_sum
1.15±0μs 1.17±0.01μs 1.01 geometry_kernels.GCAConstLatIntersection.time_accux_constlat_kernel
847±2ns 850±9ns 1.00 geometry_kernels.GCAConstLatIntersection.time_gca_const_lat_intersection
1.54±0μs 1.55±0μs 1.01 geometry_kernels.GCAConstLatIntersection.time_try_gca_const_lat_intersection
1.27±0μs 1.27±0μs 1.01 geometry_kernels.GCAGCAIntersection.time_accux_gca_kernel
1.11±0μs 1.10±0μs 0.99 geometry_kernels.GCAGCAIntersection.time_gca_gca_intersection
1.82±0.02μs 1.80±0.01μs 0.99 geometry_kernels.GCAGCAIntersection.time_try_gca_gca_intersection
38.5±0.02μs 38.3±0.3μs 1.00 geometry_kernels.OrientPredicates.time_on_minor_arc
472±2ns 467±1ns 0.99 geometry_kernels.OrientPredicates.time_orient3d_on_sphere
2.92±0.1ms 2.79±0ms 0.95 geometry_samebody.SameBodyConstLat.time_accux_dispatch
1.33±0ms 1.33±0ms 1.00 geometry_samebody.SameBodyConstLat.time_accux_kernel
1.79±0.01ms 1.78±0.01ms 0.99 geometry_samebody.SameBodyConstLat.time_fp64_dispatch
151±0.2μs 151±0.7μs 1.00 geometry_samebody.SameBodyConstLat.time_fp64_kernel
32.7±0.3ms 32.7±0.2ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_dispatch
10.7±0.01ms 10.7±0.04ms 0.99 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_kernel
28.0±0.1ms 31.4±4ms ~1.12 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_dispatch
4.45±0.02ms 4.43±0.01ms 1.00 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_kernel
781±4ms 782±2ms 1.00 import.Imports.timeraw_import_uxarray
912±10ns 908±10ns 1.00 mpas_ocean.CheckNorm.time_check_norm('120km')
853±10ns 853±20ns 1.00 mpas_ocean.CheckNorm.time_check_norm('480km')
722±5ms 718±5ms 0.99 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
44.8±0.2ms 45.3±0.5ms 1.01 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
13.5±0.05μs 13.5±0.08μs 1.00 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
13.6±0.1μs 13.6±0.05μs 1.00 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
4.54±0.01ms 4.56±0.03ms 1.01 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('120km')
3.00±0.02ms 2.99±0.01ms 1.00 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('480km')
3.31±0.01s 3.31±0.01s 1.00 mpas_ocean.ConstructFaceLatLon.time_welzl('120km')
213±0.5ms 213±2ms 1.00 mpas_ocean.ConstructFaceLatLon.time_welzl('480km')
19.7±0.03ms 19.7±0.02ms 1.00 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
1.12±0.01ms 1.09±0.01ms 0.98 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
10.6±0.01ms 10.6±0.01ms 1.00 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
748±7μs 736±7μs 0.98 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
659±2ms 648±0.8ms 0.98 mpas_ocean.CrossSections.time_const_lat('120km', 1)
328±2ms 331±3ms 1.01 mpas_ocean.CrossSections.time_const_lat('120km', 2)
171±2ms 170±0.6ms 1.00 mpas_ocean.CrossSections.time_const_lat('120km', 4)
483±1ms 489±6ms 1.01 mpas_ocean.CrossSections.time_const_lat('480km', 1)
247±2ms 247±2ms 1.00 mpas_ocean.CrossSections.time_const_lat('480km', 2)
126±0.3ms 126±0.5ms 1.00 mpas_ocean.CrossSections.time_const_lat('480km', 4)
22.4±0.5ms 22.1±0.06ms 0.99 mpas_ocean.DualMesh.time_dual_mesh_construction('120km')
2.57±0.02ms 2.57±0.02ms 1.00 mpas_ocean.DualMesh.time_dual_mesh_construction('480km')
836±2ms 844±3ms 1.01 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
50.2±0.6ms 50.7±0.4ms 1.01 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
73.3±0.6ms 72.2±0.5ms 0.98 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.65±0.07ms 5.52±0.1ms 0.98 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
350M 350M 1.00 mpas_ocean.Gradient.peakmem_gradient('120km')
165±0.2ms 166±2ms 1.01 mpas_ocean.Gradient.time_gradient('120km')
12.0±0.4ms 11.5±0.08ms 0.96 mpas_ocean.Gradient.time_gradient('480km')
188±1μs 188±0.4μs 1.00 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
87.7±0.4μs 87.3±0.6μs 1.00 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
350M 350M 1.00 mpas_ocean.Integrate.peakmem_integrate('120km')
329M 329M 1.00 mpas_ocean.Integrate.peakmem_integrate('480km')
180±1μs 180±1μs 1.00 mpas_ocean.Integrate.time_integrate('120km')
157±0.8μs 156±0.7μs 1.00 mpas_ocean.Integrate.time_integrate('480km')
187±2ms 189±1ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
188±2ms 187±0.6ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
188±1ms 188±0.7ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
13.9±0.2ms 14.0±0.2ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
13.9±0.06ms 14.2±0.07ms 1.02 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
13.9±0.05ms 14.0±0.2ms 1.00 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
281±2μs 283±1μs 1.01 mpas_ocean.PointInPolygon.time_face_search_lonlat('120km')
286±0.8μs 286±1μs 1.00 mpas_ocean.PointInPolygon.time_face_search_lonlat('480km')
268±1μs 266±2μs 0.99 mpas_ocean.PointInPolygon.time_face_search_xyz('120km')
267±1μs 269±2μs 1.01 mpas_ocean.PointInPolygon.time_face_search_xyz('480km')
211±0.4ms 212±1ms 1.00 mpas_ocean.RemapDownsample.time_bilinear_remapping
227±2ms 228±0.4ms 1.00 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
4.28±0.02ms 4.31±0.01ms 1.01 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
1.18±0s 1.18±0s 1.00 mpas_ocean.RemapUpsample.time_bilinear_remapping
36.0±0.4ms 36.0±0.2ms 1.00 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
8.82±0.2ms 8.93±0.2ms 1.01 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
27.0±0.4ms 27.1±0.3ms 1.00 mpas_ocean.ZonalAverage.time_zonal_average('120km')
5.31±0.06ms 5.47±0.05ms 1.03 mpas_ocean.ZonalAverage.time_zonal_average('480km')
325M 324M 1.00 quad_hexagon.QuadHexagon.peakmem_open_dataset
324M 324M 1.00 quad_hexagon.QuadHexagon.peakmem_open_grid
6.51±0.07ms 6.48±0.2ms 1.00 quad_hexagon.QuadHexagon.time_open_dataset
5.53±0.1ms 5.51±0.1ms 1.00 quad_hexagon.QuadHexagon.time_open_grid

@Sevans711
Sevans711 self-requested a review July 31, 2026 12:58

@Sevans711 Sevans711 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a clean fix for these benchmarks. The run-benchmark results, along with the results reported in original message in PR thread, now all show expected scaling with grid size, rather than microsecond times regardless of grid size.

I considered whether it would make more sense to use Grid.__init__ with a dataset made up of just source_grid.node_lon, source_grid.node_lat, source_grid.face_node_connectivity, instead of using Grid.from_topology(), but then I realized that it shouldn't affect the timing of the benchmarks themselves, because that all happens directly in setup(), anyways.

So, looks good to me, no notes, my recommendation is to merge to main!

@cmdupuis3
cmdupuis3 requested review from dylannelson and rajeeja July 31, 2026 16:17
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 bug Something isn't working run-benchmark Run ASV benchmark workflow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Connectivity benchmarks are a no-op

2 participants