Skip to content

Build partition scatter maps with tile ranks and prefix scan - #8

Draft
res-life wants to merge 1 commit into
mainfrom
perf/partition-rank-scatter-draft
Draft

res-life wants to merge 1 commit into
mainfrom
perf/partition-rank-scatter-draft

Conversation

@res-life

@res-life res-life commented Nov 10, 2026 •

Copy link
Copy Markdown
Owner

Description

Multi-column STRING focus: 1.281x event speedup, or 21.9% lower partition time, across the 117 large synthetic STRING fixtures defined below.

cudf::partition uses a contended partition-cursor atomic increment per row to build its scatter map. For eligible inputs, save uint16 tile-local row ranks, scan partition-major tile counts, and emit scatter_map[input] = output without per-row cursor atomics. This replaces only map construction; generic result materialization is shared unchanged. The fallback preserves its original allocation order and keeps histogram/scratch buffers alive through materialization.

Independent split of NVIDIA/cudf#25154. One rank/scan algorithm, with no STRING materialization dependency. Both PRs can merge/revert independently and combine without conflicts.

CPU-only heuristic: N >= 1,000,000, 2 <= partitions <= 256, and at least 4 bytes of known output storage per row. Fixed-width sizes count directly; top-level STRING/LIST offsets or DICTIONARY32 indices count as 4 bytes; other nested storage conservatively contributes zero. Small tables, zero-column tables, narrow schemas and unsupported partition counts retain the histogram/cursor path. No device skew/length samples are used. The lower row boundary avoids measured small-input time regressions; the storage boundary avoids measured rank-state peak-memory regressions for 1/2-byte schemas.

291 additions + 52 deletions = 343 changed lines, including tests.

Companion independent draft: #7; both target main and neither depends on the other.

Performance

Primary workload: multi-column STRING

Across 117 large multi-column STRING fixtures, this PR gives 1.281x event-time speedup (21.9% lower partition time) and 1.280x wall-time speedup. This is the primary workload focus; the all-type aggregate is retained below as a regression/control result.

Scope: regular synthetic STRING tables with at least 1M rows, 2+ STRING columns and 2–256 partitions. Include every fixture in that scope, including nullable inputs and cases declined by this PR's heuristic. Baseline is 65b9b3c222 on NVIDIA L4; these are standalone cuDF partition microbenchmarks, not application-level benchmark results, and not incremental speedups over the complete NVIDIA#25154 implementation. Each fixture has equal weight in the geometric mean.

STRING column count Cases Event speedup Partition time reduction Wall speedup
2 53 1.411x 29.2% 1.410x
3 16 1.354x 26.1% 1.353x
4 20 1.223x 18.2% 1.222x
10 28 1.067x 6.3% 1.067x

Column-count groups contain different row/length/skew mixes; this table is not an isolated column-count scaling experiment.

Configured maximum string length (bytes) Cases Event speedup Partition time reduction Wall speedup
1–8 8 1.904x 47.5% 1.898x
9–128 67 1.321x 24.3% 1.320x
129–512 42 1.130x 11.5% 1.130x
Separate long-tail generator: mostly 0–8, max 512 4 1.744x 42.7% 1.737x

The regular-generator maximum is not a fixed per-row length. The long-tail row is a separate set, excluded from the 117-case headline. Nullable multi-STRING fixtures alone: 13 cases, 1.074x event speedup; the rank-map optimization retains generic STRING materialization.

Paired multi-STRING examples

Three alternating-order rounds, 30 samples per library per round. Times are medians of round medians; speedups are paired-round geometric means. The rows below are all five simultaneous-admission STRING cases in the final interaction cohort. The combined column includes both PRs; it is not this PR alone.

Rows / STRING columns / max bytes / partitions / map Baseline event ms This PR event ms This PR event speedup This PR wall speedup #7 + #8 event speedup
1,000,000 / 2 / 128 / 2 / 90% hot 2.8375 2.0311 1.386x 1.383x 1.775x
1,000,000 / 2 / 128 / 2 / uniform 2.9476 2.1591 1.368x 1.366x 1.839x
1,000,000 / 4 / 512 / 2 / uniform 14.0319 13.1057 1.072x 1.072x 1.411x
1,000,000 / 2 / 512 / 256 / 90% hot 7.3518 6.5182 1.135x 1.134x 1.467x
1,000,003 / 2 / long-tail ≤512 / 2 / 90% hot 1.3690 0.6938 1.970x 1.960x 4.223x

Across all seven interaction fixtures, no combined result declined by more than 5% against the best standalone version. Small-input retained-path latency flags remain documented below; these results do not establish universal per-case improvement.

Full matrix, retained-path flags and validation methodology
Measured subset Cases Event geomean speedup Wall geomean speedup
Original workloads 348 1.710x 1.697x
All final screening fixtures 497 1.575x 1.564x
Heuristic admits 332 1.979x 1.960x
Heuristic declines 165 0.995x 0.993x

Original heuristic families, with additional controls included:

Scenario family Cases Event speedup Wall speedup
Fixed width, no nulls 102 2.665x 2.618x
Fixed width, dense nulls (75%+) 45 2.498x 2.464x
STRING, no nulls 138 1.453x 1.449x
Empty / identity controls 47 1.025x 1.018x
Small inputs / partition boundary 88 0.977x 0.977x
Fixed width, other nulls 25 2.481x 2.441x
Uniform payload / zero columns 10 1.043x 1.034x
STRING, nullable 13 1.074x 1.074x
Mixed 13 1.405x 1.403x
Nested (LIST / STRUCT) 16 1.423x 1.419x

