Skip to content

Fix interp performance regression from #9881 - #11496

Draft
oshokothari07-ai wants to merge 1 commit into
pydata:mainfrom
oshokothari07-ai:fix/interp-vectorize-bulk-dims
Draft

Fix interp performance regression from #9881#11496
oshokothari07-ai wants to merge 1 commit into
pydata:mainfrom
oshokothari07-ai:fix/interp-vectorize-bulk-dims

Conversation

@oshokothari07-ai

Copy link
Copy Markdown

Description

Closes #10683.

This PR addresses the performance regression in DataArray.interp and Dataset.interp introduced by #9881 when the target coordinate varies along a dimension of the source array.

The regression occurs because interpolate_variable enables vectorize=True when calling apply_ufunc. With np.vectorize, every non-core dimension is iterated in Python, including dimensions that do not actually require vectorization. For cases such as da[t, r, z].interp(z=target[t]), this causes the interpolator to be called once for every (t, r) pair instead of once per t.

The fix promotes the remaining non-vectorized dimensions to core dimensions so they are passed to _interpnd in bulk. _interpnd already treats these leading dimensions as constant, so this avoids the unnecessary Python-level looping while preserving interpolation behavior. This optimization is applied only to in-memory arrays because making these dimensions core for chunked arrays would force dask to rechunk along them.

On the example from the issue, this reduces _interpnd calls from 7930 to 122 and reduces runtime from roughly 2.2 s to around 110 ms in my local testing.

Testing

  • Added a regression test that verifies the interpolator is not repeatedly called over free dimensions.
  • Added a companion test that verifies chunking is preserved for dask-backed arrays.
  • Verified that the regression test fails without the fix.
  • Local results for xarray/tests/test_interp.py and xarray/tests/test_missing.py: 283 passed, 74 skipped, 1 xfailed.
  • ruff check and ruff format pass.

Limitations

This is a targeted workaround rather than the more general redesign of the apply_ufunc interpolation path discussed in the issue. It recovers most of the regression but does not restore the performance seen in 2024.11.0.

I was not able to run the full test suite on main locally because the repository currently requires Python 3.11+, while my local environment is Python 3.10.11. The implementation was validated against byte-identical code for the affected functions, but CI will provide the final verification across supported Python versions, platforms, the full dask test matrix, and minimum-version configurations.

I also did not run mypy locally. The only typed addition is bulk_dims: tuple[Hashable, ...], and CI will validate type checking against both the current and minimum supported environments.

Checklist

AI Disclosure

  • This PR contains AI-generated content.

    • I have tested any AI-generated content in my PR.

    • I take responsibility for any AI-generated content in my PR.

      • Tools: Claude

I used Claude as an engineering assistant during the investigation and implementation. I reviewed the changes, validated the implementation and tests, and take responsibility for the final code and this pull request.

When the target coordinate varies along a dimension of the interpolated
object, interpolate_variable passes vectorize=True to apply_ufunc, which
uses np.vectorize. np.vectorize loops in Python over every non-core
dimension, not only the dimensions that actually needed vectorizing, so
da[t, r, z].interp(z=target[t]) made t*r calls into the interpolator
instead of t.

Declare the remaining dimensions as core dimensions so they are handed to
the interpolator in bulk; _interpnd already treats leading dimensions as
constant. This is restricted to in-memory arrays because making a
dimension a core dimension forces dask to rechunk along it.

For the example in the issue this reduces _interpnd calls from 7930 to
122 (a factor of n_r = 65).

Fixes pydata#10683
@Illviljan Illviljan added the run-benchmark Run the ASV benchmark workflow label Aug 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

run-benchmark Run the ASV benchmark workflow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

interp() performance regression in 2025.1.0+

3 participants