Skip to content

Split cuda-cccl into headers, compute, and metapackage wheels - #10622

Open
tpn wants to merge 17 commits into
NVIDIA:mainfrom
tpn:codex/cuda-cccl-package-split
Open

Split cuda-cccl into headers, compute, and metapackage wheels#10622
tpn wants to merge 17 commits into
NVIDIA:mainfrom
tpn:codex/cuda-cccl-package-split

Conversation

@tpn

@tpn tpn commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Description

cuda.compute and the upcoming cuda.coop package both need the CCCL header payload. Keeping those headers inside the monolithic cuda-cccl distribution makes that payload hard to share without overlapping wheel ownership.

This PR assigns each payload to one distribution:

Distribution Imports Contents and dependency
cccl-headers cuda.cccl.headers and the existing cuda.cccl convenience exports libcudacxx, CUB, Thrust, and CUDAX headers; relocatable CMake packages; licenses. Depends only on cuda-pathfinder>=1.2.3.
cuda-compute Existing cuda.compute API Compute Python/native code and compute-owned HostJIT resources. Depends on the exact same version of cccl-headers.
cuda-cccl No owned modules Metapackage that depends on the exact same version of cuda-compute. Existing extras forward to the matching compute extras.

The split keeps cuda.cccl.headers, the cuda.cccl root exports, and cuda.compute intact. It removes the deprecated pre-1.0 cuda.cccl.parallel.experimental alias. Compute-private helpers and serialization version checks now live under cuda.compute, and serialized artifacts identify cuda-compute.

Upgrade from the monolithic wheel

Warning

Before installing this split for the first time, uninstall an older monolithic cuda-cccl wheel:

python -m pip uninstall -y cuda-cccl
python -m pip install cuda-cccl

The old wheel's RECORD owns paths that now belong to cccl-headers and cuda-compute. A direct in-place upgrade can let pip uninstall the old distribution after installing the new owners, deleting their files. Clean installs and later upgrades within the three-wheel layout do not have this problem.

CUDAX CMake package

The packaged CUDAX config keeps _cudax_cudax as a non-imported implementation target and exposes it through the global imported cudax::cudax target. This keeps wheel-provided headers out of the compiler's system-header search order and allows downstream install(EXPORT) sets to preserve cudax::cudax as an external dependency.

The target requires C++17, adds CUDA 17 when CUDA is enabled, and enables libcudacxx group features. Tests cover C++-only discovery, enabling CUDA after the first discovery, real CUDA compilation, repeated discovery, CCCL COMPONENTS cudax, and a fresh consumer of an installed downstream export.

HostJIT and release integration

The compute wheel owns generated Clang and minimal-CUDA HostJIT resources under cuda.compute, including the v2 library layout introduced by #9583. Wheel builds resolve those resources at runtime; standalone and editable builds retain their compile-time fallback paths.

Linux and Windows wheel jobs now build and test all three distributions. Release collection preserves every unique platform cuda-compute wheel, selects universal wheels from one deterministic Linux producer, and compares duplicate universal wheels by logical ZIP contents. The release validator checks coordinated versions, exact base dependencies, wheel tags, payload ownership, required header families, and zero cross-wheel overlap. Publication accepts artifacts only from a completed, successful, manually dispatched Python-wheel workflow in this repository.

Local validation

  • Built cccl-headers, cuda-cccl, and both v1/v2 cuda-compute wheels. All passed twine check, metadata, RECORD, license, native-content, absolute-path, and zero-overlap audits.
  • Rebuilt both universal wheels with a fixed SOURCE_DATE_EPOCH; both were byte-for-byte reproducible and tagged py3-none-any.
  • Installed headers, compute, and the transitive metapackage into isolated environments. pip check, public imports, header-family discovery, examples, serialization, and v2 HostJIT resource tests passed.
  • Ran installed-wheel CMake consumers with CMake 3.21.4 and 4.3.2, including the CUDAX export/install cases described above.
  • Ran representative v1 and v2 reductions on local SM75 and SM120 GPUs. The v1 serialization round trip passed on SM120.
  • Final focused suites passed: wheel scripts 12/12, metadata and merger tests 11/11, HostJIT path tests 3/3, both retained real coordinated wheel sets, full changed-file pre-commit, git diff --check, and signature verification for all 17 commits.

Exact reviewed head: 104733b67c855120da17acffaa23746977b6e2c0.

Remaining gates

Windows execution, ARM64, the full Python/CUDA Toolkit matrix, free-threading/TSan, and external CI remain PR gates. Package-name ownership and index publication are separate release gates; this work did not upload wheels or add a CI override.

Checklist

  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

@copy-pr-bot

copy-pr-bot Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@github-project-automation github-project-automation Bot moved this to Todo in CCCL Aug 4, 2026
@cccl-authenticator-app cccl-authenticator-app Bot moved this from Todo to In Progress in CCCL Aug 4, 2026
@tpn
tpn marked this pull request as ready for review August 4, 2026 06:55
@tpn
tpn requested review from a team as code owners August 4, 2026 06:55
Copilot AI lite review requested due to automatic review settings August 4, 2026 06:55
@tpn
tpn requested review from a team as code owners August 4, 2026 06:55
@tpn
tpn requested a review from gonidelis August 4, 2026 06:55
@tpn
tpn requested review from davebayer and jrhemstad August 4, 2026 06:55
@cccl-authenticator-app cccl-authenticator-app Bot moved this from In Progress to In Review in CCCL Aug 4, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Splits the monolithic cuda-cccl Python distribution into a coordinated set of wheels (cccl-headers, cuda-compute, and a cuda-cccl metapackage) while preserving the public import surface (cuda.cccl.headers, cuda.cccl convenience exports, and cuda.compute) and updating CI, docs, and CMake packaging accordingly.

Changes:

  • Introduces cccl-headers (header payload + CMake packages) and refactors cuda-compute to depend on it (plus new version/serialization tagging).
  • Converts cuda-cccl into a metapackage and updates wheel build/test/release workflows to validate coordinated wheel sets and ownership.
  • Updates CUDAX CMake targets to use a non-imported implementation target wrapped by a global imported target to avoid system-include precedence issues, with corresponding CMake tests.

Reviewed changes

Copilot reviewed 113 out of 295 changed files in this pull request and generated no comments.

Show a summary per file
File Description
test/cmake/test_export/CMakeLists.txt Adds assertions for CUDAX target wrapping, compile features, and compile definitions.
python/cuda_compute/tests/compute/test_merge_sort.py Updates package naming in NumPy-version comment.
python/cuda_compute/tests/compute/test_hostjit_paths.py Adds tests ensuring HostJIT path env vars resolve to compute-owned bundled resources and preserve explicit env vars.
python/cuda_compute/tests/compute/test_deferred_annotations.py Adds coverage for deferred annotations / future-annotations usage with gpu_struct and iterators.
python/cuda_compute/tests/compute/examples/unique/unique_by_key_basic.py Adds unique_by_key basic example.
python/cuda_compute/tests/compute/examples/unique/init.py Adds examples package marker for unique examples.
python/cuda_compute/tests/compute/examples/transform/unary_transform_object.py Adds unary transform object-API example.
python/cuda_compute/tests/compute/examples/transform/unary_transform_basic.py Adds unary transform basic example.
python/cuda_compute/tests/compute/examples/transform/binary_transform_object.py Adds binary transform object-API example.
python/cuda_compute/tests/compute/examples/transform/binary_transform_basic.py Adds binary transform basic example.
python/cuda_compute/tests/compute/examples/struct/struct_transform.py Adds transform example using custom gpu_struct types.
python/cuda_compute/tests/compute/examples/struct/struct_reduction.py Adds reduction example using custom gpu_struct types.
python/cuda_compute/tests/compute/examples/struct/init.py Adds examples package marker for struct examples.
python/cuda_compute/tests/compute/examples/sort/segmented_sort_basic.py Adds segmented sort example.
python/cuda_compute/tests/compute/examples/sort/radix_sort_object.py Adds radix sort object-API example.
python/cuda_compute/tests/compute/examples/sort/radix_sort_buffer.py Adds radix sort DoubleBuffer example.
python/cuda_compute/tests/compute/examples/sort/radix_sort_basic.py Adds radix sort basic example.
python/cuda_compute/tests/compute/examples/sort/merge_sort_object.py Adds merge sort object-API example.
python/cuda_compute/tests/compute/examples/sort/merge_sort_basic.py Adds merge sort basic example.
python/cuda_compute/tests/compute/examples/sort/init.py Adds examples package marker for sort examples.
python/cuda_compute/tests/compute/examples/serialization/ahead_of_time_compilation.py Adds AOT compilation example with clean v2 skip behavior.
python/cuda_compute/tests/compute/examples/serialization/init.py Adds examples package marker for serialization examples.
python/cuda_compute/tests/compute/examples/select/select_with_side_effect.py Adds select example demonstrating side effects (atomic counter).
python/cuda_compute/tests/compute/examples/select/select_with_iterator.py Adds select example using iterators.
python/cuda_compute/tests/compute/examples/select/select_basic.py Adds select basic example.
python/cuda_compute/tests/compute/examples/select/init.py Adds examples package marker for select examples.
python/cuda_compute/tests/compute/examples/segmented/segmented_reduce_object.py Adds segmented reduce object-API example.
python/cuda_compute/tests/compute/examples/segmented/segmented_reduce_basic.py Adds segmented reduce basic example.
python/cuda_compute/tests/compute/examples/segmented/init.py Adds examples package marker for segmented examples.
python/cuda_compute/tests/compute/examples/scan/running_average.py Adds inclusive-scan running-average example.
python/cuda_compute/tests/compute/examples/scan/inclusive_scan_object.py Adds inclusive scan object-API example.
python/cuda_compute/tests/compute/examples/scan/inclusive_scan_custom.py Adds inclusive scan custom-op example.
python/cuda_compute/tests/compute/examples/scan/exclusive_scan_object.py Adds exclusive scan object-API example.
python/cuda_compute/tests/compute/examples/scan/exclusive_scan_max.py Adds exclusive scan max-op example.
python/cuda_compute/tests/compute/examples/scan/init.py Adds examples package marker for scan examples.
python/cuda_compute/tests/compute/examples/reduction/sum_reduction.py Adds sum reduction example.
python/cuda_compute/tests/compute/examples/reduction/sum_reduction_lambda.py Adds sum reduction lambda example.
python/cuda_compute/tests/compute/examples/reduction/sum_custom_reduction.py Adds custom reduction example.
python/cuda_compute/tests/compute/examples/reduction/reduce_object.py Adds reduction object-API example.
python/cuda_compute/tests/compute/examples/reduction/minmax_reduction.py Adds min/max reduction example using gpu_struct.
python/cuda_compute/tests/compute/examples/reduction/min_reduction.py Adds min reduction example.
python/cuda_compute/tests/compute/examples/reduction/init.py Adds examples package marker for reduction examples.
python/cuda_compute/tests/compute/examples/raw_op/init.py Adds examples package marker for raw-op examples.
python/cuda_compute/tests/compute/examples/partition/three_way_partition_basic.py Adds three-way partition example.
python/cuda_compute/tests/compute/examples/partition/init.py Adds examples package marker for partition examples.
python/cuda_compute/tests/compute/examples/iterator/zip_iterator_reduction.py Adds zip-iterator reduction example.
python/cuda_compute/tests/compute/examples/iterator/zip_iterator_elementwise.py Adds zip-iterator elementwise example.
python/cuda_compute/tests/compute/examples/iterator/zip_iterator_counting.py Adds zip+counting iterator example.
python/cuda_compute/tests/compute/examples/iterator/transform_output_iterator.py Adds transform-output-iterator example.
python/cuda_compute/tests/compute/examples/iterator/transform_iterator_lambda.py Adds transform-iterator lambda example.
python/cuda_compute/tests/compute/examples/iterator/transform_iterator_basic.py Adds transform-iterator basic example.
python/cuda_compute/tests/compute/examples/iterator/shuffle_iterator_basic.py Adds shuffle-iterator example.
python/cuda_compute/tests/compute/examples/iterator/reverse_output_iterator.py Adds reverse-output-iterator example.
python/cuda_compute/tests/compute/examples/iterator/reverse_input_iterator.py Adds reverse-input-iterator example.
python/cuda_compute/tests/compute/examples/iterator/permutation_iterator_output.py Adds permutation iterator output (scatter) example.
python/cuda_compute/tests/compute/examples/iterator/permutation_iterator_composed.py Adds composed permutation+transform iterator example.
python/cuda_compute/tests/compute/examples/iterator/permutation_iterator_basic.py Adds permutation iterator basic example.
python/cuda_compute/tests/compute/examples/iterator/discard_iterator_basic.py Adds discard iterator example.
python/cuda_compute/tests/compute/examples/iterator/counting_iterator_basic.py Adds counting iterator example.
python/cuda_compute/tests/compute/examples/iterator/constant_iterator_basic.py Adds constant iterator example.
python/cuda_compute/tests/compute/examples/iterator/cache_modified_iterator_basic.py Adds cache-modified iterator example.
python/cuda_compute/tests/compute/examples/iterator/init.py Adds examples package marker for iterator examples.
python/cuda_compute/tests/compute/examples/histogram/histogram_even_basic.py Adds histogram-even basic example.
python/cuda_compute/tests/compute/examples/histogram/init.py Adds examples package marker for histogram examples.
python/cuda_compute/tests/compute/examples/free_threading/object_api.py Adds free-threading object-API example.
python/cuda_compute/tests/compute/examples/free_threading/direct_api.py Adds free-threading direct-API example.
python/cuda_compute/tests/compute/examples/free_threading/init.py Adds examples package marker for free-threading examples.
python/cuda_compute/tests/compute/examples/binary_search/upper_bound_object.py Adds upper_bound object-API example.
python/cuda_compute/tests/compute/examples/binary_search/upper_bound_basic.py Adds upper_bound basic example.
python/cuda_compute/tests/compute/examples/binary_search/lower_bound_object.py Adds lower_bound object-API example.
python/cuda_compute/tests/compute/examples/binary_search/lower_bound_basic.py Adds lower_bound basic example.
python/cuda_compute/tests/compute/examples/binary_search/init.py Adds examples package marker for binary-search examples.
python/cuda_compute/tests/_utils/device_array.py Updates test utility docstring to cuda-compute.
python/cuda_compute/tests/_utils/init.py Updates test utility package docstring to cuda-compute.
python/cuda_compute/cuda/compute/typing.py Adds public typing helpers/protocols for device arrays/streams/operators.
python/cuda_compute/cuda/compute/op.py Updates docs literalinclude path to new examples location.
python/cuda_compute/cuda/compute/iterators/_zip.py Updates docs literalinclude path to new examples location.
python/cuda_compute/cuda/compute/iterators/_utils.py Adds future-annotations helper module.
python/cuda_compute/cuda/compute/iterators/_transform.py Updates docs literalinclude paths to new examples location.
python/cuda_compute/cuda/compute/iterators/_shuffle.py Updates docs literalinclude path to new examples location.
python/cuda_compute/cuda/compute/iterators/_permutation.py Updates docs literalinclude path to new examples location.
python/cuda_compute/cuda/compute/iterators/_counting.py Updates docs literalinclude path to new examples location.
python/cuda_compute/cuda/compute/iterators/_constant.py Updates docs literalinclude path to new examples location.
python/cuda_compute/cuda/compute/iterators/_common.py Adds iterator common utilities (CUDA preamble + ensure_iterator).
python/cuda_compute/cuda/compute/iterators/init.py Adds iterator public exports for cuda.compute.iterators.
python/cuda_compute/cuda/compute/determinism.py Adds Determinism re-export module.
python/cuda_compute/cuda/compute/cccl/.gitkeep Preserves package directory structure.
python/cuda_compute/cuda/compute/algorithms/_unique_by_key.py Updates docs literalinclude paths to new examples location.
python/cuda_compute/cuda/compute/algorithms/_transform.py Updates docs literalinclude paths to new examples location.
python/cuda_compute/cuda/compute/algorithms/_three_way_partition.py Updates docs literalinclude paths to new examples location.
python/cuda_compute/cuda/compute/algorithms/_sort/_sort_common.py Adds shared sort utilities (SortOrder/DoubleBuffer/_get_arrays).
python/cuda_compute/cuda/compute/algorithms/_sort/_segmented_sort.py Hooks segmented sort into shared sort utilities and updated examples paths.
python/cuda_compute/cuda/compute/algorithms/_sort/_radix_sort.py Hooks radix sort into shared sort utilities and updated examples paths.
python/cuda_compute/cuda/compute/algorithms/_sort/_merge_sort.py Updates docs literalinclude path to new examples location.
python/cuda_compute/cuda/compute/algorithms/_sort/init.py Adds public sort module exports.
python/cuda_compute/cuda/compute/algorithms/_select.py Updates docs literalinclude paths to new examples location.
python/cuda_compute/cuda/compute/algorithms/_segmented_reduce.py Updates docs literalinclude paths to new examples location.
python/cuda_compute/cuda/compute/algorithms/_scan.py Updates docs literalinclude paths to new examples location.
python/cuda_compute/cuda/compute/algorithms/_reduce.py Updates docs literalinclude paths to new examples location.
python/cuda_compute/cuda/compute/algorithms/_histogram.py Updates docs literalinclude paths to new examples location.
python/cuda_compute/cuda/compute/algorithms/_binary_search.py Updates docs literalinclude paths to new examples location.
python/cuda_compute/cuda/compute/_version.py Adds cuda-compute distribution version lookup for runtime/serialization tagging.
python/cuda_compute/cuda/compute/_utils/init.py Adds identifier sanitization helper for JIT symbol naming.
python/cuda_compute/cuda/compute/_target_cc.py Adds context-local target-cc plumbing for multi-arch builds.
python/cuda_compute/cuda/compute/_serialization/dispatch.py Adds public serialize/deserialize entry points and concurrency warning.
python/cuda_compute/cuda/compute/_serialization/codec.py Switches serialization version stamping/messages to cuda-compute.
python/cuda_compute/cuda/compute/_serialization/init.py Adds serialization public exports.
python/cuda_compute/cuda/compute/_nvtx.py (Touched) NVTX integration placeholder/module.
python/cuda_compute/cuda/compute/_device_code.py Adds DeviceCode wrapper type for op code blobs.
python/cuda_compute/cuda/compute/_cuda_version_utils.py Improves missing cuda.bindings error message to reference cuda-compute extras.
python/cuda_compute/cuda/compute/_cpp_compile.py Switches include-path discovery to cuda.cccl.headers.
python/cuda_compute/cuda/compute/_cccl_interop.py Switches include-path discovery to cuda.cccl.headers.
python/cuda_compute/cuda/compute/_bindings_segmented_reduce_backend_v2.pxi Adds HostJIT (v2) segmented-reduce call helper shim.
python/cuda_compute/cuda/compute/_bindings_segmented_reduce_backend_v1.pxi Adds v1 segmented-reduce call helper shim.
python/cuda_compute/cuda/compute/_bindings_op_code_type_v2.pxi Adds v2 op-code-type enum parsing including LLVM IR.
python/cuda_compute/cuda/compute/_bindings_op_code_type_v1.pxi Adds v1 op-code-type enum parsing.
python/cuda_compute/cuda/compute/_bindings_binary_search_backend_v2.pxi Adds v2 binary-search build-result helper.
python/cuda_compute/cuda/compute/_bindings_binary_search_backend_v1.pxi Adds v1 binary-search build-result helper.
python/cuda_compute/cuda/compute/init.py Adds __version__ export and updates HostJIT bundle path logic to compute-owned _hostjit.
python/cuda_compute/benchmarks/compute/transform/fill.py Adds Python benchmark for fill via ConstantIterator + unary transform.
python/cuda_compute/benchmarks/compute/README.md Updates benchmark docs for cuda-compute / cccl-headers split.
python/cuda_compute/benchmarks/compute/pixi.toml Updates pixi environments/deps to install cuda-compute and local cccl-headers.
python/cuda_compute/benchmarks/compute/AGENTS.md Updates contributor guidance paths for split package layout.
python/cuda_compute/benchmarks/compute/.gitignore Adds ignores for benchmark build/results/pixi artifacts.
python/cuda_compute/.gitignore Adds standard Python/CMake ignore patterns for the new project layout.
python/cuda_cccl/tests/test_cuda_cccl_metadata.py Adds tests asserting the metapackage has no Python payload and forwards extras/version-pinned deps.
python/cuda_cccl/tests/headers/test_cuda_cccl.py Removes old header tests from metapackage tree (now owned by cccl-headers).
python/cuda_cccl/LICENSE Removes redundant LICENSE pointer file from metapackage project.
python/cuda_cccl/cuda/cccl/parallel/experimental/init.py Removes deprecated cuda.cccl.parallel.experimental alias module.
python/cuda_cccl/cuda/cccl/parallel/init.py Removes cuda.cccl.parallel package wrapper.
python/cuda_cccl/cuda/cccl/headers/include/init.py Removes old header payload marker from metapackage tree.
python/cuda_cccl/cuda/cccl/headers/include_paths.py Removes old include-path helper (migrated to cccl-headers).
python/cuda_cccl/cuda/cccl/headers/init.py Removes old headers package init (migrated to cccl-headers).
python/cuda_cccl/cuda/cccl/init.py Removes old cuda.cccl implementation from metapackage tree.
python/cuda_cccl/.gitignore Simplifies ignore list for metapackage project.
python/cccl_headers/README.md Adds cccl-headers package overview and usage snippet.
python/cccl_headers/cuda/cccl/py.typed Marks cuda.cccl typing support for cccl-headers.
python/cccl_headers/cuda/cccl/headers/include/init.py Adds header payload root marker for bundled headers.
python/cccl_headers/cuda/cccl/headers/include_paths.py Adds include-path discovery implementation using cuda-pathfinder.
python/cccl_headers/cuda/cccl/headers/init.py Adds cccl-headers public API (IncludePaths, get_include_paths, __version__).
python/cccl_headers/cuda/cccl/init.py Adds convenience exports from cuda.cccl for header distribution.
python/cccl_headers/CMakeLists.txt Adds language-free install-only CMake project for packaging headers/CMake configs/licenses.
lib/cmake/cudax/cudax-config.cmake Reworks CUDAX target to wrap non-imported implementation in imported global target; adds CUDA feature enablement when CUDA language enabled.
lib/cmake/cccl/cccl-config.cmake Simplifies CUDAX aliasing to point at the public wrapper target.
docs/python/resources.rst Updates examples link and setup guidance for split wheel installs.
docs/python/index.rst Documents split distributions and adds headers API entry point.
docs/python/headers_api.rst Adds autodoc page for cuda.cccl.headers.
docs/python/compute/developer_overview.rst Updates source-tree path references for compute + headers packages.
docs/python/api_reference.rst Adds headers API to docs toctree.
docs/conf.py Updates autodoc sys.path setup to include both cuda_compute and cccl_headers trees.
ci/windows/test_cuda_compute_python.ps1 Updates Windows compute lane to install coordinated wheelhouse and validate no implicit metapackage install.
ci/windows/test_cuda_compute_minimal_python.ps1 Updates Windows minimal compute lane to install headers + compute from wheelhouse and run tests.
ci/windows/test_cuda_cccl_headers_python.ps1 Updates Windows headers lane to install only cccl-headers and run its tests.
ci/windows/test_cuda_cccl_examples_python.ps1 Updates examples lane to install coordinated wheels and run compute examples + benchmark smoke test.
ci/windows/build_common_python.psm1 Refactors wheelhouse helpers to locate coordinated wheels (headers/compute/meta).
ci/util/workflow/get_wheel_artifact_name.sh Fixes missing echo and treats null job fields as missing.
ci/update_version.sh Removes update hook for deleted monolithic cuda.cccl version file.
ci/test/python_wheels/CMakeLists.txt Adds CI test to run wheel artifact collection/validation scripts.
ci/test/inspect_changes/python_cuda_compute.output Adds inspect_changes golden output for cuda_compute project.
ci/test/inspect_changes/python_cuda_compute.dirty_files Adds inspect_changes dirty-files list for cuda_compute project.
ci/test/inspect_changes/python_cccl_headers.output Adds inspect_changes golden output for cccl_headers project.
ci/test/inspect_changes/python_cccl_headers.dirty_files Adds inspect_changes dirty-files list for cccl_headers project.
ci/test/CMakeLists.txt Registers new python_wheels CI test subdirectory.
ci/test_python_common.sh Updates local CI install constraints to include all three coordinated projects.
ci/test_cuda_compute_minimal_python.sh Updates Linux minimal compute lane to install headers + compute from wheelhouse and run tests.
ci/test_cuda_compute_minimal_python_tsan.sh Updates TSan lane to install headers + compute and run free-threaded tests under TSan.
ci/test_cuda_cccl_headers_python.sh Updates Linux headers lane to install only cccl-headers and run its tests from outside the source tree.
ci/project_files_and_dependencies.yaml Updates Python project dependency graph and include regexes to cover split projects and CUDAX public changes.
ci/matrix.yaml Renames Python wheel build job and updates examples job naming.
ci/generate_version.sh Adds strict bash flags and makes JSON path robust relative to CI directory.
ci/build_cuda_cccl_wheel.sh Updates wheel build script to produce coordinated wheelhouse (universal headers/meta + platform compute) with reproducibility support.
ci/build_cuda_cccl_python_v2.sh Updates wrapper comment for v2 HostJIT build to reflect new compute wheel target.
ci/build_cuda_cccl_python_tsan.sh Updates wrapper comment for TSan build to reflect new compute wheel target.
ci/bench/README.md Updates benchmark infra docs to handle pre/post split layouts.
c/parallel.v2/src/hostjit/libnvcc/CMakeLists.txt Gates embedding build-tree HostJIT paths behind a new runtime-paths option.
c/parallel.v2/CMakeLists.txt Adds option to use runtime HostJIT resource paths rather than embedded build-tree defaults.
.pre-commit-config.yaml Splits mypy into separate hooks for cuda.compute and cuda.cccl.headers projects.
.github/workflows/release-wheels.yml Tightens release workflow: validates trusted wheel run, collects coordinated wheels, validates set before publish.
.github/workflows/ci-workflow-pull-request.yml Updates CI smoke install to install coordinated wheels (headers/compute/meta) and run pip check.
.coderabbit.yaml Broadens review focus instructions to cover all Python paths.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
docs/python/setup.rst (1)

