Skip to content

ASV better memory benchmarks - #1609

Open
cmdupuis3 wants to merge 8 commits into
UXARRAY:mainfrom
cmdupuis3:cmd/asv-peakmem-benchmark-fix
Open

ASV better memory benchmarks#1609
cmdupuis3 wants to merge 8 commits into
UXARRAY:mainfrom
cmdupuis3:cmd/asv-peakmem-benchmark-fix

Conversation

@cmdupuis3

@cmdupuis3 cmdupuis3 commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Closes #1605

Overview

The current behavior of a few peakmem benchmarks entrains module imports and caching, which dwarf the actual memory usage supposedly being tested. This PR offers benchmarks of low-level memory behavior as well as warm setups to prevent the persistent "every PR improves memory by the same amount" issue in #1605.

Expected Usage

Most of these benchmarks are useful as-is, but there are also a couple of benchmarks of pure uxarray imports to compare with if the illusory memory improvement ever returns.

PR Checklist

General

  • An issue is linked created and linked
  • Add appropriate labels
  • Filled out Overview and Expected Usage (if applicable) sections

Testing

  • Adequate tests are created if there is new functionality
  • Tests cover all possible logical paths in your function
  • Tests are not too basic (such as simply calling a function and nothing else)

Documentation

  • Docstrings have been added to all new functions
  • Docstrings have updated with any function changes

cmdupuis3 and others added 3 commits July 22, 2026 12:52
Three benchmarks reported a near-identical "improvement" on every PR regardless
of what the PR touched:

  578M -> 391M  0.68  face_bounds.FaceBounds.peakmem_face_bounds(geoflow-small)
  708M -> 390M  0.55  face_bounds.FaceBounds.peakmem_face_bounds(quad-hexagon)
  498M -> 384M  0.77  mpas_ocean.Gradient.peakmem_gradient('480km')

They were not measuring the operation under test. asv's peakmem_* records the
max RSS of the whole process, and per asv's docs it "also counts memory usage
during the setup routine". Profiling the face_bounds params:

  grid                    import  +open_grid  +.bounds   attributable to op
  quad-hexagon  ( 24K)     236MB      265MB     301MB     36MB (12%)
  geoflow-small (1.1M)     236MB      263MB     487MB    224MB (46%)
  outCSne8      ( 48K)     235MB      281MB     317MB     35MB (11%)
  oQU480        (4.6M)     236MB      270MB     306MB     36MB (12%)

`import uxarray` alone is ~226 MB and constant to within 1 MB. oQU480 is 190x
larger than quad-hexagon yet both attributed ~36 MB to Grid.bounds -- the
benchmark was nearly insensitive to its own workload. The part that did vary was
numba: uxarray has 81 @njit(cache=True) kernels and both affected paths go
through them (uxarray/grid/bounds.py, uxarray/core/gradient.py). With a cold JIT
cache the quad-hexagon case peaked at 599 MB, with a warm one 298 MB -- a ratio
of 0.50, matching the ratios seen in CI. Which side of an `asv continuous`
comparison paid the compile cost depended on run order, not on the code under
review.

peakmem_* could not be repaired in place, because there was nothing to measure.
Across every operation the five peakmem benchmarks covered, against every mesh
in the suite including the 98 MB / 28,571-face oQU120:

  Grid.bounds        ~1 MB     open_grid   0-10 MB (lazy; mostly allocator noise)
  gradient        0-0.1 MB     integrate       0.0 MB
  open_dataset      0.0 MB

Two better instruments were evaluated and rejected:

  - Sampled peak RSS. Validates cleanly (a known 200 MB allocation measures as
    200.0 MB) and is immune to process history. But the warm-up call needed to
    keep JIT out of the measurement leaves freed pages in the allocator, so RSS
    *growth* undercounts -- every operation measured 0.0-0.1 MB this way.
  - tracemalloc. Measures allocation volume rather than RSS growth, so it would
    sidestep page reuse, but it does not observe numba NRT allocations, which is
    where uxarray's array memory is allocated.

What remains is deterministic size accounting via track_* benchmarks, which also
sidesteps the setup confound entirely -- track_* does not count setup. Verified
byte-identical across cold JIT, warm JIT, and an independent second cold JIT for
all 14 parameter combinations, and it scales correctly with the mesh
(quad-hexagon reports 128 bytes = 4 faces x 32). It does not capture transient
peaks, but the measurements above show those are ~1 MB, far below anything worth
gating on, and no available instrument captures them reliably here.

