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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

interp() performance regression in 2025.1.0+

2 participants