25-30: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Correct the CUDA Toolkit prerequisite.

Lines 25-30 require a preinstalled Toolkit. Lines 45-46 state that cu12 and cu13 install cuda-toolkit. State that users need either a cu* extra or a compatible system Toolkit. Reserve the system Toolkit prerequisite for sysctk* variants.

ci/windows/build_cuda_cccl_python.ps1 (1)

255-272: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

important: forward the coordinated version and SOURCE_DATE_EPOCH into the nested CUDA 13 container.

Lines 83-114 state the intent that the outer build, the nested CUDA 13 build, and the universal wheel builds share one version. The nested invocation does not pass SETUPTOOLS_SCM_PRETEND_VERSION_FOR_CUDA_COMPUTE or SOURCE_DATE_EPOCH. The nested script therefore re-derives both from git inside the CUDA 13 image. Any difference in git state, tag visibility, or safe.directory handling in that image produces a different compute wheel version, and the merge step then combines mismatched versions. Forwarding the values also removes the redundant unshallow and version generation in the nested container.

Proposed fix
         '--env', "CCCL_PYTHON_USE_V2=$($env:CCCL_PYTHON_USE_V2)",
+        '--env', "SETUPTOOLS_SCM_PRETEND_VERSION_FOR_CUDA_COMPUTE=$($env:SETUPTOOLS_SCM_PRETEND_VERSION_FOR_CUDA_COMPUTE)",
+        '--env', "SOURCE_DATE_EPOCH=$($env:SOURCE_DATE_EPOCH)",
         $Cuda13Image,
🟠 Major comments (30)
.github/workflows/release-wheels.yml-67-82 (1)

67-82: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Missing Branch Authorization (CWE-862): Missing Authorization

Reachability: Internal · Exploitability: Moderate

important: Restrict accepted runs to approved release branches. The workflow currently accepts successful workflow_dispatch runs from any branch, so a feature-branch build can reach the PyPI publish step. Add an allowlist for .head_branch, such as main and approved branch/{major}.{minor}.x branches.

ci/test/python_wheels/test_wheel_scripts.py-512-525 (1)

512-525: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

important: the post-uninstall isolation check depends on undefined behavior and can fail for the wrong reason.

importlib.util.find_spec('cuda.compute') imports the parent package cuda first. The old metapackage is the only distribution that provides cuda/, so after the uninstall two outcomes are possible:

  • pip removes the now-empty directories. import cuda then fails and find_spec raises ModuleNotFoundError instead of returning None. check=True reports a test failure.
  • pip leaves the empty cuda/compute/ directory. That directory resolves as a namespace package, so find_spec returns a spec and the assertion fails.

pip does not guarantee either outcome, so this assertion does not reliably test what it intends. Assert that no importable module with a loader remains, and treat a missing parent as success.

Proposed fix
-                    (
-                        "import importlib.util; "
-                        "assert importlib.util.find_spec('cuda.compute') is None; "
-                        "assert importlib.util.find_spec('cuda.cccl') is None"
-                    ),
+                    (
+                        "import importlib.util\n"
+                        "def gone(name):\n"
+                        "    try:\n"
+                        "        spec = importlib.util.find_spec(name)\n"
+                        "    except ModuleNotFoundError:\n"
+                        "        return True\n"
+                        "    return spec is None or spec.loader is None\n"
+                        "assert gone('cuda.compute')\n"
+                        "assert gone('cuda.cccl')\n"
+                    ),
python/cuda_compute/benchmarks/compute/scan/exclusive/sum.py-82-82 (1)

82-82: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

important: Limit the default element-count axis.

The exponent 32 creates 2^32 elements. Input and output alone require 32 GiB for 32-bit types and 64 GiB for 64-bit types. Temporary storage increases this requirement.

Cap the default axis or skip cases that exceed available GPU memory. Otherwise, a normal unfiltered run can terminate before it records the smaller cases.

As per path instructions, benchmark changes must avoid excessive runtime and preserve useful comparison data.

Source: Path instructions

python/cuda_compute/benchmarks/compute/utils.py-53-67 (1)

53-67: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Keep float64 interpolation finite.

For np.float64, max_val - min_val overflows to inf. Production probabilities then produce inf or nan, causing incorrect select thresholds. Use (1.0 - probability) * min_val + probability * max_val.

Source: Path instructions

python/cuda_compute/tests/compute/test_no_numba.py-268-270 (1)

268-270: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: cuda-compute declares numpy without a lower bound, so NumPy 1.x remains supported. Use np.argsort(h_keys, kind="stable"); stable=True raises TypeError on NumPy 1.x.

python/cuda_compute/tests/compute/test_radix_sort.py-322-324 (1)

322-324: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: both bit-window tests use dtype().itemsize as a bit count. itemsize is a byte count, so the begin/end bit sets stay within 0..8 and high key bits are never sorted. host_sort repeats the same bounds, so the assertions pass and the coverage loss is silent.

  • python/cuda_compute/tests/compute/test_radix_sort.py#L322-L324: change num_bits = dtype().itemsize to dtype().itemsize * 8 in test_radix_sort_pairs_bit_window.
  • python/cuda_compute/tests/compute/test_radix_sort.py#L377-L379: apply the same change in test_radix_sort_pairs_double_buffer_bit_window.
python/cuda_compute/tests/test_examples.py-119-127 (1)

119-127: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

important: subprocess.run has no timeout. If an example hangs, the whole test session hangs until the CI job is killed. Add a timeout and report it as a failure.

                     result = subprocess.run(
                         [sys.executable, module_file],
                         capture_output=True,
                         text=True,
                         cwd=os.path.dirname(module_file),
+                        timeout=600,
                     )
python/cccl_headers/cuda/cccl/headers/include_paths.py-16-23 (1)

16-23: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Make the cached IncludePaths value immutable.

get_include_paths returns the same mutable object for each cached probe_file. One caller can modify a field and corrupt the include paths returned to later callers.

Declare the dataclass with @dataclass(frozen=True), or cache immutable path values and construct a new result for each call.

Also applies to: 50-64

Source: Path instructions

python/cuda_compute/cuda/compute/_bindings_impl.pyx-236-236 (1)

236-236: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

important: Add except NULL to get_buffer_pointer

When PyObject_GetBuffer fails, callers receive NULL without the Python exception being propagated. ctypes_typed_pointer_payload_ptr can then dereference ptr_ref[0] and crash.

python/cuda_compute/cuda/compute/_jit.py-826-837 (1)

826-837: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

important: the try block catches only OSError and TypeError. Two other failures are reachable here. ast.parse raises SyntaxError when the retrieved source is not a standalone statement, which happens for a lambda: inspect.getsource returns the enclosing call expression, and func.__name__ is <lambda>, so Line 866 would also raise KeyError. to_jit_op_adapter routes any callable with captured device arrays through this function, so a lambda that closes over a device array reaches it. Wrap parse and lookup failures in the same actionable ValueError, or reject non-def callables with an explicit message.

python/cuda_compute/cuda/compute/_jit.py-668-674 (1)

668-674: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

important: both OpAdapter subclasses implement __eq__ by dereferencing attributes on other with no type check. Python calls __eq__ on hash collisions inside dicts and sets, and both classes are registered as cache-key providers at Line 1046 and Line 1048. A collision with any foreign key type raises AttributeError instead of returning NotImplemented.

  • python/cuda_compute/cuda/compute/_jit.py#L668-L674: guard _StatelessOp.__eq__ with isinstance(other, _StatelessOp) and return NotImplemented otherwise.
  • python/cuda_compute/cuda/compute/_jit.py#L1027-L1031: guard _StatefulOp.__eq__ with isinstance(other, _StatefulOp) and return NotImplemented otherwise.
python/cuda_compute/tests/compute/test_three_way_partition.py-48-50 (1)

48-50: 🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

important: this builds 77 parameterizations, and log_size 16 and 20 run 65K and 1M element partitions for all 11 dtypes. Each case compiles two custom operators. The sibling test_unique_by_key.py marks sizes at or above 2**20 with pytest.mark.large through get_mark. Apply the same marking here so a default CI run does not pay for 11 million-element partitions.

Source: Path instructions

python/cuda_compute/tests/compute/test_unique_by_key.py-143-144 (1)

143-144: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: both test files define their own random_array helper that accepts max_value but applies it only to integral dtypes. For every floating-point dtype the helper returns values in [0, 1), so the callers' value-based predicates and equality checks degenerate and the float parameterizations lose their coverage. Fix the helper in both places, or move one corrected helper into tests/_utils.

  • python/cuda_compute/tests/compute/test_unique_by_key.py#L143-L144: scale the float keys into a small integral range so consecutive duplicate keys occur and the de-duplication path runs.
  • python/cuda_compute/tests/compute/test_three_way_partition.py#L87-L93: scale the float inputs across the 42 threshold so the float cases produce all three partitions.
python/cuda_compute/benchmarks/compute/.gitignore-17-19 (1)

17-19: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

important: ignoring pixi.lock leaves the benchmark environment unpinned. A benchmark run on one machine can then resolve different dependency versions than another, which invalidates cross-run performance comparison. The benchmarking conventions require reproducible runs and comparable results. Commit pixi.lock and ignore only .pixi/.

 # Pixi
 .pixi/
-pixi.lock

As per path instructions: "Check that benchmark changes measure meaningful workloads, keep axes comparable, avoid excessive runtime, and preserve useful comparison data."

Source: Path instructions

python/cccl_headers/tests/test_cccl_headers.py-249-252 (1)

249-252: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Line 250, Line 251, Line 293, Line 294, and Line 295 pass CMake cache values through .as_posix(), but Line 249 and Line 252 interpolate the raw Path. On Windows str(Path) produces backslashes, and CMake treats a backslash in a cache value as an escape. The result is a broken cudax_DIR and CMAKE_INSTALL_PREFIX. Use .as_posix() for both.

-                f"-Dcudax_DIR={cudax_cmake_dir}",
+                f"-Dcudax_DIR={cudax_cmake_dir.as_posix()}",
                 f"-DCCCL_DIR={(package_root / 'lib' / 'cmake' / 'cccl').as_posix()}",
                 f"-DEXPECTED_CUDAX_INCLUDE={(package_root / 'include').as_posix()}",
-                f"-DCMAKE_INSTALL_PREFIX={build_dir / 'install'}",
+                f"-DCMAKE_INSTALL_PREFIX={(build_dir / 'install').as_posix()}",
python/cuda_compute/cuda/compute/struct.py-97-107 (1)

97-107: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Do not discard constructor arguments. Positional arguments cause all keyword arguments to be ignored. A dictionary first argument also causes trailing positional arguments to be ignored. Reject unsupported mixes, or merge them with duplicate and missing-field validation.

python/cuda_compute/cuda/compute/struct.py-146-163 (1)

146-163: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Add coercion for declared TypeDescriptor fields. _field_spec_to_type_descriptors accepts types.TypeDescriptor, but _coerce_value has no matching branch. gpu_struct({"x": types.int32})(1) reaches the fallback and raises AttributeError. Validate nested struct classes before accepting them, and coerce descriptors through field_type.dtype.type(...).

python/cuda_compute/cuda/compute/types.py-74-80 (1)

74-80: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

important: Freeze the field mapping at construction. StructTypeDescriptor stores and exposes the caller’s mutable dictionary, while equality, hashing, and layout_key() read it. A later mutation changes cache identity while _dtype remains unchanged. Copy the mapping and expose an immutable view.

Also applies to: 90-108

python/cuda_compute/cuda/compute/types.py-260-265 (1)

260-265: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Collect every annotated positional parameter. The break leaves input_tds with only the first annotated parameter. A multi-argument operator then gets a truncated signature. Remove the break and define explicit handling for missing annotations.

