NVIDIA / NVIDIA/cudf

[FEA] Reduce libcudf fatbin size by deduplicating equivalent CUDA kernel instantiations

Open
#23,419 2 comments 0 reactions 0 assignees View on GitHub
feature request Needs Triage
Dominant language
C++
Stars
9.8k
Forks
1.1k
Avg merge
3d 6m
Merged PRs (30d)
278

Description

**Is your feature request related to a problem? Please describe.**

`libcudf.so` is approximately 1.5 GiB in the current cudf-spark-jni package. A recent full Release build containing the supported CUDA architecture matrix measured:

- `libcudf.so`: 1,504,051,352 bytes
- `.nv_fatbin`: 1,061,134,960 bytes (70.55% of the library)
- 518 `fatbinData` blobs, commonly containing eight SASS images plus PTX

This size increases package storage, distribution, and native-library extraction time. It is particularly visible in Spark executor startup, where every executor may need to extract the bundled native library before CUDA initialization (NVIDIA/cudf-spark#15145).

Inspection of the largest fatbin blobs found that separate CUDA translation units often emit equivalent template kernel instantiations. The duplication is then repeated across the supported GPU architectures. Existing size-oriented fatbin compression reduces the byte representation but cannot remove these duplicate kernels.

**Describe the solution you'd like**

Deduplicate the highest-value equivalent kernel instantiations while preserving all supported GPU architectures and production symbols.

Three isolated CUDA object prototypes produced the following results:

| Candidate | Separate/specialized fatbins (`sm_75`) | Prototype fatbin (`sm_75`) | Measured saving | Estimated full-matrix saving |
|---|---:|---:|---:|---:|
| Co-locate stable and unstable segmented sort | 9,627,344 B | 4,815,528 B | 4,811,816 B (49.98%) | 18.32 MiB |
| Co-locate segmented standard deviation and variance | 4,540,088 B | 2,285,232 B | 2,254,856 B (49.67%) | 15.14 MiB |
| Share bounded-open and bounded-closed range-window kernel types | 7,790,032 B | 5,207,784 B | 2,582,248 B (33.15%) | 6.16 MiB |

The combined conservative estimate is 39.6 MiB, or 3.91% of `.nv_fatbin` and 2.76% of the complete library. The full-matrix values are estimates obtained by applying the measured one-architecture reduction ratio to the exact corresponding blobs in the full build; they still need confirmation with an all-architecture build.

All three prototypes compiled successfully with CUDA 12.9.1 and `CMAKE_CUDA_ARCHITECTURES=75`. The strong exported symbol set of each prototype matched the original object, or the union of the original objects for co-location tests.

Suggested implementations:

1. **Segmented sort:** Place the stable and unstable implementations from `src/sort/segmented_sort.cu` and `src/sort/stable_segmented_sort.cu` in one translation unit and remove the second source from the CMake source list. The prototype included both sources only as a measurement shortcut; a production change should move the definitions normally. Across all inspected architectures, 99.8-100% of the stable segmented-sort SASS was already present in the unstable blob. The stable PTX entry points were also a subset of the unstable PTX entry points, except for one additional unstable helper kernel.
2. **Segmented std/variance:** Place the two dispatch entry points currently in `src/reductions/segmented/std.cu` and `src/reductions/segmented/var.cu` in one translation unit. On `sm_75`, 96-98% of their SASS was identical by section name and contents.
3. **Range windows:** Remove `WindowType` from the template identity of `rolling::bounded_distance_functor` and pass open/closed as a uniform runtime flag or enum. In the `sm_75` cubin, the 72 bounded-open and 72 bounded-closed kernels each occupied 5.059 MiB; together they represented 81.3% of the TU's SASS. Sharing the kernel type collapses these to one family.

The first two should not change runtime GPU behavior. The range-window change adds a uniform branch to comparison logic, so it should only proceed with focused rolling benchmarks covering open/closed bounds, grouped/ungrouped inputs, nulls, and the supported data types.

A follow-up candidate is scalar standard deviation/variance. Their `sm_75` cubins have about 5.29 MiB of exactly overlapping SASS, suggesting roughly another 10 MiB at full architecture coverage, but this pair has not yet been compiled as a combined prototype and is not included in the estimate above.

**Describe alternatives you've considered**

- **Remove GPU architectures:** Not acceptable; all supported architectures must remain available.
- **Strip more symbols:** Does not address the dominant fatbin payload and would reduce production stack-trace quality.
- **Increase fatbin/JAR compression:** cuDF already calls `rapids_cuda_enable_fatbin_compression(... TUNE_FOR rapids)`. CUDA 13's size-oriented zstd fatbin compression should improve representation but does not eliminate equivalent instantiations.
- **Split large translation units:** This improves parallel build time but generally redistributes or duplicates device code instead of reducing the final binary. This goal needs to be balanced with the compile-time work in #21973.
- **Move the kernels to RTCX/LTO IR:** The infrastructure from #22496 is complementary and may produce larger long-term savings, but migrating ordinary libcudf kernels introduces runtime-linking and cache considerations. The source-level changes above are smaller AOT optimizations.

**Additional context**

Related work:

- NVIDIA/cudf-spark#15145 tracks executor startup latency, including native-library extraction of the approximately 1.5 GiB library.
- #21973 documents libcudf compile-time optimization and the build-time benefits of splitting translation units. Co-location changes proposed here should therefore measure both final binary size and the parallel build critical path.
- #22496 implemented the LTO IR infrastructure for deferred specialization and binary-size reduction.
- #17399 tracks broader JIT compilation of cuDF kernels.

Suggested validation for each change:

- Full Release build with the complete supported architecture matrix
- Compare `.nv_fatbin`, complete `libcudf.so`, and packaged artifact sizes
- Confirm exported symbols and run the affected unit tests
- Measure the CUDA compilation critical path
- Run focused NVBench coverage for any device-code type erasure, especially range rolling

Contributor guide

Open the contributing guide

Research direction

Start with src/sort/segmented_sort.cu, src/sort/stable_segmented_sort.cu, src/reductions/segmented/std.cu, and src/reductions/segmented/var.cu, then inspect the CMake source lists and the rolling bounded-distance implementation. Run an all-architecture Release build and the affected unit tests; for range windows, add focused NVBench coverage. Done means reduced .nv_fatbin and library sizes with exported symbols, GPU behavior, and the build critical path preserved.

Written by the indexing model from the issue text.

Assessment

Tech stack
cmake, cpp
Domain
build-system, performance
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.