The rationale is recorded in benchmarks/_memsize.py so the next person does not
reintroduce peakmem_*. The commented-out mem_* stubs in quad_hexagon.py, an
earlier attempt at the same thing, are removed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The previous commit removed peakmem_* because the per-operation memory it
claimed to measure was ~1 MB against a reported 400-700 MB. But the larger
question those benchmarks were reaching for -- "how much memory does it take to
open this grid and compute on it, from a cold start" -- is real, and asv can
answer it with its own peakmem_* once two things are controlled:

  1. Process history. ru_maxrss is a high-water mark that never falls, so
     imports, setup() and earlier work in the same process set a floor under the
     result. asv already spawns a separate process per benchmark *and per
     parameter* (runner._run_benchmark_single_param), so this is handled as long
     as the benchmark classes declare no setup() -- asv counts setup memory
     towards peakmem_*, which is exactly the confound its own docs warn about.

  2. numba JIT cache warmth. Compiling uxarray's 81 @njit(cache=True) kernels
     costs a few hundred MB of transient RSS, so an otherwise identical run
     peaked at 599 MB cold and 298 MB warm. Whichever side of an `asv continuous`
     comparison happened to compile paid that cost.

setup_cache handles (2). asv runs it in its own process
(runner.Spawner.create_setup_cache), so LLVM's footprint never enters the
high-water mark of the processes that do the measuring; they load the compiled
kernels from numba's on-disk cache instead. It runs once per commit, so both
sides of a comparison are warmed symmetrically. Every parameter is warmed, not
just one -- the grids do not all reach the same njit signatures.

Measured via `asv run --python=same --quick -b peakmem`, twice warm and once
after deleting every .nbi/.nbc in the installed uxarray:

                              warm    warm    COLD    spread
  import uxarray              280M    282M    280M      0.7%
  open+bounds quad-hexagon    349M    349M    346M      0.9%
  open+bounds geoflow-small   348M    348M    348M      0.0%
  open+bounds outCSne8        365M    364M    370M      1.6%
  open+bounds oQU480          354M    356M    351M      1.4%
  gradient 480km              358M    355M    354M      1.1%
  gradient 120km              371M    370M    381M      2.9%

The cold column is the condition that used to halve the result; the cache
repopulated from 0 to 33 entries during that run, confirming setup_cache did the
compiling. Everything sits inside 2.9%, against asv's default 10% factor.

peakmem_import_uxarray is included deliberately. ~280 MB of every row above is
just importing uxarray, so tracking it on its own means a heavy new top-level
import shows up as itself instead of silently inflating everything else.

Also moves _memsize into benchmarks/helpers/ and gives it an __init__.py, so the
package structure is explicit rather than relying on namespace packages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@cmdupuis3 cmdupuis3 added bug Something isn't working benchmarking Related to benchmarks, memory usage, and/or time profiling run-benchmark Run ASV benchmark workflow labels Jul 22, 2026
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown

ASV Benchmarking

Benchmark Comparison Results

Benchmarks that have improved:

Change Before [ab023b9] After [734a41d] Ratio Benchmark (Parameter)
- 436M 330M 0.76 mpas_ocean.FaceAreas.peakmem_compute_face_areas('480km')

Benchmarks that have stayed the same:

Change Before [ab023b9] After [734a41d] Ratio Benchmark (Parameter)
201±1ms 203±2ms 1.01 bench_connectivity.Connectivity.time_edge_face('120km')
11.9±0.08ms 12.7±0.4ms 1.06 bench_connectivity.Connectivity.time_edge_face('480km')
198±1ms 197±0.9ms 1 bench_connectivity.Connectivity.time_edge_node('120km')
11.0±0.1ms 11.2±0.09ms 1.02 bench_connectivity.Connectivity.time_edge_node('480km')
197±1ms 201±2ms 1.02 bench_connectivity.Connectivity.time_face_edge('120km')
11.5±0.2ms 11.5±0.05ms 1 bench_connectivity.Connectivity.time_face_edge('480km')
868±10ms 888±10ms 1.02 bench_connectivity.Connectivity.time_face_face('120km')
55.9±0.3ms 57.0±0.3ms 1.02 bench_connectivity.Connectivity.time_face_face('480km')
65.9±2μs 67.9±3μs 1.03 bench_connectivity.Connectivity.time_face_node('120km')
65.1±2μs 65.9±2μs 1.01 bench_connectivity.Connectivity.time_face_node('480km')
405±10μs 422±10μs 1.04 bench_connectivity.Connectivity.time_n_nodes_per_face('120km')
331±10μs 336±2μs 1.02 bench_connectivity.Connectivity.time_n_nodes_per_face('480km')
198±0.7ms 199±0.6ms 1 bench_connectivity.Connectivity.time_node_edge('120km')
11.4±0.01ms 12.1±0.5ms 1.06 bench_connectivity.Connectivity.time_node_edge('480km')
76.0±0.4ms 77.2±3ms 1.02 bench_connectivity.Connectivity.time_node_face('120km')
5.09±0.05ms 5.10±0.05ms 1 bench_connectivity.Connectivity.time_node_face('480km')
8.79±0.1ms 8.88±0.1ms 1.01 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
2.78±0.09ms 2.85±0.08ms 1.03 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
10.6±0.1ms 10.1±0.04ms 0.95 face_bounds.FaceBounds.time_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
2.10±0.01ms 2.08±0.02ms 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 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 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
123k 123k 1 face_bounds.FaceBounds.track_nbytes_face_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
128 128 1 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 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 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 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
712 712 1 face_bounds.FaceBounds.track_nbytes_grid_with_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
334M 334M 1 face_bounds.FaceBoundsPeakMem.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/mpas/QU/oQU480.231010.nc'))
363M 363M 1 face_bounds.FaceBoundsPeakMem.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/scrip/outCSne8/outCSne8.nc'))
336M 336M 1 face_bounds.FaceBoundsPeakMem.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/geoflow-small/grid.nc'))
335M 335M 1 face_bounds.FaceBoundsPeakMem.peakmem_open_and_bounds(PosixPath('/home/runner/work/uxarray/uxarray/test/meshfiles/ugrid/quad-hexagon/grid.nc'))
1.22±0.03μs 1.22±0.05μs 1 geometry_kernels.AccucrossKernels.time_accucross
2.75±0.04μs 2.73±0.05μs 1 geometry_kernels.AccucrossKernels.time_accucross_pair
470±10ns 451±4ns 0.96 geometry_kernels.EFTPrimitives.time_acc_sqrt_re
451±20ns 436±20ns 0.97 geometry_kernels.EFTPrimitives.time_diff_of_products
406±6ns 386±9ns 0.95 geometry_kernels.EFTPrimitives.time_two_prod
411±10ns 396±10ns 0.96 geometry_kernels.EFTPrimitives.time_two_sum
1.54±0.05μs 1.57±0.04μs 1.02 geometry_kernels.GCAConstLatIntersection.time_accux_constlat_kernel
1.12±0.03μs 1.11±0.02μs 1 geometry_kernels.GCAConstLatIntersection.time_gca_const_lat_intersection
1.89±0.04μs 1.94±0.06μs 1.02 geometry_kernels.GCAConstLatIntersection.time_try_gca_const_lat_intersection
1.64±0.03μs 1.63±0.04μs 0.99 geometry_kernels.GCAGCAIntersection.time_accux_gca_kernel
1.36±0.02μs 1.36±0.03μs 1 geometry_kernels.GCAGCAIntersection.time_gca_gca_intersection
2.13±0.03μs 2.14±0.03μs 1 geometry_kernels.GCAGCAIntersection.time_try_gca_gca_intersection
52.3±0.6μs 52.2±2μs 1 geometry_kernels.OrientPredicates.time_on_minor_arc
1.16±0.02μs 1.17±0.05μs 1.01 geometry_kernels.OrientPredicates.time_orient3d_on_sphere
2.72±0.1ms 2.59±0.01ms 0.95 geometry_samebody.SameBodyConstLat.time_accux_dispatch
1.17±0.01ms 1.17±0ms 1 geometry_samebody.SameBodyConstLat.time_accux_kernel
1.73±0.01ms 1.71±0.02ms 0.99 geometry_samebody.SameBodyConstLat.time_fp64_dispatch
147±2μs 147±8μs 1 geometry_samebody.SameBodyConstLat.time_fp64_kernel
32.4±0.04ms 32.2±0.03ms 0.99 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_dispatch
10.4±0.06ms 10.2±0.02ms 0.98 geometry_samebody_gcagca.SameBodyGcaGca.time_accux_kernel
26.7±0.2ms 26.5±0.04ms 0.99 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_dispatch
4.91±0ms 4.88±0.01ms 0.99 geometry_samebody_gcagca.SameBodyGcaGca.time_fp64_kernel
293M 293M 1 import.Imports.peakmem_import_uxarray
796±5ms 798±3ms 1 import.Imports.timeraw_import_uxarray
2.65±0.02ms 2.66±0.02ms 1 mpas_ocean.CheckNorm.time_check_norm('120km')
2.22±0.02ms 2.19±0.02ms 0.99 mpas_ocean.CheckNorm.time_check_norm('480km')
799±6ms 805±7ms 1.01 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('120km')
53.2±0.3ms 54.2±0.3ms 1.02 mpas_ocean.ConnectivityConstruction.time_face_face_connectivity('480km')
664±6μs 660±8μs 0.99 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('120km')
577±10μs 584±5μs 1.01 mpas_ocean.ConnectivityConstruction.time_n_nodes_per_face('480km')
5.35±0.03ms 5.34±0.04ms 1 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('120km')
3.84±0.01ms 3.87±0.04ms 1.01 mpas_ocean.ConstructFaceLatLon.time_cartesian_averaging('480km')
3.45±0.01s 3.43±0.02s 1 mpas_ocean.ConstructFaceLatLon.time_welzl('120km')
224±0.8ms 221±0.9ms 0.99 mpas_ocean.ConstructFaceLatLon.time_welzl('480km')
18.2±0.04ms 18.1±0.01ms 1 mpas_ocean.ConstructTreeStructures.time_ball_tree('120km')
1.01±0.02ms 998±20μs 0.99 mpas_ocean.ConstructTreeStructures.time_ball_tree('480km')
10.6±0.03ms 10.5±0.01ms 1 mpas_ocean.ConstructTreeStructures.time_kd_tree('120km')
732±20μs 690±10μs 0.94 mpas_ocean.ConstructTreeStructures.time_kd_tree('480km')
701±8ms 696±3ms 0.99 mpas_ocean.CrossSections.time_const_lat('120km', 1)
354±3ms 350±1ms 0.99 mpas_ocean.CrossSections.time_const_lat('120km', 2)
183±3ms 182±0.6ms 0.99 mpas_ocean.CrossSections.time_const_lat('120km', 4)
537±4ms 544±8ms 1.01 mpas_ocean.CrossSections.time_const_lat('480km', 1)
277±4ms 274±1ms 0.99 mpas_ocean.CrossSections.time_const_lat('480km', 2)
140±0.9ms 141±0.2ms 1 mpas_ocean.CrossSections.time_const_lat('480km', 4)
24.4±0.04ms 24.6±0.2ms 1.01 mpas_ocean.DualMesh.time_dual_mesh_construction('120km')
3.48±0.03ms 3.50±0.04ms 1.01 mpas_ocean.DualMesh.time_dual_mesh_construction('480km')
349M 349M 1 mpas_ocean.FaceAreas.peakmem_compute_face_areas('120km')
60.8±0.4ms 61.0±0.3ms 1 mpas_ocean.FaceAreas.time_compute_face_areas('120km')
7.16±0.1ms 7.25±0.09ms 1.01 mpas_ocean.FaceAreas.time_compute_face_areas('480km')
939±10ms 964±3ms 1.03 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', False)
50.6±0.7ms 53.8±2ms 1.06 mpas_ocean.GeoDataFrame.time_to_geodataframe('120km', True)
82.9±0.5ms 84.0±0.8ms 1.01 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', False)
5.64±0.2ms 5.64±0.1ms 1 mpas_ocean.GeoDataFrame.time_to_geodataframe('480km', True)
176±4ms 174±0.9ms 0.99 mpas_ocean.Gradient.time_gradient('120km')
12.8±0.06ms 12.9±0.1ms 1.01 mpas_ocean.Gradient.time_gradient('480km')
457k 457k 1 mpas_ocean.Gradient.track_nbytes_gradient('120km')
28.7k 28.7k 1 mpas_ocean.Gradient.track_nbytes_gradient('480km')
350M 350M 1 mpas_ocean.GradientPeakMem.peakmem_gradient('120km')
330M 329M 1 mpas_ocean.GradientPeakMem.peakmem_gradient('480km')
384±7μs 383±10μs 1 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('120km')
190±10μs 195±3μs 1.03 mpas_ocean.HoleEdgeIndices.time_construct_hole_edge_indices('480km')
539±10μs 539±20μs 1 mpas_ocean.Integrate.time_integrate('120km')
456±9μs 462±10μs 1.01 mpas_ocean.Integrate.time_integrate('480km')
18.4M 18.4M 1 mpas_ocean.Integrate.track_nbytes_integrate('120km')
1.2M 1.2M 1 mpas_ocean.Integrate.track_nbytes_integrate('480km')
179±0.7ms 179±0.8ms 1 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'exclude')
183±1ms 181±0.5ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'include')
180±1ms 182±1ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('120km', 'split')
13.7±0.05ms 13.4±0.2ms 0.98 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'exclude')
13.4±0.09ms 13.5±0.4ms 1.01 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'include')
13.5±0.08ms 13.4±0.2ms 0.99 mpas_ocean.MatplotlibConversion.time_dataarray_to_polycollection('480km', 'split')
394±10μs 397±10μs 1.01 mpas_ocean.PointInPolygon.time_face_search_lonlat('120km')
380±4μs 404±20μs 1.06 mpas_ocean.PointInPolygon.time_face_search_lonlat('480km')
373±7μs 380±9μs 1.02 mpas_ocean.PointInPolygon.time_face_search_xyz('120km')
359±9μs 356±10μs 0.99 mpas_ocean.PointInPolygon.time_face_search_xyz('480km')
237±0.3ms 245±1ms 1.03 mpas_ocean.RemapDownsample.time_bilinear_remapping
283±2ms 293±9ms 1.03 mpas_ocean.RemapDownsample.time_inverse_distance_weighted_remapping
15.6±0.09ms 15.5±0.1ms 1 mpas_ocean.RemapDownsample.time_nearest_neighbor_remapping
1.43±0s 1.43±0.01s 1 mpas_ocean.RemapUpsample.time_bilinear_remapping
35.9±0.1ms 37.2±0.4ms 1.04 mpas_ocean.RemapUpsample.time_inverse_distance_weighted_remapping
12.6±0.3ms 12.4±0.3ms 0.98 mpas_ocean.RemapUpsample.time_nearest_neighbor_remapping
26.3±0.5ms 26.7±0.5ms 1.02 mpas_ocean.ZonalAverage.time_zonal_average('120km')
5.67±0.06ms 5.77±0.07ms 1.02 mpas_ocean.ZonalAverage.time_zonal_average('480km')
6.94±0.06ms 6.91±0.1ms 1 quad_hexagon.QuadHexagon.time_open_dataset
5.89±0.08ms 6.28±0.4ms 1.07 quad_hexagon.QuadHexagon.time_open_grid
408 408 1 quad_hexagon.QuadHexagon.track_nbytes_open_dataset
392 392 1 quad_hexagon.QuadHexagon.track_nbytes_open_grid