python/cuda_compute/cuda/compute/types.py-171-179 (1)

171-179: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

important: Preserve structured-dtype layouts

from_numpy_dtype() and gpu_struct() rebuild structured dtypes from field types with align=True. This discards source offsets and itemsize, so packed or explicitly padded dtypes can receive a different record ABI. Preserve the source layout, or reject unsupported layouts, in both paths. gpu_struct() must also handle title aliases without treating them as additional fields.

ci/windows/test_cuda_compute_python.ps1-29-38 (1)

29-38: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

important: Install only "$wheelPath[test-$ctkFlavor$cudaMajor]" and let pip resolve cccl-headers from $wheelhouse. The current command installs $headersWheelPath separately, so the import assertion cannot detect a missing dependency in cuda-compute. Run this check in a fresh environment and assert the installed cccl-headers distribution.

python/cuda_compute/cuda/compute/iterators/_discard.py-70-84 (1)

70-84: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Do not expose the discard iterator as input-capable. This no-op operation does not write result, but IteratorBase treats its non-None return as a valid input dereference. An algorithm that receives DiscardIterator as d_in reads uninitialized device data. Return None here so input conversion fails.

python/cuda_compute/cuda/compute/iterators/_reverse.py-37-41 (1)

37-41: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

important: Define empty-array behavior before calculating size - 1. For an empty device array, this creates a PointerIterator at -1 elements and serializes a pointer before the allocation. Reject the input or use a valid empty-range representation.

python/cuda_compute/cuda/compute/iterators/_reverse.py-139-140 (1)

139-140: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Negate the host-side offset. The class contract and _make_advance_op() move positive offsets backward. This method moves the wrapped iterator forward instead. For an array-backed iterator, ReverseIterator(array) + 1 points one element past the end instead of at the preceding element.

python/cuda_compute/cuda/compute/iterators/_base.py-76-81 (1)

76-81: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Resolve the implicit iterator cache key to the current compute capability. When USING_V2 is false, get_target_cc() returns None for default builds, and all three accessors use None as the cache key. Switching devices can reuse the first device's incompatible LTO-IR.

python/cuda_compute/cuda/compute/iterators/_cache_modified.py-69-78 (1)

69-78: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Reject descriptors without a generated C++ type. A 4-byte structured dtype passes the size check, but cpp_type_from_descriptor() returns None, producing static_cast<None**> and a JIT compilation failure.

python/cuda_compute/cuda/compute/iterators/_cache_modified.py-96-100 (1)

96-100: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Use int64_t for the advance distance. ReverseIterator passes a negative int64_t to the wrapped iterator. Reading it as uint64_t converts -n to 2^64 - n, causing an invalid positive pointer adjustment.

python/cuda_compute/cuda/compute/_utils/temp_storage_buffer.py-20-40 (1)

20-40: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

important: Bind memory-pool configuration and default-stream cleanup to the allocation device. When stream targets another device, _set_default_mempool_threshold(dev.device_id) configures the wrong pool. When stream is None, finalization can enqueue cudaFreeAsync on another thread's default device and leave the allocation reserved after the warning. Store the allocation device and preserve the allocation stream or device for cleanup. Add multi-GPU tests for cross-device streams and cross-thread finalization.

ci/windows/test_cuda_compute_minimal_python.ps1-29-37 (1)

29-37: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

important: Do not pass $headersWheelPath as a direct install target. The command installs cccl-headers even if the cuda-compute wheel omits its required dependency. Because pip check validates declared installed dependencies, it cannot detect that omission. Install only "$wheelPath[minimal-$ctkFlavor$cudaMajor]" with --find-links $wheelhouse, then assert that the resolver installed the matching cccl-headers distribution. (pip.pypa.io)

Based on PR objectives, the split requires dependency validation across the wheel set.

python/cuda_compute/README.md-17-19 (1)

17-19: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Add the required cleanup and reinstall procedure to the installation section. The README directs existing aggregate users to continue installing cuda-cccl but does not provide the required migration from the monolithic wheel. Users can otherwise retain files from the old wheel-ownership layout. As per PR objectives, the split requires an uninstall/reinstall procedure when users upgrade from the monolithic wheel.

🟡 Minor comments (21)
docs/python/compute/index.rst-311-311 (1)

311-311: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Quote the package extras in these installation commands.

Unquoted square brackets can be interpreted as pathname patterns by the shell. Use quoted requirements such as pip install 'cuda-compute[minimal-cu13]' and pip install 'cuda-compute[minimal-sysctk13]'.

Also applies to: 541-542

Source: Path instructions

ci/util/python/validate_cccl_wheel_set.py-71-75 (1)

71-75: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

important: Parse extra markers instead of matching one rendered form. A valid marker such as (python_version < "3.11") and extra == "test" or a changed version bound is classified as unconditional, which can block wheel validation. Use a complete marker parser and add regression tests for these forms.

python/cuda_compute/benchmarks/compute/partition/three_way.py-67-68 (1)

67-68: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

important: Report both counter writes. d_num_selected_out stores two counters, but the accounting reports one. Use 2 * d_num_selected_out.dtype.itemsize to match C++ add_global_memory_writes<offset_t>(2). np.int32 is a supported output dtype and does not cause an out-of-bounds write.

python/cuda_compute/tests/compute/examples/sort/radix_sort_basic.py-45-47 (1)

45-47: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

important: Replace stable=True with kind="stable" in both sort examples. python/cuda_compute/pyproject.toml declares numpy without a minimum version, and NumPy 1.x raises TypeError for stable=True.

python/cuda_compute/benchmarks/compute/segmented_reduce/variable_sum.py-118-118 (1)

118-118: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Report both offset arrays in segmented-operation metrics.

Both benchmarks pass separate start and end offset arrays but report traffic for one contiguous num_segments + 1 array.

  • python/cuda_compute/benchmarks/compute/segmented_reduce/variable_sum.py#L118-L118: report 2 * num_segments * start_offsets.dtype.itemsize.
  • python/cuda_compute/benchmarks/compute/segmented_sort/keys.py#L126-L126: report 2 * num_segments * start_offsets.dtype.itemsize.

As per path instructions, benchmark results must preserve useful comparison data.

Source: Path instructions

python/cuda_compute/tests/compute/examples/select/select_object.py-57-78 (1)

57-78: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Validate every demonstrated selection result.

Both examples execute and retrieve an output that the assertions do not validate.

  • python/cuda_compute/tests/compute/examples/select/select_object.py#L57-L78: assert the second selected count and values.
  • python/cuda_compute/tests/compute/examples/select/select_with_side_effect.py#L39-L54: assert the selected even values, not only the counts.
python/cuda_compute/tests/compute/examples/sort/radix_sort_buffer.py-21-23 (1)

21-23: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

suggestion: 8.3 - 1 in the literal list looks like a typo for 8.3, -1. The list still has 10 entries, so the example passes, but a reader of a public example will stop here. Replace it with the intended literal.

 h_in_values = np.array(
-    [-3.2, 2.2, 1.9, 4.0, -3.9, 2.7, 0, 8.3 - 1, 2.9, 5.4], dtype="float32"
+    [-3.2, 2.2, 1.9, 4.0, -3.9, 2.7, 0, 7.3, 2.9, 5.4], dtype="float32"
 )
python/cuda_compute/benchmarks/compute/transform/complex_cmp.py-84-86 (1)

84-86: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: the write accounting is off by one element. The transform writes num_items = num_elements - 1 booleans, but line 86 charges num_elements. Use num_items so the reported write bandwidth matches the C++ benchmark.

     state.add_element_count(num_elements)
     state.add_global_memory_reads(num_elements * d_in.dtype.itemsize)
-    state.add_global_memory_writes(num_elements * d_out.dtype.itemsize)
+    state.add_global_memory_writes(num_items * d_out.dtype.itemsize)

Note num_items is currently defined at line 79, after this block would need it; move the assignment above state.add_element_count.

Source: Path instructions

python/cuda_compute/tests/compute/examples/sort/radix_sort_buffer.py-49-49 (1)

49-49: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

important: Use kind="stable" or require NumPy 2.0+. cuda-compute declares an unconstrained numpy dependency, so NumPy 1.x remains possible; stable=True raises TypeError there.

python/cuda_compute/tests/compute/test_reduce.py-473-487 (1)

473-487: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: This block builds reducer_1 and reducer_2 for two identical-body ops with different names, then never asserts anything. The case is dead code and covers nothing.

Add the expected assertion. Based on the neighbouring cases and the comment, ops with the same body but different names should map to the same cached reducer:

     reducer_2 = cuda.compute.make_reduce_into(
         d_in=TransformIterator(CountingIterator(np.int32(0)), op3),
         d_out=DeviceArray.empty(1, dtype="int64"),
         op=sum_op,
         h_init=np.zeros(1, dtype="int64"),
     )
+    assert reducer_1 is reducer_2

If the intended behaviour is the opposite, use is not instead. Confirm the caching contract before choosing.

python/cuda_compute/tests/compute/examples/raw_op/llvm_stateless.py-13-22 (1)

13-22: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

important: Exclude llvmlite 0.43.x from the example test dependencies or rewrite the IR with typed pointers. llvmlite 0.43.x does not support the opaque ptr syntax used here. The example runner already handles sys.exit(0), and llvm.initialize() is not required by current llvmlite releases.

python/cuda_compute/tests/compute/examples/scan/running_average.py-1-16 (1)

1-16: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

important: Add the license header and move # example-begin above the imports.

This file has no NVIDIA copyright/SPDX header. Every sibling example in python/cuda_compute/tests/compute/examples/scan/ carries one, and the repository guidelines require the license text in all source files.

The # example-begin marker at Line 12 also sits after the imports. Documentation extraction between example-begin and example-end therefore produces a snippet without import cupy, import numpy, or the cuda.compute imports. The docstring at Lines 13-15 is likewise not a module docstring because statements precede it.

As per coding guidelines: "All headers, and also source files, must have the correct license text."

+# Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
+#
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+# example-begin
+"""
+Inclusive scan using zip iterator and output transform iterator to compute running average.
+"""
+
 import cupy as cp
 import numpy as np
 
 import cuda.compute
 from cuda.compute import (
     ConstantIterator,
     TransformOutputIterator,
     ZipIterator,
     gpu_struct,
 )
-
-# example-begin
-"""
-Inclusive scan using zip iterator and output transform iterator to compute running average.
-"""

Source: Coding guidelines

python/cuda_compute/tests/compute/test_iterators.py-107-118 (1)

107-118: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

important: test_reverse_output_iterator_equality duplicates the input test. ReverseIterator supports both input and output dereference, but this test only compares kind and does not exercise output dereference. Delete the duplicate or replace it with an output-operation test.

python/cuda_compute/cuda/compute/_jit.py-818-820 (1)

818-820: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

suggestion: the docstring says the state arrays appear "after the regular parameters". _AddStateParameters prepends them, and the example at Line 812 shows def func(state, x). Correct the docstring to say the state parameters come first.

python/cuda_compute/.gitignore-30-31 (1)

30-31: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

suggestion: Replace *.cmake with explicit generated-file patterns such as cmake_install.cmake and CTestTestfile.cmake. Remove the no-op !CMakeLists.txt rule.

python/cuda_compute/cuda/compute/_utils/protocols.py-73-85 (1)

73-85: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

important: Catch TypeError as well as AttributeError. PyTorch exposes Tensor.size as a method, so int(arr.size) raises TypeError before the shape fallback.

python/cuda_compute/cuda/compute/struct.py-58-63 (1)

58-63: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Reject Python keywords and names defined by or required by _Struct. _jit.py generates invalid attribute expressions for keyword fields, and _fields overwrites the instance field map before record conversion.

python/cuda_compute/cuda/compute/typing.py-64-64 (1)

64-64: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Add StreamLike to __all__. The protocol is public and documented, but wildcard imports and API tools that honor __all__ omit it.

python/cuda_compute/cuda/compute/typing.py-61-61 (1)

61-61: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

important: Close the RawOp cross-reference target. The missing > prevents Sphinx from resolving cuda.compute.op.RawOp.

python/cuda_cccl/README.md-11-14 (1)

11-14: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Quote both extras specifiers. In zsh, unquoted square brackets can cause no matches found before pip runs. Use pip install "cuda-cccl[cu13]" and pip install "cuda-cccl[cu12]".

python/cuda_compute/README.md-22-23 (1)

22-23: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Quote every requirement that contains an extra. Unquoted [...] is shell glob syntax. A shell can alter or reject the requirement before pip parses it. Use "cuda-compute[cu13]" and the same quoting for all variants, including the aggregate example. (pip.pypa.io)

Also applies to: 30-31, 37-38, 42-42

🧹 Nitpick comments (31)
c/parallel.v2/src/hostjit/libnvcc/compiler.cpp (1)

135-141: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

important: Apply the required CCCL C++ naming and function declarations.

Rename appendClangResourceDir to append_clang_resource_dir. Mark the host-only helper with _CCCL_HOST_API and inline. Update the four call sites in this change.

As per coding guidelines, “Use snake_case for all other symbols,” “Functions must be marked with _CCCL_HOST_API,” and “Non-template, non-constexpr functions must be declared inline.”

Also applies to: 985-989, 1384-1388, 1537-1541, 2009-2013

Source: Coding guidelines

python/cuda_compute/benchmarks/compute/host/host_benchmark_cases.py (1)

91-107: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: patch_wrapper_to_skip_native_compute silently no-ops when a wrapper exposes neither _bound_build_result nor partitioner. In that case the host-overhead benchmark launches the real kernel against the 1-byte temp storage, so the measurement changes meaning without any signal. The docstring assumes a loud failure, but a silent no-op is also possible if a wrapper type changes its internals. Track whether any patch was applied and raise if none was.

-def patch_wrapper_to_skip_native_compute(
-    wrapper: Any, return_kind: NoopReturnKind
-) -> None:
+def patch_wrapper_to_skip_native_compute(
+    wrapper: Any, return_kind: NoopReturnKind
+) -> None:
@@
+    patched = False
     if (bound := getattr(wrapper, "_bound_build_result", None)) is not None:
         wrapper._bound_build_result = NoopBuildResult(bound, return_kind)
+        patched = True
 
     if (partitioner := getattr(wrapper, "partitioner", None)) is not None:
         patch_wrapper_to_skip_native_compute(partitioner, return_kind)
+        patched = True
+
+    if not patched:
+        raise RuntimeError(
+            f"No build result to patch on {type(wrapper).__name__}; "
+            "host-overhead benchmark would launch the real kernel."
+        )
python/cuda_compute/benchmarks/compute/host/test_host_pytest_benchmark.py (1)

58-95: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: both host-overhead tests leave the patched NoopBuildResult inside the cached wrapper after the test ends. Any later test or benchmark in the same process that resolves the same cache key then skips the native kernel silently. Clear the caches after the measurement as well, for example with an autouse fixture that calls cc.clear_all_caches() on teardown.

python/cuda_compute/tests/packaging/test_merge_cuda_wheels.py (1)

50-68: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: the two tests cover only the changed branch of _validate_shared_contents. The asserted message pins missing=[] and extra=[] as well, so those branches carry the same contract but stay untested. Add one case where a shared file exists in only one extracted wheel, to cover missing/extra.

python/cuda_compute/benchmarks/compute/transform/complex_cmp.py (1)

61-74: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

suggestion: num_elements - 1 becomes -1 if an axis value of 0 is ever configured, and d_in[:-1] would be empty. The current axis starts at 2^16, so this is not reachable today. Only add a guard if the axis list may change.

python/cuda_compute/tests/compute/examples/sort/segmented_sort_object.py (1)

33-63: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: cp.asarray(start_offsets) and cp.asarray(end_offsets) are re-created six times across construction, sizing, and execution. Each call copies host to device. Hoist the two device arrays once and reuse them; the example then also shows the intended usage.

 d_output_vals = cp.empty_like(d_input_vals)
+d_start_offsets = cp.asarray(start_offsets)
+d_end_offsets = cp.asarray(end_offsets)

Then pass start_offsets_in=d_start_offsets and end_offsets_in=d_end_offsets in all three call sites.

python/cuda_compute/benchmarks/compute/transform/babelstream.py (1)

195-216: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

suggestion: Reuse zip_in in launcher. ZipIterator has no per-invocation mutable state. Constructing zip_in_iter adds host work to each timed launch and makes nstream timings inconsistent with the other benchmarks.

Source: Path instructions

python/cuda_compute/tests/compute/examples/iterator/reverse_input_iterator.py (1)

27-31: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: Both reverse-iterator examples carry comments copied from a reduction example, but each calls cuda.compute.inclusive_scan. The rendered documentation names the wrong operation.

  • python/cuda_compute/tests/compute/examples/iterator/reverse_input_iterator.py#L27-L31: change "initial value for the reduction" to "initial value for the scan" and "Perform the reduction." to "Perform the scan."
  • python/cuda_compute/tests/compute/examples/iterator/reverse_output_iterator.py#L30-L30: change "Perform the reduction." to "Perform the scan."
python/cuda_compute/tests/compute/examples/iterator/shuffle_iterator_basic.py (1)

32-33: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: cp.sort(d_output) is compared against d_input directly. This passes only because the input literal is already sorted ascending. Use cp.sort(d_input) on the right side so the check survives a change to the input values.

python/cuda_compute/tests/compute/examples/iterator/zip_iterator_counting.py (1)

35-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: num_items is hardcoded to 8. Use len(arr) so the example stays correct if the input array changes.

python/cuda_compute/tests/compute/test_reduce.py (1)

940-954: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: test_reduce_with_not_guaranteed_determinism runs the reduction and asserts nothing. Add a loose-tolerance check on d_output so the test can detect a wrong result, not only an exception.

python/cuda_compute/tests/compute/test_scan.py (1)

94-97: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: is_short_dtype = dtype.itemsize < 16 is true for every dtype except complex128 and wider, so the 31-element truncation applies to int64 and float64 as well. The name and the comment describe small-range types. Either rename the flag to state the real condition, or restrict the truncation to the narrow integer dtypes that can actually overflow.

python/cuda_compute/tests/compute/test_permutation_iterator.py (1)

201-220: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: compile_cpp_op_code.cache_clear() clears process-wide cache state. Other tests then recompile, and the hits >= 2 assertion becomes order- and parallelism-sensitive. Prefer a relative measurement instead of clearing the cache.

-    compile_cpp_op_code.cache_clear()
-
+    baseline = compile_cpp_op_code.cache_info().hits
+
     # Create multiple instances with same structure
     iterators = []
     for i in range(3):
