rasterize: slice line_props/point_props per tile in dask backends (#2020)#2023
Conversation
) The dask backends embedded the full per-type props tables into every delayed tile task, despite the polygon path already filtering via poly_props[pmask]. For workloads with many localized geometries this amplified scheduler overhead by O(N_geoms * N_tiles). Adds _slice_props_for_tile that returns the subset of props referenced by a tile and a remapped local-index array. Wired into _run_dask_numpy and _run_dask_cupy alongside the existing segment / point tile filters. Measured: 5000 points x 8 cols / 100 tiles graph shrinks ~30 MB -> 0.3 MB; localized lines ~32 MB -> 1.1 MB. Dask + cupy parity verified.
PR Review: rasterize: slice line_props/point_props per tile in dask backends (#2020)Graph-payload fix that brings the line/point paths in line with what the polygon path already does. The new BlockersNone. Suggestions
Nits
What looks good
Checklist
|
Add an explicit straddling-line test that asserts a line crossing a tile seam renders on both sides. Fix the np.unique comment (inverse map is a new array, not in-place), normalise the empty-branch local_idx dtype to int32, and note in the cupy comment that for sprawling-line workloads the cost shifts from graph payload to per-tile PCIe uploads.
Closes #2020.
Summary
_run_dask_numpyand_run_dask_cupypreviously embedded the full per-typeline_propsandpoint_propstables in every delayed tile task closure, even though only a small subset of geometries hits any one tile. The polygon path already handles this correctly viapoly_props[pmask]; the line and point paths did not._slice_props_for_tilewhich slicespropsto the unique geom indices referenced by a tile and returns a remapped int32 local-index array. Wired it into both dask backends alongside the existing_segments_for_tile/_points_for_tilefilters._ensure_cupyupload the per-tile slice inside the worker. The previous driver-sidecupy.asarray(line_props)only saved redundant uploads when the same arrays were referenced across tasks; per-tile slicing trades that for far smaller graph payloads.Why
Without this fix the graph payload scales as O(N_geoms * N_tiles). At 5 000 points with 8 numeric columns across 100 tiles this puts ~30 MB of
point_propsduplicates in the graph; for localized lines under the same shape it is ~32 MB. Workers ship a tiny pixel-extent fix.Measured
Sprawling random lines that touch most tiles cannot benefit because every tile genuinely references most rows of
line_props; this is fundamental. The fix targets the realistic localized case.Tests
xrspatial/tests/test_rasterize_tile_props_slice_2020.py(9 new tests):TestSlicePropsForTile: empty input keeps column shape;sliced[local_idx]round-trips toprops[geom_idx]; duplicate geom indices compact to one row.TestDaskGraphPayloadBounded: pickled graph for 5 000 points / 5 000 localized lines stays under a few MB.TestDaskBackendOutputUnchanged: numpy vs dask outputs match exactly with lines + points, withmerge='sum', and with polygon-only input.All 184 existing rasterize tests pass. Dask + cupy parity confirmed end-to-end against the numpy backend on a mixed lines + points GeoDataFrame.
Test plan
pytest xrspatial/tests/test_rasterize.py xrspatial/tests/test_rasterize_accuracy.py xrspatial/tests/test_rasterize_tile_props_slice_2020.py(193 passed, 2 pre-existing skips)_scanline_fill_gpuresource probe: 39 regs/thread, 24 KB local mem/thread (unchanged)