@Sevans711

Copy link
Copy Markdown
Collaborator

Thank you for working on this and opening up this PR! I have a few quick thoughts before reviewing:

  1. I wonder if nbytes should be added directly as a property of Grid objects, instead of needing a custom grid_nbytes function? It might be nice to be able to do uxgrid.nbytes, since Grid is basically just an xr.Dataset with some extra functionality attached to it, and it seems nice to be able to quickly check how large of a grid you are working with.
  2. What is the purpose of benchmarks that measure the size of the loaded Grid objects or arrays? My initial understanding is that the answer should always be the same, and it isn't really measuring runtime efficiency nor total memory usage. Would these work better as unit tests? E.g. "test_face_bounds_array_size" which asserts the size of face_bounds from oQU480.231010.nc is 57.3 kB, with some small tolerance for rounding errors. I might also be not fully understanding the purpose of benchmarks. Also wondering if @erogluorhan or @rajeeja have thoughts on this question in particular?

@cmdupuis3 cmdupuis3 self-assigned this Jul 24, 2026
@cmdupuis3

Copy link
Copy Markdown
Collaborator Author

@Sevans711 as per convo, 1 is really a question for @erogluorhan or @rajeeja. On 2, these are included because the peakmem is not necessarily the same as the total memory usage in a chunked situation. This particular batch of benchmarks is a little verbose, but it basically serves as a regression test against the kinds of spurious improvements in other PRs, so that we have a better idea of which things are bloating the peakmem metrics.

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.

Some ASV peakmem benchmarks always show the same "improvement"

3 participants