Skip to content

Guard flow_length_dinf() against unbounded memory allocations (#1355)#1358

Merged
brendancol merged 1 commit into
mainfrom
issue-1355
Apr 29, 2026
Merged

Guard flow_length_dinf() against unbounded memory allocations (#1355)#1358
brendancol merged 1 commit into
mainfrom
issue-1355

Conversation

@brendancol
Copy link
Copy Markdown
Contributor

Closes #1355.

flow_length_dinf allocates several full-grid working arrays in its eager numpy and cupy backends with no upfront budget check. A 50000x50000 raster asks for ~72 GB of host RAM before anything errors out.

Adds _check_memory and _check_gpu_memory helpers, wired into the numpy and cupy dispatch in flow_length_dinf(). Dask paths are unchanged since per-tile allocations are bounded by chunk size. Same shape as #1332 (d8) and #1353 (mfd).

Budget

CPU: 29 B/px

Array dtype bytes/px
in_degree int32 4
valid int8 1
flow_len float64 8
order_r int64 8
order_c int64 8

GPU: 32 B/px (input float64 + output float64 + headroom).

Tests

Five new tests in TestMemoryGuard:

  • test_numpy_huge_raster_raises -- numpy backend raises MemoryError when _available_memory_bytes is patched to 1
  • test_numpy_normal_input_succeeds -- normal-size raster passes the guard
  • test_dask_path_skips_guard -- dask backend does not trigger the guard at dispatch
  • test_error_message_mentions_dimensions -- error mentions 7x9 and dask
  • test_cupy_huge_raster_raises -- cupy backend raises when GPU memory is patched low (gated on cuda_and_cupy_available)

Test plan

  • pytest xrspatial/hydro/tests/test_flow_length_dinf.py -- 30 passed
  • Full hydro suite -- 643 passed, only known flaky test_stream_link_dask_temp_cleanup failed

flow_length_dinf in xrspatial/hydro/ allocates several full-grid working
arrays in its eager numpy and cupy backends with no upfront budget
check. A 50000x50000 raster asks for about 72 GB of host RAM before
anything errors out.

Add _check_memory and _check_gpu_memory helpers wired into the numpy
and cupy dispatch paths in flow_length_dinf(), mirroring the d8 fix
in #1332 and the mfd fix in #1353. Dask path is left alone since
per-tile allocations are bounded by chunk size.

CPU budget: 29 B/px (in_degree int32 + valid int8 + flow_len float64
+ order_r int64 + order_c int64). GPU budget: 32 B/px conservative
(input float64 + output float64 + headroom).

Tests: oversize numpy raises, normal raster passes, dask backend
bypasses the guard, error message includes grid dimensions and the
'dask' hint, cupy gated on cuda_and_cupy_available.
@github-actions github-actions Bot added the performance PR touches performance-sensitive code label Apr 29, 2026
@brendancol brendancol merged commit a78f4e9 into main Apr 29, 2026
11 checks passed
@brendancol brendancol deleted the issue-1355 branch May 4, 2026 19:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance PR touches performance-sensitive code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

flow_length_dinf: no memory guard on H*W working arrays

1 participant