Screening: 0 admitted fixtures exceeded a 5% event or wall slowdown; 0 fixtures increased measured device peak by the 1% + 4 KiB reporting threshold. Focused validation repeated 43 selected fixtures in three alternating-order rounds of 30 samples per variant (baseline and this split); a separate interaction cohort compares baseline, each split and both. Repeated material slowdowns (>5%,>5us, at least 2 rounds): 2. All >5% ratio changes are retained in the report, including sub-5us changes.

Representative paired results (median of round medians; speedups use paired-round geometric means):

Fixture (N/P/C; length or width; map) Baseline event ms This PR event ms Event speedup Wall speedup Peak MiB, baseline → PR
strings-n1000000-p200-c10-w8-l128-z0-m0-d0-s0 12.5281 12.3115 1.017x 1.017x 690.87 → 690.74
strings-n1000000-p200-c10-w8-l128-z10-m0-d0-s0 11.9527 11.4516 1.042x 1.042x 629.73 → 629.60
fixed-n1000000-p2-c1-w8-l0-z0-m0-d2-s0 0.6922 0.0696 9.901x 9.148x 11.45 → 11.44
fixed-n1000000-p2-c1-w8-l0-z0-m0-d0-s0 0.6661 0.0715 8.901x 8.229x 11.45 → 11.44

Retained-path cases flagged by the repeat rule (these are not admitted by the new heuristic; causality remains unresolved):

Fixture Baseline event ms This PR event ms Paired event speedup Wall speedup
fixed-n1-p2-c2-w4-l0-z0-m1-d0-s7 0.1145 0.1609 0.830x 0.831x
lists-n1025-p2-c1-w8-l32-z0-m0-d0-s7 0.1434 0.1679 0.928x 0.931x

Small-input end-to-end nonregression is not established for every fixture. The full screen and paired repeats retain their slow cases above. Additional baseline A/A controls used CPU3, four rotated rounds and 100 samples on 13 selected fixtures; identical-baseline ratios ranged roughly 0.62–1.44. For one flagged fixed-width fallback (65,537 rows,P=2,C=8,I32,all-valid masks,sliced), Nsight Compute measured approximately 118.6 us total GPU kernel time for baseline and the split variants (<0.3% difference). Final rank removes the empty-map construction; CUPTI verifies that, in this profiled case, final rank and STRING fallback have the same runtime API counts as baseline (including 144 cudaGetDevice, 24 launches and 24 allocation/free pairs). These diagnostics separate the unchanged GPU work from variable CPU/API latency; they do not prove universal end-to-end improvement. Latest-upstream-main validation and stable-host latency confirmation remain before upstream review.

These drafts target res-life/cudf:main at the original NVIDIA/cudf#25154 baseline 65b9b3c222, which is also the measured base. Complete partition translation units, private headers and tests match the measured JNI sources after comments, formatting and include-order normalization. Separate ports to NVIDIA main 9efdb32adbd are prepared, but no latest-upstream-main build or performance claim is made.

All validation used an existing JNI checkout and its compatible build cache: unchanged common cuDF objects, separately rebuilt partition TU and relinked library per variant. NVIDIA L4, driver 595.71.05; CUDA 12.9.1, gcc-toolset 14, Release O3, sm89, PTDS, same RMM allocator and benchmark executable. Input construction and correctness checks are outside timing. >=150 ms warmup; 15 samples per fixture for screening. Event timing spans partition and output destruction, including CPU/GPU synchronization gaps; wall time additionally includes event recording and end synchronization. Speedups are baseline/candidate (larger is better). Peak memory means output plus temporary device allocations, excluding input/context/code caches and host pinned memory.

497 measured fixtures include all 348 original workloads, plus heuristic boundaries, schema/null/offset declines, long-tail STRING lengths, nested/zero-column/empty inputs. The rows above overlap; geometric means do not imply every input improves. Raw results retain per-case timings, samples, boundaries/schema/row-hash correctness, GPU-process isolation, loaded-library and artifact hashes. Only completed accepted runs contribute. Sliced STRUCT is excluded because the frozen baseline itself throws; unsliced STRUCT and sliced LIST/STRING/fixed-width remain covered. Disabled large-STRING threshold errors are covered by unit tests.

Validation

One typed test exercises all 8 supported integral map types at N=1,000,003; one table test checks CPU-expected grouping at N=999,999/1,000,000/1,000,003,P=2/16/256/257, uniform/all-hot/90%-hot maps and nullable sliced values. Existing tests cover zero columns, narrow types and nested fallback/materialization.

  • JNI PoC full PARTITIONING_TEST: 1,877 passed, 1 existing disabled.

  • STREAM_PARTITIONING_TEST with new-testing-default stream interposition: 7 passed.

  • 8 typed map tests at N=1,000,003 through memcheck and synccheck; racecheck on the shared-memory count kernel: zero errors/hazards. The I32 value schema admits the optimized path.

  • Combined PoC: 1,879 partition tests + 7 stream tests passed.

  • Standalone patches, both application orders, identical resulting sources, actual Git merges, formatting and whitespace checks passed.

  • No latest-upstream-main build/test claim; these fork drafts retain the validated original baseline.

  • Independently scoped change with focused tests.

  • Performance numbers and benchmark baseline/configuration recorded.

  • Latest-upstream-main build and stable-host latency validation complete.

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.

1 participant