@@
-    cache_info = compile_cpp_op_code.cache_info()
-    assert cache_info.hits >= 2, (
-        f"Expected cache hits for same structure, got {cache_info.hits} hits, "
+    cache_info = compile_cpp_op_code.cache_info()
+    assert cache_info.hits - baseline >= 2, (
+        f"Expected cache hits for same structure, got {cache_info.hits - baseline} hits, "
         f"{cache_info.misses} misses"
     )
python/cuda_compute/tests/compute/test_iterators.py (1)

68-69: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: Remove the dead assignment.

Line 68 assigns it and Line 69 overwrites it before any use. Delete Line 68, or compare the kinds of both iterators if that was the intent.

-    it = CountingIterator(np.int32(0))
     it = CountingIterator(np.int32(1))
python/cuda_compute/tests/compute/test_binary_search.py (1)

27-37: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: Replace np.isdtype(dtype, "integral") with np.issubdtype(dtype, np.integer). cuda-compute declares numpy without a minimum version, but np.isdtype requires NumPy 2.0 or later. NumPy 1.x environments raise AttributeError when these tests run.

python/cuda_compute/tests/compute/test_bindings.py (1)

120-124: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: Match TypeInfo metadata to the represented types. Value wraps an 8-byte UINT64; both iterators describe INT32. Use TypeInfo(8, 8, UINT64) and TypeInfo(4, 4, INT32). Iterator state is separate from value_type, but the current metadata still reports incorrect element sizes.

python/cuda_compute/tests/compute/test_select.py (1)

35-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: the test data is dtype-unaware, so several parameterized select cases assert on empty or full selections instead of partial selections. The shared root cause is that generated values do not respect the predicate ranges for every dtype in DTYPE_LIST.

  • python/cuda_compute/tests/compute/test_select.py#L35-L46: scale the floating branch of random_array by max_value when it is provided.
  • python/cuda_compute/tests/compute/test_select.py#L301-L301: build signed mixed-sign data for test_select_reuse_object instead of subtracting 50 from unsigned or [0, 1) values.
python/cuda_compute/tests/compute/test_serialization_diagnostics.py (1)

48-52: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: b.find(_C_MAGIC) returns -1 when the header layout changes and the magic is absent. struct.pack_into accepts a negative offset and then patches bytes near the end of the blob, so the test would fail with a misleading deserialize error instead of pointing at the missing header. Assert the index. The same find result is used unguarded at line 77.

 def _patch_u32(blob, field_off, value):
     b = bytearray(blob)
     i = b.find(_C_MAGIC)
+    assert i >= 0, "C serialization header magic not found in blob"
     struct.pack_into("<I", b, i + len(_C_MAGIC) + field_off, value)
     return bytes(b)
python/cuda_compute/tests/packaging/test_cuda_compute_metadata.py (1)

159-181: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: these assertions match exact multi-line CMake text, including newlines and two-space indentation. Any reformatting of c/parallel.v2/CMakeLists.txt or of the compute CMakeLists.txt breaks the test without a behavior change. Match the intent with whitespace-tolerant regexes instead.

+import re
...
-    assert (
-        f'option(\n  {runtime_paths}\n  "Resolve HostJIT resource paths at runtime '
-        'instead of embedding build-tree defaults."\n  OFF\n)' in parallel_cmake
-    )
-    assert (
-        f'if (SKBUILD_STATE STREQUAL "wheel")\n  set({runtime_paths} ON)\nendif()'
-        in compute_cmake
-    )
+    assert re.search(rf"option\(\s*{runtime_paths}\s+\"[^\"]+\"\s+OFF\s*\)", parallel_cmake)
+    assert re.search(
+        rf"if\s*\(\s*SKBUILD_STATE\s+STREQUAL\s+\"wheel\"\s*\)\s*set\(\s*{runtime_paths}\s+ON\s*\)",
+        compute_cmake,
+    )

The same concern applies to the exact set(CYTHON_FLAGS ...) and _cython_package_dir strings at lines 175-179.

python/cuda_compute/tests/test_examples.py (1)

87-93: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: hasattr(module, "__main__") is never true for an imported module unless the module defines that attribute, so the exec branch is unreachable. Drop the condition and the exec call. This also clears the static-analysis code-injection hint on line 93.

-        # Check if module has a main function - if so, run it
-        if hasattr(module, "__main__") or hasattr(module, "main"):
-            # Call main if it exists
-            if hasattr(module, "main"):
-                module.main()
-            else:
-                # Try to run the module as if it were called directly
-                exec(f"import {module_name}; {module_name}.__main__()")
+        # Check if module has a main function - if so, run it
+        if hasattr(module, "main"):
+            module.main()

Source: Linters/SAST tools

python/cuda_compute/cuda/compute/_bindings_impl.pyx (2)

256-268: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

suggestion: the three malloc results are used without NULL checks. On allocation failure the loop writes through a NULL pointer and the process crashes. A partial failure also leaks the earlier two allocations. Check each result and raise MemoryError after freeing what was already allocated.


193-197: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: the message states "Alignment must be non-negative" but the check rejects 0, which is non-negative. Use "positive" to match the check and the docstring.

Proposed fix
     if alignment < 1:
         raise ValueError(
-            "Alignment must be non-negative, "
+            "Alignment must be positive, "
             f"got {alignment}."
         )
python/cuda_compute/cuda/compute/_caching.py (2)

705-709: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

suggestion: __eq__ accesses other._identity unconditionally. A comparison against a non-CachableFunction object raises AttributeError instead of returning False. These objects are used as dict keys, so a hash collision with a foreign key triggers the comparison. Return NotImplemented when the type does not match.

Proposed fix
     def __eq__(self, other):
+        if not isinstance(other, CachableFunction):
+            return NotImplemented
         return self._identity == other._identity

490-500: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

suggestion: Log resolve() failures before the fallback rebuild

If resolve() fails, log the exception at debug level before rebuilding. The default builder() uses call_build, which returns a loaded result, so the fallback does not need an additional load() call.

python/cuda_compute/cuda/compute/_jit.py (3)

316-365: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: tuple_to_struct_cast registers on types.BaseTuple, which is the base of both types.Tuple and types.UniTuple. cast_tuple_to_struct then registers the same conversion for those two subclasses. The two implementations differ in failure behavior: the first raises ValueError on a size mismatch, the second returns None. Keep one implementation so the size-mismatch behavior is deterministic.


938-946: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: the key name "strides" holds a single itemsize scalar, not a stride tuple, and "shape" holds a scalar length. The names imply NumPy semantics that do not apply. Rename to "itemsize"/"stride"/"length" or document the 1-D contiguous assumption inline.


82-92: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

suggestion: Add an upper bound or explicit compatibility check for numba-cuda. _compile_pyfunc_with_fixup is private, so a future incompatible release can cause ImportError or TypeError during the first compilation.

python/cccl_headers/tests/test_cccl_headers.py (1)

121-123: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: this test invokes cmake with no availability check. If cmake is absent, subprocess.run raises FileNotFoundError and the test errors instead of skipping. The headers wheel has one runtime dependency and can be tested in a minimal environment. Add a skip guard.

 def test_cudax_cmake_target_is_consumer_safe(tmp_path):
+    if shutil.which("cmake") is None:
+        pytest.skip("cmake is not available")
     package_root = Path(headers.__file__).parent

Add import shutil at the top.

python/cuda_compute/tests/compute/test_transform.py (1)

86-87: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: import numpy as np inside test_unary_transform_struct_type and test_binary_transform_struct_type duplicates the module-level import at Line 5. Remove both local imports.

Also applies to: 113-114

python/cuda_compute/tests/compute/test_unique_by_key.py (1)

87-110: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: the loop variable next at Line 102 shadows the builtin. Rename it to current or nxt to keep the reference host implementation readable.

python/cuda_compute/cuda/compute/_utils/__init__.py (1)

8-22: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

suggestion: Keep sanitize_identifier as a character sanitizer. _create_void_ptr_wrapper intentionally rejects empty and digit-leading results with .isidentifier(). Update the docstring to state that callers must validate the sanitized result.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
docs/python/setup.rst (1)

25-30: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Correct the CUDA Toolkit prerequisite.

Lines 25-30 require a preinstalled Toolkit. Lines 45-46 state that cu12 and cu13 install cuda-toolkit. State that users need either a cu* extra or a compatible system Toolkit. Reserve the system Toolkit prerequisite for sysctk* variants.

ci/windows/build_cuda_cccl_python.ps1 (1)

255-272: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

important: forward the coordinated version and SOURCE_DATE_EPOCH into the nested CUDA 13 container.

Lines 83-114 state the intent that the outer build, the nested CUDA 13 build, and the universal wheel builds share one version. The nested invocation does not pass SETUPTOOLS_SCM_PRETEND_VERSION_FOR_CUDA_COMPUTE or SOURCE_DATE_EPOCH. The nested script therefore re-derives both from git inside the CUDA 13 image. Any difference in git state, tag visibility, or safe.directory handling in that image produces a different compute wheel version, and the merge step then combines mismatched versions. Forwarding the values also removes the redundant unshallow and version generation in the nested container.

Proposed fix
         '--env', "CCCL_PYTHON_USE_V2=$($env:CCCL_PYTHON_USE_V2)",
+        '--env', "SETUPTOOLS_SCM_PRETEND_VERSION_FOR_CUDA_COMPUTE=$($env:SETUPTOOLS_SCM_PRETEND_VERSION_FOR_CUDA_COMPUTE)",
+        '--env', "SOURCE_DATE_EPOCH=$($env:SOURCE_DATE_EPOCH)",
         $Cuda13Image,
🟠 Major comments (30)
.github/workflows/release-wheels.yml-67-82 (1)

67-82: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Missing Branch Authorization (CWE-862): Missing Authorization

Reachability: Internal · Exploitability: Moderate

important: Restrict accepted runs to approved release branches. The workflow currently accepts successful workflow_dispatch runs from any branch, so a feature-branch build can reach the PyPI publish step. Add an allowlist for .head_branch, such as main and approved branch/{major}.{minor}.x branches.

ci/test/python_wheels/test_wheel_scripts.py-512-525 (1)

512-525: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

important: the post-uninstall isolation check depends on undefined behavior and can fail for the wrong reason.

importlib.util.find_spec('cuda.compute') imports the parent package cuda first. The old metapackage is the only distribution that provides cuda/, so after the uninstall two outcomes are possible:

  • pip removes the now-empty directories. import cuda then fails and find_spec raises ModuleNotFoundError instead of returning None. check=True reports a test failure.
  • pip leaves the empty cuda/compute/ directory. That directory resolves as a namespace package, so find_spec returns a spec and the assertion fails.

pip does not guarantee either outcome, so this assertion does not reliably test what it intends. Assert that no importable module with a loader remains, and treat a missing parent as success.

Proposed fix
-                    (
-                        "import importlib.util; "
-                        "assert importlib.util.find_spec('cuda.compute') is None; "
-                        "assert importlib.util.find_spec('cuda.cccl') is None"
-                    ),
+                    (
+                        "import importlib.util\n"
+                        "def gone(name):\n"
+                        "    try:\n"
+                        "        spec = importlib.util.find_spec(name)\n"
+                        "    except ModuleNotFoundError:\n"
+                        "        return True\n"
+                        "    return spec is None or spec.loader is None\n"
+                        "assert gone('cuda.compute')\n"
+                        "assert gone('cuda.cccl')\n"
+                    ),
python/cuda_compute/benchmarks/compute/scan/exclusive/sum.py-82-82 (1)

82-82: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

important: Limit the default element-count axis.

The exponent 32 creates 2^32 elements. Input and output alone require 32 GiB for 32-bit types and 64 GiB for 64-bit types. Temporary storage increases this requirement.

Cap the default axis or skip cases that exceed available GPU memory. Otherwise, a normal unfiltered run can terminate before it records the smaller cases.

As per path instructions, benchmark changes must avoid excessive runtime and preserve useful comparison data.

Source: Path instructions

python/cuda_compute/benchmarks/compute/utils.py-53-67 (1)

53-67: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Keep float64 interpolation finite.

For np.float64, max_val - min_val overflows to inf. Production probabilities then produce inf or nan, causing incorrect select thresholds. Use (1.0 - probability) * min_val + probability * max_val.

Source: Path instructions

python/cuda_compute/tests/compute/test_no_numba.py-268-270 (1)

268-270: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: cuda-compute declares numpy without a lower bound, so NumPy 1.x remains supported. Use np.argsort(h_keys, kind="stable"); stable=True raises TypeError on NumPy 1.x.

python/cuda_compute/tests/compute/test_radix_sort.py-322-324 (1)

322-324: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: both bit-window tests use dtype().itemsize as a bit count. itemsize is a byte count, so the begin/end bit sets stay within 0..8 and high key bits are never sorted. host_sort repeats the same bounds, so the assertions pass and the coverage loss is silent.

  • python/cuda_compute/tests/compute/test_radix_sort.py#L322-L324: change num_bits = dtype().itemsize to dtype().itemsize * 8 in test_radix_sort_pairs_bit_window.
  • python/cuda_compute/tests/compute/test_radix_sort.py#L377-L379: apply the same change in test_radix_sort_pairs_double_buffer_bit_window.
python/cuda_compute/tests/test_examples.py-119-127 (1)

119-127: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

important: subprocess.run has no timeout. If an example hangs, the whole test session hangs until the CI job is killed. Add a timeout and report it as a failure.

                     result = subprocess.run(
                         [sys.executable, module_file],
                         capture_output=True,
                         text=True,
                         cwd=os.path.dirname(module_file),
+                        timeout=600,
                     )
python/cccl_headers/cuda/cccl/headers/include_paths.py-16-23 (1)

16-23: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Make the cached IncludePaths value immutable.

get_include_paths returns the same mutable object for each cached probe_file. One caller can modify a field and corrupt the include paths returned to later callers.

Declare the dataclass with @dataclass(frozen=True), or cache immutable path values and construct a new result for each call.

Also applies to: 50-64

Source: Path instructions

python/cuda_compute/cuda/compute/_bindings_impl.pyx-236-236 (1)

236-236: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

important: Add except NULL to get_buffer_pointer

When PyObject_GetBuffer fails, callers receive NULL without the Python exception being propagated. ctypes_typed_pointer_payload_ptr can then dereference ptr_ref[0] and crash.

python/cuda_compute/cuda/compute/_jit.py-826-837 (1)

826-837: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

important: the try block catches only OSError and TypeError. Two other failures are reachable here. ast.parse raises SyntaxError when the retrieved source is not a standalone statement, which happens for a lambda: inspect.getsource returns the enclosing call expression, and func.__name__ is <lambda>, so Line 866 would also raise KeyError. to_jit_op_adapter routes any callable with captured device arrays through this function, so a lambda that closes over a device array reaches it. Wrap parse and lookup failures in the same actionable ValueError, or reject non-def callables with an explicit message.

python/cuda_compute/cuda/compute/_jit.py-668-674 (1)

668-674: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

important: both OpAdapter subclasses implement __eq__ by dereferencing attributes on other with no type check. Python calls __eq__ on hash collisions inside dicts and sets, and both classes are registered as cache-key providers at Line 1046 and Line 1048. A collision with any foreign key type raises AttributeError instead of returning NotImplemented.

  • python/cuda_compute/cuda/compute/_jit.py#L668-L674: guard _StatelessOp.__eq__ with isinstance(other, _StatelessOp) and return NotImplemented otherwise.
  • python/cuda_compute/cuda/compute/_jit.py#L1027-L1031: guard _StatefulOp.__eq__ with isinstance(other, _StatefulOp) and return NotImplemented otherwise.
python/cuda_compute/tests/compute/test_three_way_partition.py-48-50 (1)

48-50: 🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

important: this builds 77 parameterizations, and log_size 16 and 20 run 65K and 1M element partitions for all 11 dtypes. Each case compiles two custom operators. The sibling test_unique_by_key.py marks sizes at or above 2**20 with pytest.mark.large through get_mark. Apply the same marking here so a default CI run does not pay for 11 million-element partitions.

Source: Path instructions

python/cuda_compute/tests/compute/test_unique_by_key.py-143-144 (1)

143-144: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: both test files define their own random_array helper that accepts max_value but applies it only to integral dtypes. For every floating-point dtype the helper returns values in [0, 1), so the callers' value-based predicates and equality checks degenerate and the float parameterizations lose their coverage. Fix the helper in both places, or move one corrected helper into tests/_utils.

  • python/cuda_compute/tests/compute/test_unique_by_key.py#L143-L144: scale the float keys into a small integral range so consecutive duplicate keys occur and the de-duplication path runs.
  • python/cuda_compute/tests/compute/test_three_way_partition.py#L87-L93: scale the float inputs across the 42 threshold so the float cases produce all three partitions.
python/cuda_compute/benchmarks/compute/.gitignore-17-19 (1)

17-19: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

important: ignoring pixi.lock leaves the benchmark environment unpinned. A benchmark run on one machine can then resolve different dependency versions than another, which invalidates cross-run performance comparison. The benchmarking conventions require reproducible runs and comparable results. Commit pixi.lock and ignore only .pixi/.

 # Pixi
 .pixi/
-pixi.lock

As per path instructions: "Check that benchmark changes measure meaningful workloads, keep axes comparable, avoid excessive runtime, and preserve useful comparison data."

Source: Path instructions

python/cccl_headers/tests/test_cccl_headers.py-249-252 (1)

249-252: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Line 250, Line 251, Line 293, Line 294, and Line 295 pass CMake cache values through .as_posix(), but Line 249 and Line 252 interpolate the raw Path. On Windows str(Path) produces backslashes, and CMake treats a backslash in a cache value as an escape. The result is a broken cudax_DIR and CMAKE_INSTALL_PREFIX. Use .as_posix() for both.

-                f"-Dcudax_DIR={cudax_cmake_dir}",
+                f"-Dcudax_DIR={cudax_cmake_dir.as_posix()}",
                 f"-DCCCL_DIR={(package_root / 'lib' / 'cmake' / 'cccl').as_posix()}",
                 f"-DEXPECTED_CUDAX_INCLUDE={(package_root / 'include').as_posix()}",
-                f"-DCMAKE_INSTALL_PREFIX={build_dir / 'install'}",
+                f"-DCMAKE_INSTALL_PREFIX={(build_dir / 'install').as_posix()}",
python/cuda_compute/cuda/compute/struct.py-97-107 (1)

97-107: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Do not discard constructor arguments. Positional arguments cause all keyword arguments to be ignored. A dictionary first argument also causes trailing positional arguments to be ignored. Reject unsupported mixes, or merge them with duplicate and missing-field validation.

python/cuda_compute/cuda/compute/struct.py-146-163 (1)

146-163: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Add coercion for declared TypeDescriptor fields. _field_spec_to_type_descriptors accepts types.TypeDescriptor, but _coerce_value has no matching branch. gpu_struct({"x": types.int32})(1) reaches the fallback and raises AttributeError. Validate nested struct classes before accepting them, and coerce descriptors through field_type.dtype.type(...).

python/cuda_compute/cuda/compute/types.py-74-80 (1)

74-80: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

important: Freeze the field mapping at construction. StructTypeDescriptor stores and exposes the caller’s mutable dictionary, while equality, hashing, and layout_key() read it. A later mutation changes cache identity while _dtype remains unchanged. Copy the mapping and expose an immutable view.

Also applies to: 90-108

python/cuda_compute/cuda/compute/types.py-260-265 (1)

260-265: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Collect every annotated positional parameter. The break leaves input_tds with only the first annotated parameter. A multi-argument operator then gets a truncated signature. Remove the break and define explicit handling for missing annotations.

python/cuda_compute/cuda/compute/types.py-171-179 (1)

171-179: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

important: Preserve structured-dtype layouts

from_numpy_dtype() and gpu_struct() rebuild structured dtypes from field types with align=True. This discards source offsets and itemsize, so packed or explicitly padded dtypes can receive a different record ABI. Preserve the source layout, or reject unsupported layouts, in both paths. gpu_struct() must also handle title aliases without treating them as additional fields.

ci/windows/test_cuda_compute_python.ps1-29-38 (1)

29-38: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

important: Install only "$wheelPath[test-$ctkFlavor$cudaMajor]" and let pip resolve cccl-headers from $wheelhouse. The current command installs $headersWheelPath separately, so the import assertion cannot detect a missing dependency in cuda-compute. Run this check in a fresh environment and assert the installed cccl-headers distribution.

python/cuda_compute/cuda/compute/iterators/_discard.py-70-84 (1)

70-84: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Do not expose the discard iterator as input-capable. This no-op operation does not write result, but IteratorBase treats its non-None return as a valid input dereference. An algorithm that receives DiscardIterator as d_in reads uninitialized device data. Return None here so input conversion fails.

python/cuda_compute/cuda/compute/iterators/_reverse.py-37-41 (1)

37-41: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

important: Define empty-array behavior before calculating size - 1. For an empty device array, this creates a PointerIterator at -1 elements and serializes a pointer before the allocation. Reject the input or use a valid empty-range representation.

python/cuda_compute/cuda/compute/iterators/_reverse.py-139-140 (1)

139-140: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Negate the host-side offset. The class contract and _make_advance_op() move positive offsets backward. This method moves the wrapped iterator forward instead. For an array-backed iterator, ReverseIterator(array) + 1 points one element past the end instead of at the preceding element.

python/cuda_compute/cuda/compute/iterators/_base.py-76-81 (1)

76-81: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Resolve the implicit iterator cache key to the current compute capability. When USING_V2 is false, get_target_cc() returns None for default builds, and all three accessors use None as the cache key. Switching devices can reuse the first device's incompatible LTO-IR.

python/cuda_compute/cuda/compute/iterators/_cache_modified.py-69-78 (1)

69-78: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Reject descriptors without a generated C++ type. A 4-byte structured dtype passes the size check, but cpp_type_from_descriptor() returns None, producing static_cast<None**> and a JIT compilation failure.

python/cuda_compute/cuda/compute/iterators/_cache_modified.py-96-100 (1)

96-100: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Use int64_t for the advance distance. ReverseIterator passes a negative int64_t to the wrapped iterator. Reading it as uint64_t converts -n to 2^64 - n, causing an invalid positive pointer adjustment.

python/cuda_compute/cuda/compute/_utils/temp_storage_buffer.py-20-40 (1)

20-40: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

important: Bind memory-pool configuration and default-stream cleanup to the allocation device. When stream targets another device, _set_default_mempool_threshold(dev.device_id) configures the wrong pool. When stream is None, finalization can enqueue cudaFreeAsync on another thread's default device and leave the allocation reserved after the warning. Store the allocation device and preserve the allocation stream or device for cleanup. Add multi-GPU tests for cross-device streams and cross-thread finalization.

ci/windows/test_cuda_compute_minimal_python.ps1-29-37 (1)

29-37: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

important: Do not pass $headersWheelPath as a direct install target. The command installs cccl-headers even if the cuda-compute wheel omits its required dependency. Because pip check validates declared installed dependencies, it cannot detect that omission. Install only "$wheelPath[minimal-$ctkFlavor$cudaMajor]" with --find-links $wheelhouse, then assert that the resolver installed the matching cccl-headers distribution. (pip.pypa.io)

Based on PR objectives, the split requires dependency validation across the wheel set.

python/cuda_compute/README.md-17-19 (1)

17-19: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

important: Add the required cleanup and reinstall procedure to the installation section. The README directs existing aggregate users to continue installing cuda-cccl but does not provide the required migration from the monolithic wheel. Users can otherwise retain files from the old wheel-ownership layout. As per PR objectives, the split requires an uninstall/reinstall procedure when users upgrade from the monolithic wheel.

🟡 Minor comments (21)
docs/python/compute/index.rst-311-311 (1)

311-311: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Quote the package extras in these installation commands.

Unquoted square brackets can be interpreted as pathname patterns by the shell. Use quoted requirements such as pip install 'cuda-compute[minimal-cu13]' and pip install 'cuda-compute[minimal-sysctk13]'.

Also applies to: 541-542

Source: Path instructions

ci/util/python/validate_cccl_wheel_set.py-71-75 (1)

71-75: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

important: Parse extra markers instead of matching one rendered form. A valid marker such as (python_version < "3.11") and extra == "test" or a changed version bound is classified as unconditional, which can block wheel validation. Use a complete marker parser and add regression tests for these forms.

python/cuda_compute/benchmarks/compute/partition/three_way.py-67-68 (1)

67-68: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

important: Report both counter writes. d_num_selected_out stores two counters, but the accounting reports one. Use 2 * d_num_selected_out.dtype.itemsize to match C++ add_global_memory_writes<offset_t>(2). np.int32 is a supported output dtype and does not cause an out-of-bounds write.

python/cuda_compute/tests/compute/examples/sort/radix_sort_basic.py-45-47 (1)

45-47: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

important: Replace stable=True with kind="stable" in both sort examples. python/cuda_compute/pyproject.toml declares numpy without a minimum version, and NumPy 1.x raises TypeError for stable=True.

python/cuda_compute/benchmarks/compute/segmented_reduce/variable_sum.py-118-118 (1)

118-118: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Report both offset arrays in segmented-operation metrics.

Both benchmarks pass separate start and end offset arrays but report traffic for one contiguous num_segments + 1 array.

  • python/cuda_compute/benchmarks/compute/segmented_reduce/variable_sum.py#L118-L118: report 2 * num_segments * start_offsets.dtype.itemsize.
  • python/cuda_compute/benchmarks/compute/segmented_sort/keys.py#L126-L126: report 2 * num_segments * start_offsets.dtype.itemsize.

As per path instructions, benchmark results must preserve useful comparison data.

Source: Path instructions

python/cuda_compute/tests/compute/examples/select/select_object.py-57-78 (1)

57-78: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Validate every demonstrated selection result.

Both examples execute and retrieve an output that the assertions do not validate.

  • python/cuda_compute/tests/compute/examples/select/select_object.py#L57-L78: assert the second selected count and values.
  • python/cuda_compute/tests/compute/examples/select/select_with_side_effect.py#L39-L54: assert the selected even values, not only the counts.
python/cuda_compute/tests/compute/examples/sort/radix_sort_buffer.py-21-23 (1)

21-23: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

suggestion: 8.3 - 1 in the literal list looks like a typo for 8.3, -1. The list still has 10 entries, so the example passes, but a reader of a public example will stop here. Replace it with the intended literal.

 h_in_values = np.array(
-    [-3.2, 2.2, 1.9, 4.0, -3.9, 2.7, 0, 8.3 - 1, 2.9, 5.4], dtype="float32"
+    [-3.2, 2.2, 1.9, 4.0, -3.9, 2.7, 0, 7.3, 2.9, 5.4], dtype="float32"
 )
python/cuda_compute/benchmarks/compute/transform/complex_cmp.py-84-86 (1)

84-86: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: the write accounting is off by one element. The transform writes num_items = num_elements - 1 booleans, but line 86 charges num_elements. Use num_items so the reported write bandwidth matches the C++ benchmark.

     state.add_element_count(num_elements)
     state.add_global_memory_reads(num_elements * d_in.dtype.itemsize)
-    state.add_global_memory_writes(num_elements * d_out.dtype.itemsize)
+    state.add_global_memory_writes(num_items * d_out.dtype.itemsize)

Note num_items is currently defined at line 79, after this block would need it; move the assignment above state.add_element_count.

Source: Path instructions

python/cuda_compute/tests/compute/examples/sort/radix_sort_buffer.py-49-49 (1)

49-49: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

important: Use kind="stable" or require NumPy 2.0+. cuda-compute declares an unconstrained numpy dependency, so NumPy 1.x remains possible; stable=True raises TypeError there.

python/cuda_compute/tests/compute/test_reduce.py-473-487 (1)

473-487: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: This block builds reducer_1 and reducer_2 for two identical-body ops with different names, then never asserts anything. The case is dead code and covers nothing.

Add the expected assertion. Based on the neighbouring cases and the comment, ops with the same body but different names should map to the same cached reducer:

     reducer_2 = cuda.compute.make_reduce_into(
         d_in=TransformIterator(CountingIterator(np.int32(0)), op3),
         d_out=DeviceArray.empty(1, dtype="int64"),
         op=sum_op,
         h_init=np.zeros(1, dtype="int64"),
     )
+    assert reducer_1 is reducer_2

If the intended behaviour is the opposite, use is not instead. Confirm the caching contract before choosing.

python/cuda_compute/tests/compute/examples/raw_op/llvm_stateless.py-13-22 (1)

13-22: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

important: Exclude llvmlite 0.43.x from the example test dependencies or rewrite the IR with typed pointers. llvmlite 0.43.x does not support the opaque ptr syntax used here. The example runner already handles sys.exit(0), and llvm.initialize() is not required by current llvmlite releases.

python/cuda_compute/tests/compute/examples/scan/running_average.py-1-16 (1)

1-16: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

important: Add the license header and move # example-begin above the imports.

This file has no NVIDIA copyright/SPDX header. Every sibling example in python/cuda_compute/tests/compute/examples/scan/ carries one, and the repository guidelines require the license text in all source files.

The # example-begin marker at Line 12 also sits after the imports. Documentation extraction between example-begin and example-end therefore produces a snippet without import cupy, import numpy, or the cuda.compute imports. The docstring at Lines 13-15 is likewise not a module docstring because statements precede it.

As per coding guidelines: "All headers, and also source files, must have the correct license text."

+# Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. ALL RIGHTS RESERVED.
+#
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+# example-begin
+"""
+Inclusive scan using zip iterator and output transform iterator to compute running average.
+"""
+
 import cupy as cp
 import numpy as np
 
 import cuda.compute
 from cuda.compute import (
     ConstantIterator,
     TransformOutputIterator,
     ZipIterator,
     gpu_struct,
 )
-
-# example-begin
-"""
-Inclusive scan using zip iterator and output transform iterator to compute running average.
-"""

Source: Coding guidelines

python/cuda_compute/tests/compute/test_iterators.py-107-118 (1)

107-118: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

important: test_reverse_output_iterator_equality duplicates the input test. ReverseIterator supports both input and output dereference, but this test only compares kind and does not exercise output dereference. Delete the duplicate or replace it with an output-operation test.

python/cuda_compute/cuda/compute/_jit.py-818-820 (1)

818-820: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

suggestion: the docstring says the state arrays appear "after the regular parameters". _AddStateParameters prepends them, and the example at Line 812 shows def func(state, x). Correct the docstring to say the state parameters come first.

python/cuda_compute/.gitignore-30-31 (1)

30-31: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

suggestion: Replace *.cmake with explicit generated-file patterns such as cmake_install.cmake and CTestTestfile.cmake. Remove the no-op !CMakeLists.txt rule.

python/cuda_compute/cuda/compute/_utils/protocols.py-73-85 (1)

73-85: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

important: Catch TypeError as well as AttributeError. PyTorch exposes Tensor.size as a method, so int(arr.size) raises TypeError before the shape fallback.

python/cuda_compute/cuda/compute/struct.py-58-63 (1)

58-63: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Reject Python keywords and names defined by or required by _Struct. _jit.py generates invalid attribute expressions for keyword fields, and _fields overwrites the instance field map before record conversion.

python/cuda_compute/cuda/compute/typing.py-64-64 (1)

64-64: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Add StreamLike to __all__. The protocol is public and documented, but wildcard imports and API tools that honor __all__ omit it.

python/cuda_compute/cuda/compute/typing.py-61-61 (1)

61-61: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

important: Close the RawOp cross-reference target. The missing > prevents Sphinx from resolving cuda.compute.op.RawOp.

python/cuda_cccl/README.md-11-14 (1)

11-14: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Quote both extras specifiers. In zsh, unquoted square brackets can cause no matches found before pip runs. Use pip install "cuda-cccl[cu13]" and pip install "cuda-cccl[cu12]".

python/cuda_compute/README.md-22-23 (1)

22-23: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

important: Quote every requirement that contains an extra. Unquoted [...] is shell glob syntax. A shell can alter or reject the requirement before pip parses it. Use "cuda-compute[cu13]" and the same quoting for all variants, including the aggregate example. (pip.pypa.io)

Also applies to: 30-31, 37-38, 42-42

🧹 Nitpick comments (31)
c/parallel.v2/src/hostjit/libnvcc/compiler.cpp (1)

135-141: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

important: Apply the required CCCL C++ naming and function declarations.

Rename appendClangResourceDir to append_clang_resource_dir. Mark the host-only helper with _CCCL_HOST_API and inline. Update the four call sites in this change.

As per coding guidelines, “Use snake_case for all other symbols,” “Functions must be marked with _CCCL_HOST_API,” and “Non-template, non-constexpr functions must be declared inline.”

Also applies to: 985-989, 1384-1388, 1537-1541, 2009-2013

Source: Coding guidelines

python/cuda_compute/benchmarks/compute/host/host_benchmark_cases.py (1)

91-107: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: patch_wrapper_to_skip_native_compute silently no-ops when a wrapper exposes neither _bound_build_result nor partitioner. In that case the host-overhead benchmark launches the real kernel against the 1-byte temp storage, so the measurement changes meaning without any signal. The docstring assumes a loud failure, but a silent no-op is also possible if a wrapper type changes its internals. Track whether any patch was applied and raise if none was.

-def patch_wrapper_to_skip_native_compute(
-    wrapper: Any, return_kind: NoopReturnKind
-) -> None:
+def patch_wrapper_to_skip_native_compute(
+    wrapper: Any, return_kind: NoopReturnKind
+) -> None:
@@
+    patched = False
     if (bound := getattr(wrapper, "_bound_build_result", None)) is not None:
         wrapper._bound_build_result = NoopBuildResult(bound, return_kind)
+        patched = True
 
     if (partitioner := getattr(wrapper, "partitioner", None)) is not None:
         patch_wrapper_to_skip_native_compute(partitioner, return_kind)
+        patched = True
+
+    if not patched:
+        raise RuntimeError(
+            f"No build result to patch on {type(wrapper).__name__}; "
+            "host-overhead benchmark would launch the real kernel."
+        )
python/cuda_compute/benchmarks/compute/host/test_host_pytest_benchmark.py (1)

58-95: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: both host-overhead tests leave the patched NoopBuildResult inside the cached wrapper after the test ends. Any later test or benchmark in the same process that resolves the same cache key then skips the native kernel silently. Clear the caches after the measurement as well, for example with an autouse fixture that calls cc.clear_all_caches() on teardown.

python/cuda_compute/tests/packaging/test_merge_cuda_wheels.py (1)

50-68: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: the two tests cover only the changed branch of _validate_shared_contents. The asserted message pins missing=[] and extra=[] as well, so those branches carry the same contract but stay untested. Add one case where a shared file exists in only one extracted wheel, to cover missing/extra.

python/cuda_compute/benchmarks/compute/transform/complex_cmp.py (1)

61-74: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

suggestion: num_elements - 1 becomes -1 if an axis value of 0 is ever configured, and d_in[:-1] would be empty. The current axis starts at 2^16, so this is not reachable today. Only add a guard if the axis list may change.

python/cuda_compute/tests/compute/examples/sort/segmented_sort_object.py (1)

33-63: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: cp.asarray(start_offsets) and cp.asarray(end_offsets) are re-created six times across construction, sizing, and execution. Each call copies host to device. Hoist the two device arrays once and reuse them; the example then also shows the intended usage.

 d_output_vals = cp.empty_like(d_input_vals)
+d_start_offsets = cp.asarray(start_offsets)
+d_end_offsets = cp.asarray(end_offsets)

Then pass start_offsets_in=d_start_offsets and end_offsets_in=d_end_offsets in all three call sites.

python/cuda_compute/benchmarks/compute/transform/babelstream.py (1)

195-216: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

suggestion: Reuse zip_in in launcher. ZipIterator has no per-invocation mutable state. Constructing zip_in_iter adds host work to each timed launch and makes nstream timings inconsistent with the other benchmarks.

Source: Path instructions

python/cuda_compute/tests/compute/examples/iterator/reverse_input_iterator.py (1)

27-31: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: Both reverse-iterator examples carry comments copied from a reduction example, but each calls cuda.compute.inclusive_scan. The rendered documentation names the wrong operation.

  • python/cuda_compute/tests/compute/examples/iterator/reverse_input_iterator.py#L27-L31: change "initial value for the reduction" to "initial value for the scan" and "Perform the reduction." to "Perform the scan."
  • python/cuda_compute/tests/compute/examples/iterator/reverse_output_iterator.py#L30-L30: change "Perform the reduction." to "Perform the scan."
python/cuda_compute/tests/compute/examples/iterator/shuffle_iterator_basic.py (1)

32-33: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: cp.sort(d_output) is compared against d_input directly. This passes only because the input literal is already sorted ascending. Use cp.sort(d_input) on the right side so the check survives a change to the input values.

python/cuda_compute/tests/compute/examples/iterator/zip_iterator_counting.py (1)

35-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: num_items is hardcoded to 8. Use len(arr) so the example stays correct if the input array changes.

python/cuda_compute/tests/compute/test_reduce.py (1)

940-954: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: test_reduce_with_not_guaranteed_determinism runs the reduction and asserts nothing. Add a loose-tolerance check on d_output so the test can detect a wrong result, not only an exception.

python/cuda_compute/tests/compute/test_scan.py (1)

94-97: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: is_short_dtype = dtype.itemsize < 16 is true for every dtype except complex128 and wider, so the 31-element truncation applies to int64 and float64 as well. The name and the comment describe small-range types. Either rename the flag to state the real condition, or restrict the truncation to the narrow integer dtypes that can actually overflow.

python/cuda_compute/tests/compute/test_permutation_iterator.py (1)

201-220: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: compile_cpp_op_code.cache_clear() clears process-wide cache state. Other tests then recompile, and the hits >= 2 assertion becomes order- and parallelism-sensitive. Prefer a relative measurement instead of clearing the cache.

-    compile_cpp_op_code.cache_clear()
-
+    baseline = compile_cpp_op_code.cache_info().hits
+
     # Create multiple instances with same structure
     iterators = []
     for i in range(3):
@@
-    cache_info = compile_cpp_op_code.cache_info()
-    assert cache_info.hits >= 2, (
-        f"Expected cache hits for same structure, got {cache_info.hits} hits, "
+    cache_info = compile_cpp_op_code.cache_info()
+    assert cache_info.hits - baseline >= 2, (
+        f"Expected cache hits for same structure, got {cache_info.hits - baseline} hits, "
         f"{cache_info.misses} misses"
     )
python/cuda_compute/tests/compute/test_iterators.py (1)

68-69: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: Remove the dead assignment.

Line 68 assigns it and Line 69 overwrites it before any use. Delete Line 68, or compare the kinds of both iterators if that was the intent.

-    it = CountingIterator(np.int32(0))
     it = CountingIterator(np.int32(1))
python/cuda_compute/tests/compute/test_binary_search.py (1)

27-37: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: Replace np.isdtype(dtype, "integral") with np.issubdtype(dtype, np.integer). cuda-compute declares numpy without a minimum version, but np.isdtype requires NumPy 2.0 or later. NumPy 1.x environments raise AttributeError when these tests run.

python/cuda_compute/tests/compute/test_bindings.py (1)

120-124: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: Match TypeInfo metadata to the represented types. Value wraps an 8-byte UINT64; both iterators describe INT32. Use TypeInfo(8, 8, UINT64) and TypeInfo(4, 4, INT32). Iterator state is separate from value_type, but the current metadata still reports incorrect element sizes.

python/cuda_compute/tests/compute/test_select.py (1)

35-46: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: the test data is dtype-unaware, so several parameterized select cases assert on empty or full selections instead of partial selections. The shared root cause is that generated values do not respect the predicate ranges for every dtype in DTYPE_LIST.

  • python/cuda_compute/tests/compute/test_select.py#L35-L46: scale the floating branch of random_array by max_value when it is provided.
  • python/cuda_compute/tests/compute/test_select.py#L301-L301: build signed mixed-sign data for test_select_reuse_object instead of subtracting 50 from unsigned or [0, 1) values.
python/cuda_compute/tests/compute/test_serialization_diagnostics.py (1)

48-52: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: b.find(_C_MAGIC) returns -1 when the header layout changes and the magic is absent. struct.pack_into accepts a negative offset and then patches bytes near the end of the blob, so the test would fail with a misleading deserialize error instead of pointing at the missing header. Assert the index. The same find result is used unguarded at line 77.

 def _patch_u32(blob, field_off, value):
     b = bytearray(blob)
     i = b.find(_C_MAGIC)
+    assert i >= 0, "C serialization header magic not found in blob"
     struct.pack_into("<I", b, i + len(_C_MAGIC) + field_off, value)
     return bytes(b)
python/cuda_compute/tests/packaging/test_cuda_compute_metadata.py (1)

159-181: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: these assertions match exact multi-line CMake text, including newlines and two-space indentation. Any reformatting of c/parallel.v2/CMakeLists.txt or of the compute CMakeLists.txt breaks the test without a behavior change. Match the intent with whitespace-tolerant regexes instead.

+import re
...
-    assert (
-        f'option(\n  {runtime_paths}\n  "Resolve HostJIT resource paths at runtime '
-        'instead of embedding build-tree defaults."\n  OFF\n)' in parallel_cmake
-    )
-    assert (
-        f'if (SKBUILD_STATE STREQUAL "wheel")\n  set({runtime_paths} ON)\nendif()'
-        in compute_cmake
-    )
+    assert re.search(rf"option\(\s*{runtime_paths}\s+\"[^\"]+\"\s+OFF\s*\)", parallel_cmake)
+    assert re.search(
+        rf"if\s*\(\s*SKBUILD_STATE\s+STREQUAL\s+\"wheel\"\s*\)\s*set\(\s*{runtime_paths}\s+ON\s*\)",
+        compute_cmake,
+    )

The same concern applies to the exact set(CYTHON_FLAGS ...) and _cython_package_dir strings at lines 175-179.

python/cuda_compute/tests/test_examples.py (1)

87-93: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: hasattr(module, "__main__") is never true for an imported module unless the module defines that attribute, so the exec branch is unreachable. Drop the condition and the exec call. This also clears the static-analysis code-injection hint on line 93.

-        # Check if module has a main function - if so, run it
-        if hasattr(module, "__main__") or hasattr(module, "main"):
-            # Call main if it exists
-            if hasattr(module, "main"):
-                module.main()
-            else:
-                # Try to run the module as if it were called directly
-                exec(f"import {module_name}; {module_name}.__main__()")
+        # Check if module has a main function - if so, run it
+        if hasattr(module, "main"):
+            module.main()

Source: Linters/SAST tools

python/cuda_compute/cuda/compute/_bindings_impl.pyx (2)

256-268: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

suggestion: the three malloc results are used without NULL checks. On allocation failure the loop writes through a NULL pointer and the process crashes. A partial failure also leaks the earlier two allocations. Check each result and raise MemoryError after freeing what was already allocated.


193-197: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: the message states "Alignment must be non-negative" but the check rejects 0, which is non-negative. Use "positive" to match the check and the docstring.

Proposed fix
     if alignment < 1:
         raise ValueError(
-            "Alignment must be non-negative, "
+            "Alignment must be positive, "
             f"got {alignment}."
         )
python/cuda_compute/cuda/compute/_caching.py (2)

705-709: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

suggestion: __eq__ accesses other._identity unconditionally. A comparison against a non-CachableFunction object raises AttributeError instead of returning False. These objects are used as dict keys, so a hash collision with a foreign key triggers the comparison. Return NotImplemented when the type does not match.

Proposed fix
     def __eq__(self, other):
+        if not isinstance(other, CachableFunction):
+            return NotImplemented
         return self._identity == other._identity

490-500: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

suggestion: Log resolve() failures before the fallback rebuild

If resolve() fails, log the exception at debug level before rebuilding. The default builder() uses call_build, which returns a loaded result, so the fallback does not need an additional load() call.

python/cuda_compute/cuda/compute/_jit.py (3)

316-365: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: tuple_to_struct_cast registers on types.BaseTuple, which is the base of both types.Tuple and types.UniTuple. cast_tuple_to_struct then registers the same conversion for those two subclasses. The two implementations differ in failure behavior: the first raises ValueError on a size mismatch, the second returns None. Keep one implementation so the size-mismatch behavior is deterministic.


938-946: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: the key name "strides" holds a single itemsize scalar, not a stride tuple, and "shape" holds a scalar length. The names imply NumPy semantics that do not apply. Rename to "itemsize"/"stride"/"length" or document the 1-D contiguous assumption inline.


82-92: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

suggestion: Add an upper bound or explicit compatibility check for numba-cuda. _compile_pyfunc_with_fixup is private, so a future incompatible release can cause ImportError or TypeError during the first compilation.

python/cccl_headers/tests/test_cccl_headers.py (1)

121-123: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

suggestion: this test invokes cmake with no availability check. If cmake is absent, subprocess.run raises FileNotFoundError and the test errors instead of skipping. The headers wheel has one runtime dependency and can be tested in a minimal environment. Add a skip guard.

 def test_cudax_cmake_target_is_consumer_safe(tmp_path):
+    if shutil.which("cmake") is None:
+        pytest.skip("cmake is not available")
     package_root = Path(headers.__file__).parent

Add import shutil at the top.

python/cuda_compute/tests/compute/test_transform.py (1)

86-87: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: import numpy as np inside test_unary_transform_struct_type and test_binary_transform_struct_type duplicates the module-level import at Line 5. Remove both local imports.

Also applies to: 113-114

python/cuda_compute/tests/compute/test_unique_by_key.py (1)

87-110: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

suggestion: the loop variable next at Line 102 shadows the builtin. Rename it to current or nxt to keep the reference host implementation readable.

python/cuda_compute/cuda/compute/_utils/__init__.py (1)

8-22: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

suggestion: Keep sanitize_identifier as a character sanitizer. _create_void_ptr_wrapper intentionally rejects empty and digit-leading results with .isidentifier(). Update the docstring to state that callers must validate the sanitized result.

🛑 Comments failed to post (1)
python/cuda_compute/tests/compute/test_transform.py (1)

639-663: 🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win

critical: this test documents a gap in the stateful cache key. _JitOpState.get_cache_key() in _jit.py returns only the state names and dtypes. It omits the array length. _compile_stateful_op bakes len(state_array) into state_info["shape"], so len(arr) is a compile-time constant in the generated code. op1 and op2 here share the same name arr, the same float64 dtype, and the same bytecode, so their cache keys are equal while their compiled code must differ.

The test passes today only because _StatefulOp.__eq__ compares _state by identity and therefore never hits the cache. Add the array length to _JitOpState.get_cache_key() before changing that equality.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: db413a1e-af81-4235-b6ea-8a04d603af5c

📥 Commits

Reviewing files that changed from the base of the PR and between 2742c78 and 104733b.

📒 Files selected for processing (295)
  • .coderabbit.yaml
  • .github/workflows/ci-workflow-pull-request.yml
  • .github/workflows/release-wheels.yml
  • .pre-commit-config.yaml
  • AGENTS.md
  • c/parallel.v2/CMakeLists.txt
  • c/parallel.v2/src/hostjit/CMakeLists.txt
  • c/parallel.v2/src/hostjit/libnvcc/CMakeLists.txt
  • c/parallel.v2/src/hostjit/libnvcc/compiler.cpp
  • ci/bench/README.md
  • ci/bench/compare_paths.sh
  • ci/build_cuda_cccl_python.sh
  • ci/build_cuda_cccl_python_tsan.sh
  • ci/build_cuda_cccl_python_v2.sh
  • ci/build_cuda_cccl_wheel.sh
  • ci/generate_version.sh
  • ci/matrix.yaml
  • ci/project_files_and_dependencies.yaml
  • ci/test/CMakeLists.txt
  • ci/test/inspect_changes/python_cccl_headers.dirty_files
  • ci/test/inspect_changes/python_cccl_headers.output
  • ci/test/inspect_changes/python_cuda_compute.dirty_files
  • ci/test/inspect_changes/python_cuda_compute.output
  • ci/test/python_wheels/CMakeLists.txt
  • ci/test/python_wheels/test_wheel_scripts.py
  • ci/test_cuda_cccl_examples_python.sh
  • ci/test_cuda_cccl_headers_python.sh
  • ci/test_cuda_compute_minimal_python.sh
  • ci/test_cuda_compute_minimal_python_tsan.sh
  • ci/test_cuda_compute_python.sh
  • ci/test_python_common.sh
  • ci/update_version.sh
  • ci/util/python/collect_wheel_artifacts.py
  • ci/util/python/validate_cccl_wheel_set.py
  • ci/util/workflow/get_wheel_artifact_name.sh
  • ci/windows/build_common_python.psm1
  • ci/windows/build_cuda_cccl_python.ps1
  • ci/windows/test_cuda_cccl_examples_python.ps1
  • ci/windows/test_cuda_cccl_headers_python.ps1
  • ci/windows/test_cuda_compute_minimal_python.ps1
  • ci/windows/test_cuda_compute_python.ps1
  • docs/conf.py
  • docs/python/api_reference.rst
  • docs/python/compute/developer_overview.rst
  • docs/python/compute/index.rst
  • docs/python/headers_api.rst
  • docs/python/index.rst
  • docs/python/resources.rst
  • docs/python/setup.rst
  • lib/cmake/cccl/cccl-config.cmake
  • lib/cmake/cudax/cudax-config.cmake
  • python/cccl_headers/CMakeLists.txt
  • python/cccl_headers/README.md
  • python/cccl_headers/cuda/cccl/__init__.py
  • python/cccl_headers/cuda/cccl/headers/__init__.py
  • python/cccl_headers/cuda/cccl/headers/include/__init__.py
  • python/cccl_headers/cuda/cccl/headers/include_paths.py
  • python/cccl_headers/cuda/cccl/py.typed
  • python/cccl_headers/pyproject.toml
  • python/cccl_headers/tests/test_cccl_headers.py
  • python/cuda_cccl/.gitignore
  • python/cuda_cccl/CMakeLists.txt
  • python/cuda_cccl/LICENSE
  • python/cuda_cccl/README.md
  • python/cuda_cccl/cuda/cccl/__init__.py
  • python/cuda_cccl/cuda/cccl/headers/__init__.py
  • python/cuda_cccl/cuda/cccl/headers/include/__init__.py
  • python/cuda_cccl/cuda/cccl/headers/include_paths.py
  • python/cuda_cccl/cuda/cccl/parallel/__init__.py
  • python/cuda_cccl/cuda/cccl/parallel/experimental/__init__.py
  • python/cuda_cccl/pyproject.toml
  • python/cuda_cccl/tests/headers/test_cuda_cccl.py
  • python/cuda_cccl/tests/test_cuda_cccl_metadata.py
  • python/cuda_compute/.gitignore
  • python/cuda_compute/CMakeLists.txt
  • python/cuda_compute/README.md
  • python/cuda_compute/benchmarks/compute/.gitignore
  • python/cuda_compute/benchmarks/compute/AGENTS.md
  • python/cuda_compute/benchmarks/compute/README.md
  • python/cuda_compute/benchmarks/compute/histogram/even.py
  • python/cuda_compute/benchmarks/compute/host/host_benchmark_cases.py
  • python/cuda_compute/benchmarks/compute/host/test_host_pytest_benchmark.py
  • python/cuda_compute/benchmarks/compute/merge_sort/keys.py
  • python/cuda_compute/benchmarks/compute/merge_sort/pairs.py
  • python/cuda_compute/benchmarks/compute/partition/three_way.py
  • python/cuda_compute/benchmarks/compute/pixi.toml
  • python/cuda_compute/benchmarks/compute/quick_configs.yaml
  • python/cuda_compute/benchmarks/compute/radix_sort/keys.py
  • python/cuda_compute/benchmarks/compute/radix_sort/pairs.py
  • python/cuda_compute/benchmarks/compute/reduce/custom.py
  • python/cuda_compute/benchmarks/compute/reduce/min.py
  • python/cuda_compute/benchmarks/compute/reduce/nondeterministic.py
  • python/cuda_compute/benchmarks/compute/reduce/sum.py
  • python/cuda_compute/benchmarks/compute/run_benchmarks.py
  • python/cuda_compute/benchmarks/compute/scan/exclusive/custom.py
  • python/cuda_compute/benchmarks/compute/scan/exclusive/sum.py
  • python/cuda_compute/benchmarks/compute/segmented_reduce/variable_sum.py
  • python/cuda_compute/benchmarks/compute/segmented_sort/keys.py
  • python/cuda_compute/benchmarks/compute/select/if.py
  • python/cuda_compute/benchmarks/compute/select/unique_by_key.py
  • python/cuda_compute/benchmarks/compute/transform/babelstream.py
  • python/cuda_compute/benchmarks/compute/transform/complex_cmp.py
  • python/cuda_compute/benchmarks/compute/transform/fib.py
  • python/cuda_compute/benchmarks/compute/transform/fill.py
  • python/cuda_compute/benchmarks/compute/transform/grayscale.py
  • python/cuda_compute/benchmarks/compute/transform/heavy.py
  • python/cuda_compute/benchmarks/compute/transform_reduce/sum.py
  • python/cuda_compute/benchmarks/compute/utils.py
  • python/cuda_compute/cuda/compute/__init__.py
  • python/cuda_compute/cuda/compute/_bindings.py
  • python/cuda_compute/cuda/compute/_bindings.pyi
  • python/cuda_compute/cuda/compute/_bindings_binary_search_backend_v1.pxi
  • python/cuda_compute/cuda/compute/_bindings_binary_search_backend_v2.pxi
  • python/cuda_compute/cuda/compute/_bindings_impl.pyx
  • python/cuda_compute/cuda/compute/_bindings_op_code_type_v1.pxi
  • python/cuda_compute/cuda/compute/_bindings_op_code_type_v2.pxi
  • python/cuda_compute/cuda/compute/_bindings_segmented_reduce_backend_v1.pxi
  • python/cuda_compute/cuda/compute/_bindings_segmented_reduce_backend_v2.pxi
  • python/cuda_compute/cuda/compute/_bindings_serialization_v1.pxi
  • python/cuda_compute/cuda/compute/_bindings_serialization_v2.pxi
  • python/cuda_compute/cuda/compute/_caching.py
  • python/cuda_compute/cuda/compute/_cccl_interop.py
  • python/cuda_compute/cuda/compute/_cpp_compile.py
  • python/cuda_compute/cuda/compute/_cuda_version_utils.py
  • python/cuda_compute/cuda/compute/_device_code.py
  • python/cuda_compute/cuda/compute/_jit.py
  • python/cuda_compute/cuda/compute/_nvtx.py
  • python/cuda_compute/cuda/compute/_odr_helpers.py
  • python/cuda_compute/cuda/compute/_proxy.py
  • python/cuda_compute/cuda/compute/_serialization/__init__.py
  • python/cuda_compute/cuda/compute/_serialization/codec.py
  • python/cuda_compute/cuda/compute/_serialization/dispatch.py
  • python/cuda_compute/cuda/compute/_serialization/serializable.py
  • python/cuda_compute/cuda/compute/_target_cc.py
  • python/cuda_compute/cuda/compute/_utils/__init__.py
  • python/cuda_compute/cuda/compute/_utils/protocols.py
  • python/cuda_compute/cuda/compute/_utils/temp_storage_buffer.py
  • python/cuda_compute/cuda/compute/_version.py
  • python/cuda_compute/cuda/compute/algorithms/__init__.py
  • python/cuda_compute/cuda/compute/algorithms/_binary_search.py
  • python/cuda_compute/cuda/compute/algorithms/_histogram.py
  • python/cuda_compute/cuda/compute/algorithms/_reduce.py
  • python/cuda_compute/cuda/compute/algorithms/_scan.py
  • python/cuda_compute/cuda/compute/algorithms/_segmented_reduce.py
  • python/cuda_compute/cuda/compute/algorithms/_select.py
  • python/cuda_compute/cuda/compute/algorithms/_sort/__init__.py
  • python/cuda_compute/cuda/compute/algorithms/_sort/_merge_sort.py
  • python/cuda_compute/cuda/compute/algorithms/_sort/_radix_sort.py
  • python/cuda_compute/cuda/compute/algorithms/_sort/_segmented_sort.py
  • python/cuda_compute/cuda/compute/algorithms/_sort/_sort_common.py
  • python/cuda_compute/cuda/compute/algorithms/_three_way_partition.py
  • python/cuda_compute/cuda/compute/algorithms/_transform.py
  • python/cuda_compute/cuda/compute/algorithms/_unique_by_key.py
  • python/cuda_compute/cuda/compute/cccl/.gitkeep
  • python/cuda_compute/cuda/compute/determinism.py
  • python/cuda_compute/cuda/compute/iterators/__init__.py
  • python/cuda_compute/cuda/compute/iterators/_base.py
  • python/cuda_compute/cuda/compute/iterators/_cache_modified.py
  • python/cuda_compute/cuda/compute/iterators/_common.py
  • python/cuda_compute/cuda/compute/iterators/_constant.py
  • python/cuda_compute/cuda/compute/iterators/_counting.py
  • python/cuda_compute/cuda/compute/iterators/_discard.py
  • python/cuda_compute/cuda/compute/iterators/_permutation.py
  • python/cuda_compute/cuda/compute/iterators/_pointer.py
  • python/cuda_compute/cuda/compute/iterators/_reverse.py
  • python/cuda_compute/cuda/compute/iterators/_shuffle.py
  • python/cuda_compute/cuda/compute/iterators/_transform.py
  • python/cuda_compute/cuda/compute/iterators/_utils.py
  • python/cuda_compute/cuda/compute/iterators/_zip.py
  • python/cuda_compute/cuda/compute/op.py
  • python/cuda_compute/cuda/compute/struct.py
  • python/cuda_compute/cuda/compute/types.py
  • python/cuda_compute/cuda/compute/typing.py
  • python/cuda_compute/merge_cuda_wheels.py
  • python/cuda_compute/pyproject.toml
  • python/cuda_compute/tests/_utils/__init__.py
  • python/cuda_compute/tests/_utils/device_array.py
  • python/cuda_compute/tests/compute/conftest.py
  • python/cuda_compute/tests/compute/examples/binary_search/__init__.py
  • python/cuda_compute/tests/compute/examples/binary_search/lower_bound_basic.py
  • python/cuda_compute/tests/compute/examples/binary_search/lower_bound_object.py
  • python/cuda_compute/tests/compute/examples/binary_search/upper_bound_basic.py
  • python/cuda_compute/tests/compute/examples/binary_search/upper_bound_object.py
  • python/cuda_compute/tests/compute/examples/free_threading/__init__.py
  • python/cuda_compute/tests/compute/examples/free_threading/direct_api.py
  • python/cuda_compute/tests/compute/examples/free_threading/object_api.py
  • python/cuda_compute/tests/compute/examples/histogram/__init__.py
  • python/cuda_compute/tests/compute/examples/histogram/histogram_even_basic.py
  • python/cuda_compute/tests/compute/examples/histogram/histogram_object.py
  • python/cuda_compute/tests/compute/examples/iterator/__init__.py
  • python/cuda_compute/tests/compute/examples/iterator/cache_modified_iterator_basic.py
  • python/cuda_compute/tests/compute/examples/iterator/constant_iterator_basic.py
  • python/cuda_compute/tests/compute/examples/iterator/counting_iterator_basic.py
  • python/cuda_compute/tests/compute/examples/iterator/discard_iterator_basic.py
  • python/cuda_compute/tests/compute/examples/iterator/permutation_iterator_basic.py
  • python/cuda_compute/tests/compute/examples/iterator/permutation_iterator_composed.py
  • python/cuda_compute/tests/compute/examples/iterator/permutation_iterator_output.py
  • python/cuda_compute/tests/compute/examples/iterator/reverse_input_iterator.py
  • python/cuda_compute/tests/compute/examples/iterator/reverse_output_iterator.py
  • python/cuda_compute/tests/compute/examples/iterator/shuffle_iterator_basic.py
  • python/cuda_compute/tests/compute/examples/iterator/transform_iterator_basic.py
  • python/cuda_compute/tests/compute/examples/iterator/transform_iterator_lambda.py
  • python/cuda_compute/tests/compute/examples/iterator/transform_output_iterator.py
  • python/cuda_compute/tests/compute/examples/iterator/zip_iterator_counting.py
  • python/cuda_compute/tests/compute/examples/iterator/zip_iterator_elementwise.py
  • python/cuda_compute/tests/compute/examples/iterator/zip_iterator_reduction.py
  • python/cuda_compute/tests/compute/examples/partition/__init__.py
  • python/cuda_compute/tests/compute/examples/partition/three_way_partition_basic.py
  • python/cuda_compute/tests/compute/examples/partition/three_way_partition_object.py
  • python/cuda_compute/tests/compute/examples/raw_op/__init__.py
  • python/cuda_compute/tests/compute/examples/raw_op/cpp_stateful.py
  • python/cuda_compute/tests/compute/examples/raw_op/cpp_stateless.py
  • python/cuda_compute/tests/compute/examples/raw_op/llvm_stateless.py
  • python/cuda_compute/tests/compute/examples/reduction/__init__.py
  • python/cuda_compute/tests/compute/examples/reduction/min_reduction.py
  • python/cuda_compute/tests/compute/examples/reduction/minmax_reduction.py
  • python/cuda_compute/tests/compute/examples/reduction/reduce_object.py
  • python/cuda_compute/tests/compute/examples/reduction/sum_custom_reduction.py
  • python/cuda_compute/tests/compute/examples/reduction/sum_reduction.py
  • python/cuda_compute/tests/compute/examples/reduction/sum_reduction_lambda.py
  • python/cuda_compute/tests/compute/examples/scan/__init__.py
  • python/cuda_compute/tests/compute/examples/scan/ema_example.py
  • python/cuda_compute/tests/compute/examples/scan/exclusive_scan_max.py
  • python/cuda_compute/tests/compute/examples/scan/exclusive_scan_object.py
  • python/cuda_compute/tests/compute/examples/scan/inclusive_scan_custom.py
  • python/cuda_compute/tests/compute/examples/scan/inclusive_scan_object.py
  • python/cuda_compute/tests/compute/examples/scan/logcdf_example.py
  • python/cuda_compute/tests/compute/examples/scan/running_average.py
  • python/cuda_compute/tests/compute/examples/scan/segmented_sum.py
  • python/cuda_compute/tests/compute/examples/segmented/__init__.py
  • python/cuda_compute/tests/compute/examples/segmented/segmented_reduce_basic.py
  • python/cuda_compute/tests/compute/examples/segmented/segmented_reduce_object.py
  • python/cuda_compute/tests/compute/examples/select/__init__.py
  • python/cuda_compute/tests/compute/examples/select/select_basic.py
  • python/cuda_compute/tests/compute/examples/select/select_object.py
  • python/cuda_compute/tests/compute/examples/select/select_with_iterator.py
  • python/cuda_compute/tests/compute/examples/select/select_with_side_effect.py
  • python/cuda_compute/tests/compute/examples/serialization/__init__.py
  • python/cuda_compute/tests/compute/examples/serialization/ahead_of_time_compilation.py
  • python/cuda_compute/tests/compute/examples/serialization/serialize_roundtrip.py
  • python/cuda_compute/tests/compute/examples/sort/__init__.py
  • python/cuda_compute/tests/compute/examples/sort/merge_sort_basic.py
  • python/cuda_compute/tests/compute/examples/sort/merge_sort_object.py
  • python/cuda_compute/tests/compute/examples/sort/radix_sort_basic.py
  • python/cuda_compute/tests/compute/examples/sort/radix_sort_buffer.py
  • python/cuda_compute/tests/compute/examples/sort/radix_sort_object.py
  • python/cuda_compute/tests/compute/examples/sort/segmented_sort_basic.py
  • python/cuda_compute/tests/compute/examples/sort/segmented_sort_buffer.py
  • python/cuda_compute/tests/compute/examples/sort/segmented_sort_object.py
  • python/cuda_compute/tests/compute/examples/struct/__init__.py
  • python/cuda_compute/tests/compute/examples/struct/nested_struct_reduction.py
  • python/cuda_compute/tests/compute/examples/struct/nested_struct_tuple_construction.py
  • python/cuda_compute/tests/compute/examples/struct/nested_struct_zip_iterator.py
  • python/cuda_compute/tests/compute/examples/struct/struct_reduction.py
  • python/cuda_compute/tests/compute/examples/struct/struct_transform.py
  • python/cuda_compute/tests/compute/examples/transform/binary_transform_basic.py
  • python/cuda_compute/tests/compute/examples/transform/binary_transform_object.py
  • python/cuda_compute/tests/compute/examples/transform/unary_transform_basic.py
  • python/cuda_compute/tests/compute/examples/transform/unary_transform_object.py
  • python/cuda_compute/tests/compute/examples/unique/__init__.py
  • python/cuda_compute/tests/compute/examples/unique/unique_by_key_basic.py
  • python/cuda_compute/tests/compute/examples/unique/unique_by_key_object.py
  • python/cuda_compute/tests/compute/test_binary_search.py
  • python/cuda_compute/tests/compute/test_bindings.py
  • python/cuda_compute/tests/compute/test_deferred_annotations.py
  • python/cuda_compute/tests/compute/test_free_threading_stress.py
  • python/cuda_compute/tests/compute/test_func_caching.py
  • python/cuda_compute/tests/compute/test_histogram.py
  • python/cuda_compute/tests/compute/test_hostjit_paths.py
  • python/cuda_compute/tests/compute/test_iterators.py
  • python/cuda_compute/tests/compute/test_merge_sort.py
  • python/cuda_compute/tests/compute/test_multi_cc_serialization.py
  • python/cuda_compute/tests/compute/test_nested_struct.py
  • python/cuda_compute/tests/compute/test_no_numba.py
  • python/cuda_compute/tests/compute/test_numba_path_thread_safety.py
  • python/cuda_compute/tests/compute/test_permutation_iterator.py
  • python/cuda_compute/tests/compute/test_radix_sort.py
  • python/cuda_compute/tests/compute/test_raw_op.py
  • python/cuda_compute/tests/compute/test_reduce.py
  • python/cuda_compute/tests/compute/test_scan.py
  • python/cuda_compute/tests/compute/test_segmented_reduce.py
  • python/cuda_compute/tests/compute/test_segmented_sort.py
  • python/cuda_compute/tests/compute/test_select.py
  • python/cuda_compute/tests/compute/test_serialization_diagnostics.py
  • python/cuda_compute/tests/compute/test_shuffle_iterator.py
  • python/cuda_compute/tests/compute/test_struct_field_validation.py
  • python/cuda_compute/tests/compute/test_three_way_partition.py
  • python/cuda_compute/tests/compute/test_transform.py
  • python/cuda_compute/tests/compute/test_unique_by_key.py
  • python/cuda_compute/tests/compute/test_void_ptr_wrapper_validation.py
  • python/cuda_compute/tests/compute/test_zip_iterator.py
  • python/cuda_compute/tests/packaging/test_cuda_compute_metadata.py
  • python/cuda_compute/tests/packaging/test_merge_cuda_wheels.py
  • python/cuda_compute/tests/test_examples.py
  • test/cmake/test_export/CMakeLists.txt
💤 Files with no reviewable changes (9)
  • python/cuda_cccl/cuda/cccl/parallel/init.py
  • python/cuda_cccl/cuda/cccl/headers/init.py
  • python/cuda_cccl/cuda/cccl/headers/include/init.py
  • python/cuda_cccl/tests/headers/test_cuda_cccl.py
  • python/cuda_cccl/LICENSE
  • python/cuda_cccl/cuda/cccl/init.py
  • python/cuda_cccl/cuda/cccl/headers/include_paths.py
  • python/cuda_cccl/cuda/cccl/parallel/experimental/init.py
  • ci/update_version.sh

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added separate cuda-compute, cccl-headers, and aggregate cuda-cccl Python packages.
    • Added header discovery utilities and relocatable CMake package support.
    • Expanded CUDA Compute support with serialization, iterators, custom GPU structures, JIT workflows, and extensive algorithm examples.
    • Added configurable runtime resource paths for HostJIT deployments.
  • Documentation

    • Updated installation, migration, API reference, examples, benchmarks, and Python 3.14 guidance.
  • Quality Improvements

    • Strengthened wheel validation, dependency checks, cross-platform packaging, and automated test coverage.

Walkthrough

Changes

Python package split and implementation

Layer / File(s) Summary
Separate package contracts and compute implementation
python/cccl_headers/..., python/cuda_compute/..., python/cuda_cccl/...
The monolithic Python package is split into cccl-headers, cuda-compute, and the aggregate cuda-cccl metapackage. The new packages define CMake builds, metadata, public APIs, CUDA bindings, algorithms, iterators, serialization, caching, examples, and tests.
Wheel build and release validation
ci/util/python/*, ci/build_*, ci/windows/*, .github/workflows/*
Build and release workflows produce coordinated wheels, merge CUDA-major compute wheels, collect canonical artifacts, validate package contracts, and run dependency checks.
HostJIT and CUDAX packaging
c/parallel.v2/..., lib/cmake/..., test/cmake/test_export/CMakeLists.txt
HostJIT paths become configurable for runtime or embedded resources. CUDAX targets use an imported public wrapper with C++17 compile features and updated export validation.
CI, benchmarks, tests, and documentation
ci/..., docs/python/..., python/cuda_compute/tests/..., AGENTS.md
CI lanes, benchmark setup, documentation paths, package installation instructions, migration guidance, examples, and comprehensive compute/package validation are updated for the split layout.

Possibly related PRs

  • NVIDIA/cccl#9583: Modifies the same HostJIT CMake and libnvcc path handling.
  • NVIDIA/cccl#10230: Also updates merge_cuda_wheels.py to select the correct merged wheel.

Suggested reviewers: wmaxey, shwina, griwes


Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

⏱️ CCCL compile-time benchmark comparison: Public headers compile-time bench

Result: 0 regression row(s), 10 improvement row(s) above threshold.

Run Value
Config public-headers-gcc13
Baseline origin/main
Preset all-dev
Targets cub.headers.base, thrust.cpp.cuda.headers.base, libcudacxx.test.public_headers
GPU / launch args rtx2080 / --cuda 13.3 --host gcc13

Artifacts: reports and traces

TU total compilation

-f total-compilation inclusive --sort total

🟢 TU total compilation — Improvements
Rank Improvement impact Selected Δ Baseline Current Event Matched traces
1 4.797469 -4.797469 16.025452 11.227983 Total Compilation Time: cub/device/dispatch/dispatch_segmented_sort.cuh 1
2 3.473741 -3.473741 12.679953 9.206212 Total Compilation Time: cub/device/dispatch/dispatch_scan.cuh 1
3 3.408079 -3.408079 12.858641 9.450562 Total Compilation Time: cub/device/dispatch/dispatch_streaming_reduce.cuh 1
4 3.315373 -3.315373 10.451914 7.136541 Total Compilation Time: cub/device/dispatch/dispatch_merge.cuh 1
5 3.122769 -3.122769 11.885129 8.762360 Total Compilation Time: cub/device/device_merge.cuh 1

Direct file processing

-f file-processing exclusive --sort total

🟢 Direct file processing — Improvements
Rank Improvement impact Selected Δ Baseline Current Event Matched traces
1 1.656041 -1.656041 9.981552 8.325511 Processing Header File: libcudacxx/include/cuda/std/__cccl/prologue.h 548
2 0.329674 -0.329674 6.421150 6.091476 Processing Header File: libcudacxx/include/cuda/std/__tuple_dir/vector_types.h 238
3 0.311801 -0.311801 2.726132 2.414331 Processing Header File: libcudacxx/include/cuda/std/__atomic/functions/cuda_ptx_generated.h 56
4 0.256368 -0.256368 3.274642 3.018274 Processing Header File: libcudacxx/include/cuda/std/__cccl/epilogue.h 548
5 0.232089 -0.232089 2.256987 2.024898 Processing Header File: cub/cub/device/dispatch/tuning/tuning_scan.cuh 68

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

😬 CI Workflow Results

🟥 Finished in 3h 41m: Pass: 78%/534 | Total: 6d 19h | Max: 1h 29m | Hits: 94%/1272772

See results here.

AI failure analysis

1. Python 3.8 cannot parse parenthesized context managers · 4 jobs

Explanation: Four packaging jobs fail before running the new wheel validation tests because the test file uses syntax introduced after Python 3.8. The packaging environment explicitly selects Python 3.8.10.

Evidence:

CCCL Packaging nvcc Clang / [CTK12.0 Clang14] Test(amd64, RTX2080): -min-cmake, step 4

2026-08-04T08:26:28.8431724Z -- Found Python3: /home/coder/.local/share/venvs/cccl/bin/python3 (found version "3.8.10") found components: Interpreter
2026-08-04T08:26:41.7982510Z   File "/home/coder/cccl/ci/test/python_wheels/test_wheel_scripts.py", line 313
2026-08-04T08:26:41.7983441Z     tempfile.TemporaryDirectory() as temp,

Root cause: The PR added two parenthesized multi-context-manager statements, which Python 3.8 cannot parse. These tests are executed by packaging lanes whose discovered interpreter is Python 3.8.10. Sources: ci/test/python_wheels/test_wheel_scripts.py:311, ci/test/python_wheels/test_wheel_scripts.py:436.

Suggested next steps: Rewrite both statements using Python 3.8-compatible nested or unparenthesized `with` statements, then run `python3.8 ci/test/python_wheels/test_wheel_scripts.py`.

Copy this prompt into a coding agent
Repository: https://github.com/NVIDIA/cccl
Workflow run: https://github.com/NVIDIA/cccl/actions/runs/30885735498
Failure group: Python 3.8 cannot parse parenthesized context managers
Affected jobs:
- CCCL Packaging nvcc Clang / [CTK12.0 Clang14] Test(amd64, RTX2080): -min-cmake: https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352471
- CCCL Packaging nvcc Clang / [CTK12.9 Clang14] Test(amd64, T4): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352529
- CCCL Packaging nvcc GCC / [CTK12.9 GCC10] Test(amd64, T4): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352546
- CCCL Packaging nvcc GCC / [CTK12.0 GCC10] Test(amd64, RTX2080): -min-cmake: https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352614

Reproduce the syntax failure with Python 3.8, then update both parenthesized `with` statements in `ci/test/python_wheels/test_wheel_scripts.py` to syntax supported by Python 3.8, preserving the subTest and TemporaryDirectory scopes. Run the wheel-script unit test with Python 3.8 and the focused packaging CTest if available, and verify the file still works on the repository's newer Python versions.

Jobs:

2. Unused start_block variable is promoted to a CUDA error · 37 jobs

Explanation: All cudax NVCC build matrices stop because `start_block` is assigned but never meaningfully used, and warning 550-D is promoted to an error. This blocks Clang, GCC, amd64, arm64, C++17, and C++20 configurations alike.

Evidence:

cudax nvcc Clang / [CTK12.9 Clang14 C++20] Build(amd64), step 4

2026-08-04T07:03:43.2680080Z /home/coder/cccl/cudax/include/cuda/experimental/__places/localized_array.cuh(471): error #550-D: variable "start_block" was set but never used
2026-08-04T07:03:43.2683471Z 1 error detected in the compilation of "/home/coder/cccl/cudax/test/places/stream_pool.cu".

cudax nvcc GCC / [CTK12.9 GCC14 C++17] Build(amd64), step 4

2026-08-04T07:05:18.8059017Z /home/coder/cccl/cudax/include/cuda/experimental/__places/localized_array.cuh(471): error #550-D: variable "start_block" was set but never used

Root cause: `localized_array.cuh` computes `start_block` but does not include it in the allocation-map output or otherwise consume its value. NVCC still diagnoses it as set-but-unused despite the void cast, and the build promotes that warning to an error. Sources: cudax/include/cuda/experimental/__places/localized_array.cuh:471, cudax/include/cuda/experimental/__places/localized_array.cuh:472.

Suggested next steps: Remove `start_block` and its void cast unless the allocation map is intended to display it. Rebuild a single failing target such as `cudax.test.places.stream_pool` with warnings promoted before rerunning the matrix.

Copy this prompt into a coding agent
Repository: https://github.com/NVIDIA/cccl
Workflow run: https://github.com/NVIDIA/cccl/actions/runs/30885735498
Failure group: Unused start_block variable is promoted to a CUDA error
Affected jobs:
- cudax nvcc Clang / [CTK12.9 Clang14 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352331
- cudax nvcc Clang / [CTK13.0 Clang15 C++17] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352344
- cudax nvcc Clang / [CTK12.0 Clang14 C++17] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352348
- cudax nvcc Clang / [CTK13.0 Clang20 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352355
- cudax nvcc Clang / [CTK12.0 Clang14 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352357
- cudax nvcc Clang / [CTK13.3 Clang15 C++17] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352371
- cudax nvcc Clang / [CTK12.9 Clang19 C++17] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352374
- cudax nvcc Clang / [CTK12.9 Clang14 C++17] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352401
- cudax nvcc Clang / [CTK13.0 Clang20 C++17] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352406
- cudax nvcc Clang / [CTK13.3 Clang16 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352425
- cudax nvcc Clang / [CTK13.3 Clang19 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352427
- cudax nvcc Clang / [CTK13.3 Clang18 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352436
- cudax nvcc Clang / [CTK13.3 Clang21 C++17] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352441
- cudax nvcc Clang / [CTK13.3 Clang15 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352451
- cudax nvcc Clang / [CTK12.9 Clang19 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352458
- cudax nvcc Clang / [CTK13.3 Clang20 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352462
- cudax nvcc Clang / [CTK13.0 Clang15 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352467
- cudax nvcc Clang / [CTK13.3 Clang21 C++20] Build(arm64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352468
- cudax nvcc Clang / [CTK13.3 Clang17 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352481
- cudax nvcc GCC / [CTK12.9 GCC14 C++17] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352806
- cudax nvcc GCC / [CTK12.0 GCC9 C++17] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352814
- cudax nvcc GCC / [CTK12.0 GCC12 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352816
- cudax nvcc GCC / [CTK12.0 GCC12 C++17] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352823
- cudax nvcc GCC / [CTK13.0 GCC11 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352848
- cudax nvcc GCC / [CTK13.0 GCC15 C++17] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352854
- cudax nvcc GCC / [CTK12.9 GCC9 C++17] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352862
- cudax nvcc GCC / [CTK13.3 GCC11 C++17] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352873
- cudax nvcc GCC / [CTK12.9 GCC14 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352874
- cudax nvcc GCC / [CTK13.0 GCC15 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352886
- cudax nvcc GCC / [CTK13.3 GCC15 C++20] Build(arm64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352909
- cudax nvcc GCC / [CTK13.3 GCC11 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352914
- cudax nvcc GCC / [CTK13.0 GCC11 C++17] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352938
- cudax nvcc GCC / [CTK13.3 GCC15 C++17] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352977
- cudax nvcc GCC / [CTK13.3 GCC12 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917353009
- cudax nvcc GCC / Sw / [CTK13.3 GCC15 C++20] Build(amd64): sm{90}: https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917354748
- cudax nvcc GCC / Sg / [CTK13.3 GCC15 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917355387
- cudax nvcc Clang / RY / [CTK13.3 Clang21 C++20] Build(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917356706

Narrowly reproduce the NVCC 550-D failure in a cudax places target. Inspect the allocation-map formatting in `cudax/include/cuda/experimental/__places/localized_array.cuh`; if the start block is not intended for output, remove the `start_block` declaration and `(void) start_block`, otherwise add it to the formatted output consistently. Run a focused cudax places build with warnings promoted to errors, followed by representative C++17 and C++20 validation.

Jobs:

3. Wheel build script tries to delete a mounted directory · 6 jobs

Explanation: Six Python wheel jobs exit immediately when startup cleanup attempts to remove the `wheelhouse` directory itself. CI mounts that path as a Docker volume, so the mount point cannot be unlinked.

Evidence:

Python nvcc GCC / Yk / [CTK12.9 GCC13 py3.10] Build CCCL Python wheels(amd64), step 4

2026-08-04T07:03:43.6315217Z rm: cannot remove 'wheelhouse': Device or resource busy

Python (cuda.compute on v2/HostJIT) nvcc GCC / YY / [CTK12.9 GCC13 py3.14t] Build CCCL Python wheels(amd64), step 4

2026-08-04T07:05:25.9073314Z rm: cannot remove 'wheelhouse': Device or resource busy

Python (cuda.compute free-threaded ThreadSanitizer) nvcc GCC / X8 / [CTK12.9 GCC13 py3.14t] Build CCCL Python wheels(amd64), step 4

2026-08-04T07:04:41.7658929Z rm: cannot remove 'wheelhouse': Device or resource busy

Root cause: The PR changed startup cleanup to `rm -rf wheelhouse wheelhouse_merged wheelhouse_final`. The CI container mounts `wheelhouse` as a named volume, making removal of the directory itself fail under `set -e`. Sources: ci/build_cuda_cccl_python.sh:61.

Suggested next steps: Preserve the mounted `wheelhouse` directory and delete only its contents, while continuing to remove the unmounted intermediate directories. Validate with `./ci/build_cuda_cccl_python.sh -py-version 3.14` inside the CI devcontainer.

Copy this prompt into a coding agent
Repository: https://github.com/NVIDIA/cccl
Workflow run: https://github.com/NVIDIA/cccl/actions/runs/30885735498
Failure group: Wheel build script tries to delete a mounted directory
Affected jobs:
- Python nvcc GCC / Yk / [CTK12.9 GCC13 py3.10] Build CCCL Python wheels(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917355084
- Python nvcc GCC / bU / [CTK12.9 GCC13 py3.14t] Build CCCL Python wheels(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917355381
- Python (cuda.compute on v2/HostJIT) nvcc GCC / YY / [CTK12.9 GCC13 py3.14t] Build CCCL Python wheels(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917355493
- Python (cuda.compute on v2/HostJIT) nvcc GCC / YI / [CTK12.9 GCC13 py3.14] Build CCCL Python wheels(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917355507
- Python nvcc GCC / ZE / [CTK12.9 GCC13 py3.14] Build CCCL Python wheels(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917355648
- Python (cuda.compute free-threaded ThreadSanitizer) nvcc GCC / X8 / [CTK12.9 GCC13 py3.14t] Build CCCL Python wheels(amd64): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917356276

Reproduce the wheel-build startup failure in the CI devcontainer where `wheelhouse` is a mounted volume. Change `ci/build_cuda_cccl_python.sh` so cleanup empties an existing `wheelhouse` without removing the mount point—for example, use `find wheelhouse -mindepth 1 -delete`, creating it only when absent—then separately remove `wheelhouse_merged` and `wheelhouse_final`. Verify the regular, HostJIT v2, and TSan wrapper scripts all pass startup and run focused shell validation.

Jobs:

4. CMake scratch paths exceed Windows MAX_PATH · 12 jobs

Explanation: Twelve Windows header-package jobs fail while configuring the new cudax consumer-safety test. The pytest temporary directory, descriptive test name, build suffix, and CMake TryCompile tree combine into an MSBuild path longer than 260 characters.

Evidence:

Python nvcc MSVC / cc / [CTK12.0 MSVC14.44 py3.14] Test cuda.cccl.headers(amd64, L4), step 4

2026-08-04T07:52:38.5846496Z E                 C:\msbuild\17\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(203,5): error MSB4018: System.InvalidOperationException: The item metadata "%(FullPath)" cannot be applied to the path "cmTC_4b688.dir\Debug\cmTC_4b688.tlog\ParallelCustomBuild.command.1.tlog". Path: cmTC_4b688.dir\Debug\cmTC_4b688.tlog\ParallelCustomBuild.command.1.tlog exceeds the OS max path limit. The fully qualified file name must be less than 260 characters. [C:\Users\ContainerAdministrator\AppData\Local\Temp\pytest-of-ContainerAdministrator\pytest-0\popen-gw6\test_cudax_cmake_target_is_con0\build-False\CMakeFiles\CMakeScratch\TryCompile-x5bmtj\cmTC_4b688.vcxproj]
2026-08-04T07:52:38.5819428Z E             CMake Error at C:/Program Files/CMake/share/cmake-4.1/Modules/CMakeTestCXXCompiler.cmake:73 (message):

Python nvcc MSVC / b8 / [CTK12.9 MSVC14.44 py3.10] Test cuda.cccl.headers(amd64, L4), step 4

2026-08-04T07:58:06.7743426Z E                 C:\msbuild\17\MSBuild\Microsoft\VC\v170\Microsoft.CppCommon.targets(203,5): error MSB4018: System.InvalidOperationException: The item metadata "%(FullPath)" cannot be applied to the path "cmTC_c08c3.dir\Debug\cmTC_c08c3.tlog\ParallelCustomBuild.command.1.tlog". Path: cmTC_c08c3.dir\Debug\cmTC_c08c3.tlog\ParallelCustomBuild.command.1.tlog exceeds the OS max path limit. The fully qualified file name must be less than 260 characters. [C:\Users\ContainerAdministrator\AppData\Local\Temp\pytest-of-ContainerAdministrator\pytest-0\popen-gw6\test_cudax_cmake_target_is_con0\build-False\CMakeFiles\CMakeScratch\TryCompile-rh3hwo\cmTC_c08c3.vcxproj]

Root cause: The new test creates `build-False` and `build-True` beneath pytest's already long per-test temporary path. Visual Studio's generated CMake compiler-check files then exceed the runner's effective 260-character path limit. Sources: python/cccl_headers/tests/test_cccl_headers.py:240, python/cccl_headers/tests/test_cccl_headers.py:247.

Suggested next steps: Use a substantially shorter build root and directory names on Windows, such as a short temporary root plus `b0` and `b1`, with reliable cleanup. Run `pytest -q python/cccl_headers/tests/test_cccl_headers.py::test_cudax_cmake_target_is_consumer_safe` on Windows.

Copy this prompt into a coding agent
Repository: https://github.com/NVIDIA/cccl
Workflow run: https://github.com/NVIDIA/cccl/actions/runs/30885735498
Failure group: CMake scratch paths exceed Windows MAX_PATH
Affected jobs:
- Python nvcc MSVC / cc / [CTK12.0 MSVC14.44 py3.14] Test cuda.cccl.headers(amd64, L4): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91924008269
- Python nvcc MSVC / cc / [CTK13.0 MSVC14.44 py3.14] Test cuda.cccl.headers(amd64, L4): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91924008272
- Python nvcc MSVC / cc / [CTK13.3 MSVC14.44 py3.14] Test cuda.cccl.headers(amd64, L4): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91924008274
- Python nvcc MSVC / cc / [CTK12.0 MSVC14.44 py3.14 ctk-sysctk] Test cuda.cccl.headers(amd64, L4): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91924008282
- Python nvcc MSVC / cc / [CTK12.9 MSVC14.44 py3.14 ctk-latest] Test cuda.cccl.headers(amd64, L4): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91924008289
- Python nvcc MSVC / cc / [CTK13.3 MSVC14.44 py3.14 ctk-latest] Test cuda.cccl.headers(amd64, L4): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91924008307
- Python nvcc MSVC / cc / [CTK12.9 MSVC14.44 py3.14] Test cuda.cccl.headers(amd64, L4): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91924008347
- Python nvcc MSVC / cc / [CTK13.0 MSVC14.44 py3.14 ctk-sysctk] Test cuda.cccl.headers(amd64, L4): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91924008435
- Python nvcc MSVC / cc / [CTK13.3 MSVC14.44 py3.14 ctk-sysctk] Test cuda.cccl.headers(amd64, L4): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91924008458
- Python nvcc MSVC / cc / [CTK12.9 MSVC14.44 py3.14 ctk-sysctk] Test cuda.cccl.headers(amd64, L4): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91924008491
- Python nvcc MSVC / b8 / [CTK13.3 MSVC14.44 py3.10] Test cuda.cccl.headers(amd64, L4): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91924075149
- Python nvcc MSVC / b8 / [CTK12.9 MSVC14.44 py3.10] Test cuda.cccl.headers(amd64, L4): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91924075187

Reproduce the consumer-safety test on Windows with the Visual Studio generator. Modify `test_cudax_cmake_target_is_consumer_safe` so its CMake build and TryCompile trees live under a short, uniquely allocated Windows path rather than the long pytest `tmp_path`; use short build names and guarantee cleanup without weakening the test. Run the single pytest test for both `ENABLE_CUDA` values, then the focused `python/cccl_headers/tests` suite on Windows.

Jobs:

5. Select example subprocess exits without diagnostics on Windows · 1 job

Explanation: The Windows cuda.compute example suite passes 69 tests but the select-basic module fails when launched as a separate script. The harness reports an empty stderr and omits the subprocess return code, so the log cannot distinguish a Python exception from a native process crash.

Evidence:

Python nvcc MSVC / cc / [CTK12.0 MSVC14.44 py3.14 ctk-sysctk] Test cuda.compute examples(amd64, L4), step 4

2026-08-04T08:02:54.5901284Z E       AssertionError: assert False
2026-08-04T08:02:54.5902164Z E        +  where False = run_example_module('compute.examples.select.select_basic', 'Compute - Select - Select Basic')
2026-08-04T08:02:54.5910521Z Testing Compute - Select - Select Basic...\nSelected 4 items: [2 4 6 8]\n  Running compute.examples.select.select_basic as script...\n\u2717 Compute - Select - Select Basic examples failed: Module execution failed:

Root cause: The saved log proves the module succeeds during in-process discovery but its script subprocess returns nonzero with no stderr. The actual subprocess exit code and stdout are not logged, so evidence is insufficient to identify whether the cause is a Windows-native crash, teardown failure, or script-only behavior. Sources: python/cuda_compute/tests/test_examples.py:119, python/cuda_compute/tests/test_examples.py:125, python/cuda_compute/tests/test_examples.py:150.

Suggested next steps: First include the return code, stdout, and stderr in the raised failure, then rerun only the select-basic example on Windows without xdist. Use the resulting exit status to determine whether the example or its subprocess lifecycle needs correction.

Copy this prompt into a coding agent
Repository: https://github.com/NVIDIA/cccl
Workflow run: https://github.com/NVIDIA/cccl/actions/runs/30885735498
Failure group: Select example subprocess exits without diagnostics on Windows
Affected jobs:
- Python nvcc MSVC / cc / [CTK12.0 MSVC14.44 py3.14 ctk-sysctk] Test cuda.compute examples(amd64, L4): https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91924008332

Reproduce `test_compute_examples_select_select_basic` on Windows with `pytest -q -s python/cuda_compute/tests/test_examples.py::test_compute_examples_select_select_basic` and without xdist. Improve `run_example_module` so a failed subprocess reports `returncode`, stdout, and stderr, then use those diagnostics to identify and fix the script-only select failure. Run the single example test repeatedly and a focused select example validation; do not mask a native crash by merely relaxing the assertion.

Jobs:

6. Clang 21 tidy checks are promoted to errors · 1 job

Explanation: The clang-tidy lane reports multiple cudax header diagnostics as errors, beginning with a forwarding-reference constructor that can hide copy and move constructors. Additional modernize diagnostics follow, so the tidy target cannot complete.

Evidence:

clang-tidy ClangCUDA / [CTK12.9 Clang21 C++17] Build(amd64): sm{75}, step 4

2026-08-04T07:43:47.0274852Z /home/coder/cccl/cudax/include/cuda/experimental/__execution/domain.cuh:405:35: error: constructor accepting a forwarding reference can hide the copy and move constructors [bugprone-forwarding-reference-overload,-warnings-as-errors]
2026-08-04T07:43:47.0283053Z /home/coder/cccl/cudax/include/cuda/experimental/__execution/lazy.cuh:78:25: error: use '= default' to define a trivial default constructor [modernize-use-equals-default,-warnings-as-errors]
2026-08-04T07:43:47.0292256Z /home/coder/cccl/cudax/include/cuda/experimental/__execution/parallel_scheduler_backend.cuh:126:30: error: 'override' is redundant since the function is already declared 'final' [modernize-use-override,-warnings-as-errors]

Root cause: The Clang 21 tidy configuration enables checks that diagnose existing cudax declarations, with all warnings treated as errors. The first failure is an unconstrained forwarding-reference constructor in `__not_a_domain`; the log also contains independent modernize findings that must be fixed or deliberately suppressed. Sources: cudax/include/cuda/experimental/__execution/domain.cuh:405.

Suggested next steps: Address the complete set of logged tidy diagnostics, starting by constraining or replacing the forwarding-reference constructor without breaking copy/move behavior. Rerun the focused ClangCUDA `all-tidy` target with Clang 21.

Copy this prompt into a coding agent
Repository: https://github.com/NVIDIA/cccl
Workflow run: https://github.com/NVIDIA/cccl/actions/runs/30885735498
Failure group: Clang 21 tidy checks are promoted to errors
Affected jobs:
- clang-tidy ClangCUDA / [CTK12.9 Clang21 C++17] Build(amd64): sm{75}: https://github.com/NVIDIA/cccl/actions/runs/30885735498/job/91917352163

Reproduce the Clang 21 ClangCUDA tidy target and review every warnings-as-errors diagnostic in the saved output. Fix the forwarding-reference constructor in `cudax/include/cuda/experimental/__execution/domain.cuh` so it cannot shadow copy or move construction, then apply behavior-preserving fixes for the reported modernize findings or narrowly justify suppressions where CUDA constraints require them. Run the focused affected tidy targets and then the full `all-tidy` target.

Jobs:

Comment on lines +3 to +4
`cuda-compute` provides the `cuda.compute` Python interface to the
[CUDA Core Compute Libraries](https://nvidia.github.io/cccl/cpp.html#cccl-cpp-libraries).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

| `cuda-compute` | `cuda.compute` | Device-level algorithms and iterators |
| `cccl-headers` | `cuda.cccl.headers` | CCCL headers and CMake package files |
| `cuda-cccl` | None | Aggregate metapackage |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
iterators.

I'd honestly just get rid of this part. One could consider it an implementation detail that cuda.compute depends on cccl-headers. cuda-cccl (the new metapackage) can explain what it is in its README, but cuda-compute (the downstream package) need not do that.

Comment on lines +41 to +55
The `cuda-cccl` metapackage forwards the same extras, so existing aggregate
installs such as `pip install cuda-cccl[cu13]` continue to install this package.

For a header-only installation, install `cccl-headers` directly and use its
public entry point:

```bash
pip install cccl-headers
```

```python
from cuda.cccl.headers import get_include_paths

include_paths = get_include_paths()
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's preferably leave this out from the README.

Comment on lines +57 to +58
When developing from a source checkout, install the sibling header project
before this project so the exact dependency is resolved locally:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm - is there any way to express this kind of "local" dependency for editable installs? It's a bit sad that we need two install commands

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Review

Development

Successfully merging this pull request may close these issues.

3 participants