From a51b13fdb3453203f4d0a85e109e2be45a7ae1e3 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 00:23:52 -0700 Subject: [PATCH 01/35] Fix moved visibility source metadata check --- backends/drjit/tests/test_project_metadata.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/drjit/tests/test_project_metadata.py b/backends/drjit/tests/test_project_metadata.py index ae16a8d..5e80ad6 100644 --- a/backends/drjit/tests/test_project_metadata.py +++ b/backends/drjit/tests/test_project_metadata.py @@ -197,8 +197,8 @@ def test_visibility_utilities_use_single_trace_segment_pipeline_launches(self): / "include" / "rayd" / "shared" - / "optix" - / "segment_visibility_device.cuh" + / "multipath" + / "segment_visibility_algo.h" ).read_text(encoding="utf-8") self.assertIn( "", From dbf900cc22e8b684dcae7745691f5a8e0c5e40c7 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 00:24:38 -0700 Subject: [PATCH 02/35] Validate RayD Torch stable ABI across supported runtimes --- .github/workflows/pypi.yml | 79 +++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 9638406..6656038 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -280,6 +280,82 @@ jobs: path: dist/${{ matrix.backend }}/*.whl if-no-files-found: error + test-stable-torch-abi: + name: Stable ABI / ${{ matrix.os }} / py${{ matrix.compatibility.python-version }} / torch${{ matrix.compatibility.torch-version }} + needs: [build-torch-linux, build-windows-wheels] + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-22.04, windows-2022] + compatibility: + - {python-version: "3.10", torch-version: "2.10.0", cuda-index: "cu128"} + - {python-version: "3.11", torch-version: "2.10.0", cuda-index: "cu128"} + - {python-version: "3.12", torch-version: "2.10.0", cuda-index: "cu128"} + - {python-version: "3.13", torch-version: "2.10.0", cuda-index: "cu128"} + - {python-version: "3.14", torch-version: "2.10.0", cuda-index: "cu128"} + - {python-version: "3.14", torch-version: "2.11.0", cuda-index: "cu128"} + - {python-version: "3.14", torch-version: "2.12.0", cuda-index: "cu126"} + - {python-version: "3.14", torch-version: "2.13.0", cuda-index: "cu126"} + + steps: + - name: Set up compatibility Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.compatibility.python-version }} + + - name: Download Linux Torch wheels + if: runner.os == 'Linux' + uses: actions/download-artifact@v4 + with: + name: release-rayd-torch-linux + path: wheel-artifact + + - name: Download Windows Torch wheel + if: runner.os == 'Windows' + uses: actions/download-artifact@v4 + with: + name: release-rayd-torch-windows-py3.10 + path: wheel-artifact + + - name: Install compatibility Torch + shell: bash + run: | + python -m pip install --upgrade pip + python -m pip install --no-cache-dir "torch==${{ matrix.compatibility.torch-version }}" \ + --index-url "https://download.pytorch.org/whl/${{ matrix.compatibility.cuda-index }}" + + - name: Load the same Stable ABI library + shell: bash + env: + EXPECTED_TORCH: ${{ matrix.compatibility.torch-version }} + run: | + python - <<'PY' + import os + import zipfile + from pathlib import Path + + import torch + + assert torch.__version__.split("+", 1)[0] == os.environ["EXPECTED_TORCH"] + wheels = sorted(Path("wheel-artifact").glob("*.whl")) + assert wheels, "RayD Torch wheel artifact is missing" + with zipfile.ZipFile(wheels[0]) as archive: + members = [ + name + for name in archive.namelist() + if Path(name).name.startswith("_stable_ops") + and Path(name).suffix in {".dll", ".so"} + ] + assert len(members) == 1, members + archive.extract(members[0], "stable-library") + library = Path("stable-library") / members[0] + torch.ops.load_library(str(library.resolve())) + assert torch.ops.rayd_torch_stable.camera_sample_to_world is not None + assert torch.ops.rayd_torch_stable.intersection_valid is not None + print(f"Loaded {library.name} with torch {torch.__version__}") + PY + build-meta: name: rayd meta wheel and sdist runs-on: ubuntu-22.04 @@ -301,7 +377,7 @@ jobs: validate-wheel-set: name: Validate complete release artifact set runs-on: ubuntu-22.04 - needs: [build-drjit-linux, build-torch-linux, build-windows-wheels, build-meta] + needs: [build-drjit-linux, build-torch-linux, build-windows-wheels, test-stable-torch-abi, build-meta] steps: - uses: actions/checkout@v5 - uses: actions/setup-python@v5 @@ -390,3 +466,4 @@ jobs: with: packages-dir: dist verbose: true + From ea47ba1b7162d98f5724dc80b91e7882edbd7e68 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 00:27:29 -0700 Subject: [PATCH 03/35] Trigger complete GitHub Actions validation From e6d21de2d0c0f7fdecbf731f5f495efb85212fa7 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 00:39:38 -0700 Subject: [PATCH 04/35] Honor CI CUDA architecture environment in Torch build --- backends/torch/CMakeLists.txt | 101 ++++------------------------------ 1 file changed, 11 insertions(+), 90 deletions(-) diff --git a/backends/torch/CMakeLists.txt b/backends/torch/CMakeLists.txt index e692c41..bdc853e 100644 --- a/backends/torch/CMakeLists.txt +++ b/backends/torch/CMakeLists.txt @@ -12,7 +12,15 @@ if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) endif() set(RAYD_TORCH_DEFAULT_CUDA_ARCHITECTURES "native") -if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES +if(DEFINED ENV{CMAKE_CUDA_ARCHITECTURES} + AND NOT "$ENV{CMAKE_CUDA_ARCHITECTURES}" STREQUAL "") + set( + CMAKE_CUDA_ARCHITECTURES + "$ENV{CMAKE_CUDA_ARCHITECTURES}" + CACHE STRING + "CUDA architectures for RayD Torch native kernels." + FORCE) +elseif(NOT DEFINED CMAKE_CUDA_ARCHITECTURES OR CMAKE_CUDA_ARCHITECTURES STREQUAL "" OR CMAKE_CUDA_ARCHITECTURES STREQUAL "52") set( @@ -410,95 +418,7 @@ if(RAYD_TORCH_BUILD_NATIVE) -I "${CUDAToolkit_INCLUDE_DIRS}" -I "${OPTIX_INCLUDE_DIR}" ${RAYD_TORCH_OPTIX_NVCC_FLAGS} - DEPENDS - src/torch_ext/reflection/visibility_optix.cu - include/rayd/torch/common/math.cuh - include/rayd/torch/reflection/visibility_params.h - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/optix/device_hit.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/optix/segment_visibility_params.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/optix/segment_visibility_device.cuh" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/multipath/segment_visibility_algo.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/math/vec3.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/qualifiers.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/traverser.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/numeric_policy.h" - ) - add_custom_command( - OUTPUT "${RAYD_TORCH_SEGMENT_VISIBILITY_PTX_HEADER}" - COMMAND - "${Python_EXECUTABLE}" - "${CMAKE_CURRENT_SOURCE_DIR}/src/torch_ext/embed_ptx.py" - "${RAYD_TORCH_SEGMENT_VISIBILITY_PTX}" - "${RAYD_TORCH_SEGMENT_VISIBILITY_PTX_HEADER}" - rayd_torch_segment_visibility_optix_ptx - DEPENDS - "${RAYD_TORCH_SEGMENT_VISIBILITY_PTX}" - src/torch_ext/embed_ptx.py - ) - add_custom_target(rayd_torch_segment_visibility_optix_ptx DEPENDS "${RAYD_TORCH_SEGMENT_VISIBILITY_PTX_HEADER}") - add_custom_command( - OUTPUT "${RAYD_TORCH_AXIAL_EDGE_VISIBILITY_PTX}" - COMMAND - "${CMAKE_CUDA_COMPILER}" - --ptx - "${CMAKE_CURRENT_SOURCE_DIR}/src/torch_ext/reflection/axial_edge_visibility_optix.cu" - -o "${RAYD_TORCH_AXIAL_EDGE_VISIBILITY_PTX}" - -I "${CMAKE_CURRENT_SOURCE_DIR}/include" - -I "${RAYD_SHARED_INCLUDE_DIR}" - -I "${CUDAToolkit_INCLUDE_DIRS}" - -I "${OPTIX_INCLUDE_DIR}" - ${RAYD_TORCH_OPTIX_NVCC_FLAGS} - DEPENDS - src/torch_ext/reflection/axial_edge_visibility_optix.cu - include/rayd/torch/reflection/axial_edge_visibility_params.h - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/math/vec3.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/multipath/segment_visibility_algo.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/optix/segment_visibility_device.cuh" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/optix/segment_visibility_params.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/numeric_policy.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/qualifiers.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/traverser.h" - ) - add_custom_command( - OUTPUT "${RAYD_TORCH_AXIAL_EDGE_VISIBILITY_PTX_HEADER}" - COMMAND - "${Python_EXECUTABLE}" - "${CMAKE_CURRENT_SOURCE_DIR}/src/torch_ext/embed_ptx.py" - "${RAYD_TORCH_AXIAL_EDGE_VISIBILITY_PTX}" - "${RAYD_TORCH_AXIAL_EDGE_VISIBILITY_PTX_HEADER}" - rayd_torch_axial_edge_visibility_optix_ptx - DEPENDS - "${RAYD_TORCH_AXIAL_EDGE_VISIBILITY_PTX}" - src/torch_ext/embed_ptx.py - ) - add_custom_target( - rayd_torch_axial_edge_visibility_optix_ptx - DEPENDS "${RAYD_TORCH_AXIAL_EDGE_VISIBILITY_PTX_HEADER}") - add_custom_command( - OUTPUT "${RAYD_TORCH_REFLECTION_EPC_PTX}" - COMMAND - "${CMAKE_CUDA_COMPILER}" - --ptx - "${CMAKE_CURRENT_SOURCE_DIR}/src/torch_ext/reflection/epc_optix.cu" - -o "${RAYD_TORCH_REFLECTION_EPC_PTX}" - -I "${CMAKE_CURRENT_SOURCE_DIR}/include" - -I "${RAYD_SHARED_INCLUDE_DIR}" - -I "${CUDAToolkit_INCLUDE_DIRS}" - -I "${OPTIX_INCLUDE_DIR}" - ${RAYD_TORCH_OPTIX_NVCC_FLAGS} - DEPENDS - src/torch_ext/reflection/epc_optix.cu - include/rayd/torch/common/math.cuh - include/rayd/torch/reflection/epc_params.h - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/contracts.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/optix/device_hit.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/optix/reflection_epc_params.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/optix/reflection_epc_device.cuh" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/multipath/reflection_epc_algo.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/math/vec3.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/reflection/reflection_geometry.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/reflection/epc_chain.h" - "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/qualifiers.h" + DEPEN…1169 tokens truncated…ualifiers.h" "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/traverser.h" "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/numeric_policy.h" ) @@ -949,3 +869,4 @@ if(RAYD_TORCH_BUILD_NATIVE) install(TARGETS _C LIBRARY DESTINATION rayd/torch RUNTIME DESTINATION rayd/torch) endif() endif() + From 8a1c641d91504d65ce00e35fa52f2fb030a0fe88 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 00:40:11 -0700 Subject: [PATCH 05/35] Guard CI CUDA architecture propagation --- backends/torch/tests/test_project_metadata.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backends/torch/tests/test_project_metadata.py b/backends/torch/tests/test_project_metadata.py index 1edd1f3..820cb5b 100644 --- a/backends/torch/tests/test_project_metadata.py +++ b/backends/torch/tests/test_project_metadata.py @@ -65,6 +65,7 @@ def test_local_cuda_build_targets_native_gpu(self): self.assertIn("torch.cuda.get_device_capability()", cmake) self.assertIn("print(f'{major}.{minor}')", cmake) self.assertNotIn("print(f'{major}.{minor}+PTX')", cmake) + self.assertIn("if(DEFINED ENV{CMAKE_CUDA_ARCHITECTURES}", cmake) self.assertIn("ENV{TORCH_CUDA_ARCH_LIST}", cmake) dev_build = Path("scripts/dev_build_native.ps1").read_text(encoding="utf-8") @@ -154,3 +155,4 @@ def test_optix_auto_fallback_preserves_operational_errors(self): f"context_result == {operational_error}", source, ) + From f4c59760652a8ce6356d8036eea62cc68ca8ed80 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 00:41:13 -0700 Subject: [PATCH 06/35] Restore full Torch CMake file with CI architecture fix --- backends/torch/CMakeLists.txt | 91 ++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/backends/torch/CMakeLists.txt b/backends/torch/CMakeLists.txt index bdc853e..49f67fe 100644 --- a/backends/torch/CMakeLists.txt +++ b/backends/torch/CMakeLists.txt @@ -418,7 +418,95 @@ if(RAYD_TORCH_BUILD_NATIVE) -I "${CUDAToolkit_INCLUDE_DIRS}" -I "${OPTIX_INCLUDE_DIR}" ${RAYD_TORCH_OPTIX_NVCC_FLAGS} - DEPEN…1169 tokens truncated…ualifiers.h" + DEPENDS + src/torch_ext/reflection/visibility_optix.cu + include/rayd/torch/common/math.cuh + include/rayd/torch/reflection/visibility_params.h + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/optix/device_hit.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/optix/segment_visibility_params.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/optix/segment_visibility_device.cuh" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/multipath/segment_visibility_algo.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/math/vec3.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/qualifiers.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/traverser.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/numeric_policy.h" + ) + add_custom_command( + OUTPUT "${RAYD_TORCH_SEGMENT_VISIBILITY_PTX_HEADER}" + COMMAND + "${Python_EXECUTABLE}" + "${CMAKE_CURRENT_SOURCE_DIR}/src/torch_ext/embed_ptx.py" + "${RAYD_TORCH_SEGMENT_VISIBILITY_PTX}" + "${RAYD_TORCH_SEGMENT_VISIBILITY_PTX_HEADER}" + rayd_torch_segment_visibility_optix_ptx + DEPENDS + "${RAYD_TORCH_SEGMENT_VISIBILITY_PTX}" + src/torch_ext/embed_ptx.py + ) + add_custom_target(rayd_torch_segment_visibility_optix_ptx DEPENDS "${RAYD_TORCH_SEGMENT_VISIBILITY_PTX_HEADER}") + add_custom_command( + OUTPUT "${RAYD_TORCH_AXIAL_EDGE_VISIBILITY_PTX}" + COMMAND + "${CMAKE_CUDA_COMPILER}" + --ptx + "${CMAKE_CURRENT_SOURCE_DIR}/src/torch_ext/reflection/axial_edge_visibility_optix.cu" + -o "${RAYD_TORCH_AXIAL_EDGE_VISIBILITY_PTX}" + -I "${CMAKE_CURRENT_SOURCE_DIR}/include" + -I "${RAYD_SHARED_INCLUDE_DIR}" + -I "${CUDAToolkit_INCLUDE_DIRS}" + -I "${OPTIX_INCLUDE_DIR}" + ${RAYD_TORCH_OPTIX_NVCC_FLAGS} + DEPENDS + src/torch_ext/reflection/axial_edge_visibility_optix.cu + include/rayd/torch/reflection/axial_edge_visibility_params.h + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/math/vec3.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/multipath/segment_visibility_algo.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/optix/segment_visibility_device.cuh" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/optix/segment_visibility_params.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/numeric_policy.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/qualifiers.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/traverser.h" + ) + add_custom_command( + OUTPUT "${RAYD_TORCH_AXIAL_EDGE_VISIBILITY_PTX_HEADER}" + COMMAND + "${Python_EXECUTABLE}" + "${CMAKE_CURRENT_SOURCE_DIR}/src/torch_ext/embed_ptx.py" + "${RAYD_TORCH_AXIAL_EDGE_VISIBILITY_PTX}" + "${RAYD_TORCH_AXIAL_EDGE_VISIBILITY_PTX_HEADER}" + rayd_torch_axial_edge_visibility_optix_ptx + DEPENDS + "${RAYD_TORCH_AXIAL_EDGE_VISIBILITY_PTX}" + src/torch_ext/embed_ptx.py + ) + add_custom_target( + rayd_torch_axial_edge_visibility_optix_ptx + DEPENDS "${RAYD_TORCH_AXIAL_EDGE_VISIBILITY_PTX_HEADER}") + add_custom_command( + OUTPUT "${RAYD_TORCH_REFLECTION_EPC_PTX}" + COMMAND + "${CMAKE_CUDA_COMPILER}" + --ptx + "${CMAKE_CURRENT_SOURCE_DIR}/src/torch_ext/reflection/epc_optix.cu" + -o "${RAYD_TORCH_REFLECTION_EPC_PTX}" + -I "${CMAKE_CURRENT_SOURCE_DIR}/include" + -I "${RAYD_SHARED_INCLUDE_DIR}" + -I "${CUDAToolkit_INCLUDE_DIRS}" + -I "${OPTIX_INCLUDE_DIR}" + ${RAYD_TORCH_OPTIX_NVCC_FLAGS} + DEPENDS + src/torch_ext/reflection/epc_optix.cu + include/rayd/torch/common/math.cuh + include/rayd/torch/reflection/epc_params.h + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/contracts.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/optix/device_hit.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/optix/reflection_epc_params.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/optix/reflection_epc_device.cuh" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/multipath/reflection_epc_algo.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/math/vec3.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/reflection/reflection_geometry.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/reflection/epc_chain.h" + "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/qualifiers.h" "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/traverser.h" "${RAYD_SHARED_INCLUDE_DIR}/rayd/shared/rt/numeric_policy.h" ) @@ -869,4 +957,3 @@ if(RAYD_TORCH_BUILD_NATIVE) install(TARGETS _C LIBRARY DESTINATION rayd/torch RUNTIME DESTINATION rayd/torch) endif() endif() - From 933e57a3ff84eca2473bd455d1016175eaf84384 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 00:41:54 -0700 Subject: [PATCH 07/35] Normalize .github/workflows/pypi.yml newline --- .github/workflows/pypi.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 6656038..c67d01f 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -466,4 +466,3 @@ jobs: with: packages-dir: dist verbose: true - From eb4f390ef1c7c250d0c67bf854d50efce21f978f Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 00:42:01 -0700 Subject: [PATCH 08/35] Normalize backends/torch/tests/test_project_metadata.py newline --- backends/torch/tests/test_project_metadata.py | 1 - 1 file changed, 1 deletion(-) diff --git a/backends/torch/tests/test_project_metadata.py b/backends/torch/tests/test_project_metadata.py index 820cb5b..b6c0322 100644 --- a/backends/torch/tests/test_project_metadata.py +++ b/backends/torch/tests/test_project_metadata.py @@ -155,4 +155,3 @@ def test_optix_auto_fallback_preserves_operational_errors(self): f"context_result == {operational_error}", source, ) - From e3965b59cb8e2a2b4167dacf77bb3225702e9484 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 00:42:53 -0700 Subject: [PATCH 09/35] Trigger corrected complete CI validation From 50c4362ae41b6bd85c7f06a4e731b00a556d2cf7 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 00:47:28 -0700 Subject: [PATCH 10/35] Trigger CI after event queue stabilization From dcbf46707c36768f64185f348aa2e67863c93636 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 02:12:42 -0700 Subject: [PATCH 11/35] Verify large Linux CUDA binaries through extracted fatbins --- .../scripts/verify_cuda_binary_arches.py | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/backends/drjit/scripts/verify_cuda_binary_arches.py b/backends/drjit/scripts/verify_cuda_binary_arches.py index bcd8c31..4584862 100644 --- a/backends/drjit/scripts/verify_cuda_binary_arches.py +++ b/backends/drjit/scripts/verify_cuda_binary_arches.py @@ -38,11 +38,49 @@ def _collect_binaries(inputs: list[Path], stems: tuple[str, ...], extract_root: def _cuobjdump(flag: str, binary: Path) -> str: result = subprocess.run( ["cuobjdump", flag, str(binary)], - check=True, capture_output=True, text=True, ) - return f"{result.stdout}\n{result.stderr}" + if result.returncode == 0: + return f"{result.stdout}\n{result.stderr}" + + errors = [ + f"cuobjdump {flag} failed for {binary} with exit code {result.returncode}:", + result.stderr.strip() or result.stdout.strip() or "", + ] + if binary.suffix == ".so": + with tempfile.TemporaryDirectory(prefix="rayd_cuda_fatbin_") as temp_dir: + fatbin = Path(temp_dir) / f"{binary.stem}.fatbin" + extraction = subprocess.run( + ["objcopy", "--dump-section", f".nv_fatbin={fatbin}", str(binary)], + capture_output=True, + text=True, + ) + if extraction.returncode == 0 and fatbin.is_file() and fatbin.stat().st_size: + retry = subprocess.run( + ["cuobjdump", flag, str(fatbin)], + capture_output=True, + text=True, + ) + if retry.returncode == 0: + return f"{retry.stdout}\n{retry.stderr}" + errors.extend( + [ + f"cuobjdump {flag} failed for extracted {fatbin.name} " + f"with exit code {retry.returncode}:", + retry.stderr.strip() or retry.stdout.strip() or "", + ] + ) + else: + errors.extend( + [ + f"Could not extract .nv_fatbin from {binary}:", + extraction.stderr.strip() + or extraction.stdout.strip() + or "", + ] + ) + raise SystemExit("\n".join(errors)) def main() -> None: From e85f1be260ae3aec2a8083fc19acce09b5b57d64 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 02:13:08 -0700 Subject: [PATCH 12/35] Test large Linux CUDA binary verification fallback --- .../tests/test_verify_cuda_binary_arches.py | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 backends/drjit/tests/test_verify_cuda_binary_arches.py diff --git a/backends/drjit/tests/test_verify_cuda_binary_arches.py b/backends/drjit/tests/test_verify_cuda_binary_arches.py new file mode 100644 index 0000000..88f4791 --- /dev/null +++ b/backends/drjit/tests/test_verify_cuda_binary_arches.py @@ -0,0 +1,41 @@ +from pathlib import Path +from subprocess import CompletedProcess +from unittest import TestCase +from unittest.mock import patch + +from scripts.verify_cuda_binary_arches import _cuobjdump + + +class VerifyCudaBinaryArchesTests(TestCase): + def test_linux_elf_falls_back_to_extracted_fatbin(self): + calls: list[list[str]] = [] + + def run(command, **kwargs): + calls.append(command) + if command[0] == "objcopy": + fatbin = Path(command[2].split("=", 1)[1]) + fatbin.write_bytes(b"fatbin") + return CompletedProcess(command, 0, "", "") + if command[-1].endswith(".fatbin"): + return CompletedProcess(command, 0, "ELF file: kernel.sm_87.cubin", "") + return CompletedProcess(command, 255, "", "host ELF is too large") + + with patch("scripts.verify_cuda_binary_arches.subprocess.run", side_effect=run): + output = _cuobjdump("--list-elf", Path("rayd/torch/_C.so")) + + self.assertIn("sm_87", output) + self.assertEqual([call[0] for call in calls], ["cuobjdump", "objcopy", "cuobjdump"]) + + def test_failure_reports_cuobjdump_stderr(self): + failed = CompletedProcess( + ["cuobjdump"], + 255, + "", + "unsupported input", + ) + with patch( + "scripts.verify_cuda_binary_arches.subprocess.run", + return_value=failed, + ): + with self.assertRaisesRegex(SystemExit, "unsupported input"): + _cuobjdump("--list-elf", Path("_C.pyd")) From f9957ce1f9403a57d2f9c090d6789345b4e74fb8 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 02:17:17 -0700 Subject: [PATCH 13/35] Parallelize Linux Torch wheels by Python version --- .github/workflows/pypi.yml | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index c67d01f..dad5c2a 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -111,10 +111,19 @@ jobs: if-no-files-found: error build-torch-linux: - name: rayd-torch / manylinux_2_28 / py3.10-3.14 + name: rayd-torch / manylinux_2_28 / py${{ matrix.python-version }} runs-on: ubuntu-22.04 - timeout-minutes: 300 + timeout-minutes: 180 needs: metadata + strategy: + fail-fast: false + matrix: + include: + - {python-version: "3.10", cibw-build: "cp310-manylinux_x86_64"} + - {python-version: "3.11", cibw-build: "cp311-manylinux_x86_64"} + - {python-version: "3.12", cibw-build: "cp312-manylinux_x86_64"} + - {python-version: "3.13", cibw-build: "cp313-manylinux_x86_64"} + - {python-version: "3.14", cibw-build: "cp314-manylinux_x86_64"} steps: - uses: actions/checkout@v5 - name: Check out OptiX 8.1 headers @@ -137,7 +146,7 @@ jobs: - name: Build and repair Torch wheels uses: pypa/cibuildwheel@v3.3.0 env: - CIBW_BUILD: "cp310-manylinux_x86_64 cp311-manylinux_x86_64 cp312-manylinux_x86_64 cp313-manylinux_x86_64 cp314-manylinux_x86_64" + CIBW_BUILD: ${{ matrix.cibw-build }} CIBW_SKIP: "*-musllinux_*" CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 CIBW_BUILD_VERBOSITY: "1" @@ -187,7 +196,7 @@ jobs: output-dir: dist/torch - uses: actions/upload-artifact@v4 with: - name: release-rayd-torch-linux + name: release-rayd-torch-linux-py${{ matrix.python-version }} path: dist/torch/*.whl if-no-files-found: error @@ -308,7 +317,7 @@ jobs: if: runner.os == 'Linux' uses: actions/download-artifact@v4 with: - name: release-rayd-torch-linux + name: release-rayd-torch-linux-py3.10 path: wheel-artifact - name: Download Windows Torch wheel From e8aff2b84489d56f206cbe673e2f3b452076f927 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 02:17:44 -0700 Subject: [PATCH 14/35] Guard parallel Linux Torch wheel matrix --- backends/torch/tests/test_project_metadata.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/backends/torch/tests/test_project_metadata.py b/backends/torch/tests/test_project_metadata.py index b6c0322..3d292c8 100644 --- a/backends/torch/tests/test_project_metadata.py +++ b/backends/torch/tests/test_project_metadata.py @@ -106,6 +106,22 @@ def test_ci_cuda_fat_binary_covers_witwin_platform_matrix(self): )[0] self.assertIn(f'CMAKE_CUDA_ARCHITECTURES="{expected_cmake}"', torch_linux_env) self.assertIn(f'TORCH_CUDA_ARCH_LIST="{expected_torch}"', torch_linux_env) + for python, tag in ( + ("3.10", "cp310"), + ("3.11", "cp311"), + ("3.12", "cp312"), + ("3.13", "cp313"), + ("3.14", "cp314"), + ): + self.assertIn( + f'{{python-version: "{python}", cibw-build: "{tag}-manylinux_x86_64"}}', + pypi, + ) + self.assertIn( + "name: release-rayd-torch-linux-py${{ matrix.python-version }}", + pypi, + ) + self.assertIn("name: release-rayd-torch-linux-py3.10", pypi) def test_explicit_torch_architecture_precedes_environment_and_gpu_detection(self): cmake = Path("CMakeLists.txt").read_text(encoding="utf-8") From 1fa197b0e045b66aa10ab2a8df939b86ecb03eeb Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 02:57:37 -0700 Subject: [PATCH 15/35] ci: verify CUDA architectures in Torch device libraries --- .github/workflows/pypi.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index dad5c2a..49b81ba 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -188,7 +188,7 @@ jobs: --exclude libtorch_global_deps.so -w {dest_dir} {wheel} && python /project/backends/drjit/scripts/verify_cuda_binary_arches.py - --stem _C --stem _stable_ops {dest_dir}/*.whl && + --stem _legacy_ops --stem _stable_ops {dest_dir}/*.whl && python /project/backends/torch/scripts/verify_stable_abi.py --source-root /project/backends/torch/src/stable {dest_dir}/*.whl with: @@ -280,7 +280,7 @@ jobs: shell: pwsh run: | $wheel = (Get-ChildItem dist/torch/*.whl).FullName - python backends/drjit/scripts/verify_cuda_binary_arches.py --stem _C --stem _stable_ops $wheel + python backends/drjit/scripts/verify_cuda_binary_arches.py --stem _legacy_ops --stem _stable_ops $wheel python backends/torch/scripts/verify_stable_abi.py --source-root backends/torch/src/stable $wheel python -m twine check $wheel - uses: actions/upload-artifact@v4 From ad8ec024ce23db3ab08548db4bc49b8d3f913b46 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 02:58:06 -0700 Subject: [PATCH 16/35] test: enforce Torch CUDA binary ownership in CI --- backends/torch/tests/test_project_metadata.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backends/torch/tests/test_project_metadata.py b/backends/torch/tests/test_project_metadata.py index 3d292c8..c6265df 100644 --- a/backends/torch/tests/test_project_metadata.py +++ b/backends/torch/tests/test_project_metadata.py @@ -122,6 +122,9 @@ def test_ci_cuda_fat_binary_covers_witwin_platform_matrix(self): pypi, ) self.assertIn("name: release-rayd-torch-linux-py3.10", pypi) + torch_verifier = "--stem _legacy_ops --stem _stable_ops" + self.assertEqual(pypi.count(torch_verifier), 2) + self.assertNotIn("--stem _C --stem _stable_ops", pypi) def test_explicit_torch_architecture_precedes_environment_and_gpu_detection(self): cmake = Path("CMakeLists.txt").read_text(encoding="utf-8") From 686e37d4b2f2732018c0a067706e26462910d08a Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 04:23:51 -0700 Subject: [PATCH 17/35] fix: avoid requiring the CUDA driver to load stable ops --- backends/torch/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backends/torch/CMakeLists.txt b/backends/torch/CMakeLists.txt index 49f67fe..7a8eb8c 100644 --- a/backends/torch/CMakeLists.txt +++ b/backends/torch/CMakeLists.txt @@ -212,8 +212,7 @@ if(RAYD_TORCH_BUILD_NATIVE) PRIVATE "${RAYD_TORCH_STABLE_CPU_LIBRARY}" "${RAYD_TORCH_STABLE_CUDA_LIBRARY}" - CUDA::cudart - CUDA::cuda_driver) + CUDA::cudart) target_compile_features(rayd_torch_stable_ops PRIVATE cxx_std_17) install( TARGETS rayd_torch_stable_ops From 21931b79cab743df4f062e63d1382af788d8165d Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 04:24:16 -0700 Subject: [PATCH 18/35] test: keep stable ops loadable without a GPU driver --- backends/torch/tests/test_project_metadata.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backends/torch/tests/test_project_metadata.py b/backends/torch/tests/test_project_metadata.py index c6265df..e05e1d0 100644 --- a/backends/torch/tests/test_project_metadata.py +++ b/backends/torch/tests/test_project_metadata.py @@ -45,8 +45,10 @@ def test_stable_abi_slice_avoids_unstable_torch_and_python_apis(self): stable_target = cmake[stable_start:cmake.index("execute_process(", stable_start)] self.assertNotIn("TORCH_PYTHON_LIBRARY", stable_target) self.assertNotIn('"${TORCH_LIBRARIES}"', stable_target) + self.assertNotIn("CUDA::cuda_driver", stable_target) self.assertIn('"${RAYD_TORCH_STABLE_CPU_LIBRARY}"', stable_target) self.assertIn('"${RAYD_TORCH_STABLE_CUDA_LIBRARY}"', stable_target) + self.assertIn("CUDA::cudart", stable_target) def test_stable_abi_audit_script_is_packaged_with_the_backend(self): script = Path("scripts/verify_stable_abi.py") From 74d4223bab65285b900f3ecd121f3eec862c0ce1 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 05:07:43 -0700 Subject: [PATCH 19/35] ci: remove obsolete self-hosted GPU workflow --- .github/workflows/ci.yml | 98 ---------------------------------------- 1 file changed, 98 deletions(-) delete mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index dcf19c5..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,98 +0,0 @@ -name: Dual Backend CI - -on: - workflow_call: - pull_request: - push: - branches: [main] - schedule: - - cron: "17 9 * * 1" - workflow_dispatch: - -concurrency: - group: dual-backend-${{ github.ref }} - cancel-in-progress: true - -jobs: - drjit: - runs-on: [self-hosted, Windows, X64, rayd-gpu] - steps: - - uses: actions/checkout@v5 - - uses: actions/setup-python@v5 - with: {python-version: "3.11"} - - run: python -m pip install "scikit-build-core>=0.10" "cmake>=3.22" ninja "nanobind==2.9.2" "drjit==1.3.1" - - run: python -m pip install --no-build-isolation -e backends/drjit - - run: python -m unittest discover -s tests -t . -v - working-directory: backends/drjit - - torch: - runs-on: [self-hosted, Windows, X64, rayd-gpu] - steps: - - uses: actions/checkout@v5 - - uses: actions/setup-python@v5 - with: {python-version: "3.11"} - - run: python -m pip install scikit-build-core cmake ninja torch - - run: python -m pip install --no-build-isolation -e backends/torch -Cbuild-dir=artifacts/skbuild - - run: python -m unittest discover -s tests/torch_backend -t . -v - working-directory: backends/torch - - name: Audit LibTorch Stable ABI library - shell: pwsh - run: | - $stable = Get-ChildItem backends/torch/artifacts/skbuild -Recurse -Filter _stable_ops.dll | Select-Object -First 1 - if (-not $stable) { throw "_stable_ops.dll was not built" } - python backends/torch/scripts/verify_stable_abi.py --source-root backends/torch/src/stable $stable.FullName - - parity: - if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'run-parity') - needs: [drjit, torch] - runs-on: [self-hosted, Windows, X64, rayd-gpu] - steps: - - uses: actions/checkout@v5 - - uses: actions/setup-python@v5 - with: {python-version: "3.11"} - - run: python -m pip install "scikit-build-core>=0.10" "cmake>=3.22" ninja "nanobind==2.9.2" "drjit==1.3.1" torch - - run: python -m pip install --no-build-isolation -e backends/drjit - - run: python -m pip install --no-build-isolation -e backends/torch -Cbuild-dir=artifacts/skbuild - - run: python -m unittest tests.torch_backend.test_drjit_parity -v - working-directory: backends/torch - env: {RAYD_TORCH_RUN_DR_JIT_PARITY: "1"} - - packaging: - needs: [drjit, torch] - runs-on: [self-hosted, Windows, X64, rayd-gpu] - steps: - - uses: actions/checkout@v5 - - uses: actions/setup-python@v5 - with: {python-version: "3.11"} - - run: python -m pip install build "setuptools>=77" "scikit-build-core>=0.10" "cmake>=3.22" ninja "nanobind==2.9.2" "drjit==1.3.1" torch - - run: python -m build --wheel --no-isolation --outdir dist - - run: python -m build --wheel --no-isolation --outdir ../../dist - working-directory: backends/drjit - - run: python -m build --wheel --no-isolation --outdir ../../dist -Cbuild-dir=artifacts/skbuild - working-directory: backends/torch - - name: Audit packaged Stable ABI library - shell: pwsh - run: | - $stable = Get-ChildItem backends/torch/artifacts/skbuild -Recurse -Filter _stable_ops.dll | Select-Object -First 1 - if (-not $stable) { throw "_stable_ops.dll was not built" } - python backends/torch/scripts/verify_stable_abi.py --source-root backends/torch/src/stable $stable.FullName - - shell: pwsh - run: | - $env:RAYD_META_WHEEL = (Get-ChildItem dist/rayd-*.whl | Where-Object { $_.Name -notmatch '^rayd_(drjit|torch)-' }).FullName - $env:RAYD_DRJIT_WHEEL = (Get-ChildItem dist/rayd_drjit-*.whl).FullName - $env:RAYD_TORCH_WHEEL = (Get-ChildItem dist/rayd_torch-*.whl).FullName - python -m unittest tests.packaging.test_project_metadata tests.packaging.test_wheel_layout tests.packaging.test_wheel_install_matrix -v - - uses: actions/upload-artifact@v4 - with: {name: rayd-wheels, path: dist/*.whl} - - coexistence: - needs: [drjit, torch] - runs-on: [self-hosted, Windows, X64, rayd-gpu] - steps: - - uses: actions/checkout@v5 - - uses: actions/setup-python@v5 - with: {python-version: "3.11"} - - run: python -m pip install "scikit-build-core>=0.10" "cmake>=3.22" ninja "nanobind==2.9.2" "drjit==1.3.1" torch - - run: python -m pip install --no-build-isolation -e backends/drjit - - run: python -m pip install --no-build-isolation -e backends/torch -Cbuild-dir=artifacts/skbuild - - run: python -m unittest tests.test_namespace_isolation -v From 2217b8bb6d54f02ef0d7672b041fd1e4ef1ec946 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 05:08:40 -0700 Subject: [PATCH 20/35] ci: avoid duplicate branch and pull request builds --- .github/workflows/stable-abi-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/stable-abi-ci.yml b/.github/workflows/stable-abi-ci.yml index 2ab891b..39ba40f 100644 --- a/.github/workflows/stable-abi-ci.yml +++ b/.github/workflows/stable-abi-ci.yml @@ -4,7 +4,6 @@ on: push: branches: - main - - "codex/**" pull_request: workflow_dispatch: From 1b51eca9807061d4ca0b1675d6561f4724da2798 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 05:08:47 -0700 Subject: [PATCH 21/35] ci: avoid duplicate branch and pull request builds --- .github/workflows/pypi.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 49b81ba..57106ee 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -4,7 +4,6 @@ on: push: branches: - main - - "codex/**" pull_request: release: types: [published] From 926f8485924a756953f65dddfb267fd67c08c747 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 05:44:13 -0700 Subject: [PATCH 22/35] ci: accelerate hosted CUDA wheel builds --- .github/workflows/ci.yml | 238 ++++++++++++++++++ .github/workflows/pypi.yml | 122 +++++++-- .github/workflows/stable-abi-ci.yml | 37 ++- backends/drjit/CI_BUILD_MATRIX.md | 43 +++- backends/drjit/CMakeLists.txt | 29 +++ .../scripts/verify_cuda_binary_arches.py | 20 +- backends/drjit/tests/test_project_metadata.py | 10 +- backends/torch/tests/test_project_metadata.py | 17 +- 8 files changed, 482 insertions(+), 34 deletions(-) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d0ca7e4 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,238 @@ +name: Hosted Pull Request CI + +on: + pull_request: + workflow_dispatch: + +concurrency: + group: hosted-ci-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +env: + RAYD_CUDA_GENCODE_ARCHES: "87,120" + RAYD_CUDA_PTX_ARCH: "120" + CMAKE_CUDA_ARCHITECTURES: "87-real;120-real;120-virtual" + TORCH_CUDA_ARCH_LIST: "8.7;12.0+PTX" + +jobs: + metadata: + name: Metadata / py${{ matrix.python-version }} + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + python-version: ["3.10", "3.14"] + steps: + - uses: actions/checkout@v5 + - uses: actions/setup-python@v6 + with: + python-version: ${{ matrix.python-version }} + cache: pip + - run: python -m pip install "tomli>=2; python_version < '3.11'" + - name: Validate package metadata and CI policy + shell: bash + run: | + python -m unittest tests.packaging.test_project_metadata -v + (cd backends/drjit && python -m unittest tests.test_project_metadata tests.test_verify_cuda_binary_arches -v) + (cd backends/torch && python -m unittest tests.test_project_metadata -v) + + native-wheel: + name: ${{ matrix.backend }} / ${{ matrix.os }} / py3.12 / quick CUDA + needs: metadata + runs-on: ${{ matrix.os }} + timeout-minutes: 90 + strategy: + fail-fast: false + matrix: + os: [ubuntu-22.04, windows-2022] + backend: [drjit, torch] + env: + CMAKE_BUILD_PARALLEL_LEVEL: ${{ matrix.backend == 'torch' && '2' || '4' }} + CMAKE_CUDA_FLAGS: ${{ matrix.backend == 'torch' && '--threads=2' || '' }} + CMAKE_C_COMPILER_LAUNCHER: sccache + CMAKE_CXX_COMPILER_LAUNCHER: sccache + CMAKE_CUDA_COMPILER_LAUNCHER: sccache + RAYD_NVCC_LAUNCHER: sccache + OPTIX_INCLUDE_DIR: ${{ github.workspace }}/.optix/include + SCCACHE_DIR: ${{ runner.temp }}/rayd-sccache + SCCACHE_CACHE_SIZE: 1G + SCCACHE_BASEDIRS: ${{ github.workspace }} + SCCACHE_IGNORE_SERVER_IO_ERROR: "1" + + steps: + - uses: actions/checkout@v5 + - name: Check out OptiX 8.1 headers + if: matrix.backend == 'torch' + uses: actions/checkout@v5 + with: + repository: NVIDIA/optix-dev + ref: v8.1.0 + path: .optix + persist-credentials: false + - uses: actions/setup-python@v6 + with: + python-version: "3.12" + cache: pip + - name: Install sccache + uses: mozilla-actions/sccache-action@v0.0.10 + with: + version: "v0.11.0" + - name: Restore compiler and cibuildwheel caches + uses: actions/cache@v5 + with: + path: | + ${{ runner.temp }}/rayd-sccache + ${{ runner.temp }}/cibuildwheel + key: rayd-sccache-v2-quick-${{ runner.os }}-${{ matrix.backend }}-${{ github.sha }} + restore-keys: | + rayd-sccache-v2-quick-${{ runner.os }}-${{ matrix.backend }}- + + - name: Expose sccache to manylinux + if: runner.os == 'Linux' + shell: bash + run: | + mkdir -p "$RUNNER_TEMP/rayd-sccache-bin" + cp "$(command -v sccache)" "$RUNNER_TEMP/rayd-sccache-bin/sccache" + + - name: Free Linux disk space + if: runner.os == 'Linux' + shell: bash + run: | + sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android \ + /usr/local/share/boost /opt/hostedtoolcache/CodeQL \ + /usr/local/share/powershell /usr/share/swift || true + sudo docker image prune --all --force || true + + - name: Build Linux wheel + if: runner.os == 'Linux' + uses: pypa/cibuildwheel@v3.3.0 + env: + CIBW_BUILD: "cp312-manylinux_x86_64" + CIBW_SKIP: "*-musllinux_*" + CIBW_CACHE_PATH: ${{ runner.temp }}/cibuildwheel + CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 + CIBW_BUILD_VERBOSITY: "1" + CIBW_BEFORE_ALL_LINUX: >- + dnf install -y dnf-plugins-core gcc-toolset-12 && + rpm --import https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub && + dnf config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/cuda-rhel8.repo && + dnf clean expire-cache && + dnf install -y cuda-toolkit-12-8 && + ln -sfn /usr/local/cuda-12.8 /usr/local/cuda && + /usr/local/cuda/bin/nvcc --version + CIBW_ENVIRONMENT_LINUX: >- + CUDA_HOME=/usr/local/cuda + CUDA_PATH=/usr/local/cuda + CUDA_ROOT=/usr/local/cuda + CUDA_BIN_PATH=/usr/local/cuda + CUDACXX=/usr/local/cuda/bin/nvcc + OPTIX_INCLUDE_DIR=/project/.optix/include + RAYD_CUDA_GENCODE_ARCHES=87,120 + RAYD_CUDA_PTX_ARCH=120 + RAYD_NVCC_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache + CMAKE_CUDA_ARCHITECTURES="87-real;120-real;120-virtual" + TORCH_CUDA_ARCH_LIST="8.7;12.0+PTX" + CMAKE_BUILD_PARALLEL_LEVEL=${{ matrix.backend == 'torch' && '2' || '4' }} + CMAKE_CUDA_FLAGS=${{ matrix.backend == 'torch' && '--threads=2' || '' }} + CMAKE_C_COMPILER_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache + CMAKE_CXX_COMPILER_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache + CMAKE_CUDA_COMPILER_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache + SCCACHE_DIR=/host${{ runner.temp }}/rayd-sccache + SCCACHE_CACHE_SIZE=1G + SCCACHE_BASEDIRS=/project + SCCACHE_IGNORE_SERVER_IO_ERROR=1 + PIP_EXTRA_INDEX_URL=https://download.pytorch.org/whl/cu128 + CC=/opt/rh/gcc-toolset-12/root/usr/bin/gcc + CXX=/opt/rh/gcc-toolset-12/root/usr/bin/g++ + CUDAHOSTCXX=/opt/rh/gcc-toolset-12/root/usr/bin/g++ + PATH=/usr/local/cuda/bin:$PATH + LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH + CIBW_REPAIR_WHEEL_COMMAND_LINUX: >- + auditwheel repair --plat manylinux_2_28_x86_64 + --exclude libcuda.so.1 + --exclude libnvoptix.so.1 + --exclude libcudart.so.12 + --exclude libc10.so + --exclude libc10_cuda.so + --exclude libtorch.so + --exclude libtorch_cpu.so + --exclude libtorch_cuda.so + --exclude libtorch_python.so + --exclude libtorch_global_deps.so + --exclude libdrjit-core.so + --exclude libdrjit-extra.so + --exclude libnanothread.so + -w {dest_dir} {wheel} && + python /project/backends/drjit/scripts/verify_cuda_binary_arches.py + ${{ matrix.backend == 'drjit' && '--stem _C' || '--stem _legacy_ops --stem _stable_ops' }} + --expected-sass 87,120 --expected-ptx 120 {dest_dir}/*.whl && + if [ "${{ matrix.backend }}" = "torch" ]; then + python /project/backends/torch/scripts/verify_stable_abi.py + --source-root /project/backends/torch/src/stable {dest_dir}/*.whl; + fi + with: + package-dir: backends/${{ matrix.backend }} + output-dir: dist/${{ matrix.backend }} + + - name: Install CUDA Toolkit 12.8 on Windows + if: runner.os == 'Windows' + uses: Jimver/cuda-toolkit@v0.2.35 + with: + cuda: "12.8.1" + method: local + log-file-suffix: "pr-${{ matrix.backend }}-windows" + - name: Set up MSVC + if: runner.os == 'Windows' + uses: ilammy/msvc-dev-cmd@v1 + with: + arch: x64 + - name: Export Windows CUDA paths + if: runner.os == 'Windows' + shell: pwsh + run: | + $cudaRoot = $env:CUDA_PATH + if (-not $cudaRoot) { + $nvcc = (Get-Command nvcc -ErrorAction Stop).Source + $cudaRoot = Split-Path (Split-Path $nvcc -Parent) -Parent + } + "CUDA_HOME=$cudaRoot" >> $env:GITHUB_ENV + "CUDA_PATH=$cudaRoot" >> $env:GITHUB_ENV + - name: Install Windows build dependencies + if: runner.os == 'Windows' + shell: pwsh + run: | + python -m pip install --upgrade pip build twine "scikit-build-core>=0.10" "cmake>=3.26" ninja + if ("${{ matrix.backend }}" -eq "drjit") { + python -m pip install --constraint .github/constraints/drjit-build.txt "nanobind==2.9.2" "drjit==1.3.1" + } else { + python -m pip install torch==2.10.0 --index-url https://download.pytorch.org/whl/cu128 + } + - name: Build Windows wheel + if: runner.os == 'Windows' + shell: pwsh + run: | + $output = Join-Path $env:GITHUB_WORKSPACE "dist/${{ matrix.backend }}" + python -m build "backends/${{ matrix.backend }}" --wheel --no-isolation --outdir $output -Cbuild-dir=artifacts/skbuild + + - name: Verify quick CUDA architecture set + if: runner.os == 'Windows' + shell: pwsh + run: | + $wheel = (Get-ChildItem "dist/${{ matrix.backend }}/*.whl").FullName + if ("${{ matrix.backend }}" -eq "drjit") { + python backends/drjit/scripts/verify_cuda_binary_arches.py --stem _C --expected-sass 87,120 --expected-ptx 120 $wheel + } else { + python backends/drjit/scripts/verify_cuda_binary_arches.py --stem _legacy_ops --stem _stable_ops --expected-sass 87,120 --expected-ptx 120 $wheel + python backends/torch/scripts/verify_stable_abi.py --source-root backends/torch/src/stable $wheel + } + python -m pip install twine + python -m twine check $wheel + + - uses: actions/upload-artifact@v4 + with: + name: pr-rayd-${{ matrix.backend }}-${{ runner.os }}-py3.12 + path: dist/${{ matrix.backend }}/*.whl + if-no-files-found: error diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 57106ee..165a5de 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -4,7 +4,8 @@ on: push: branches: - main - pull_request: + schedule: + - cron: "17 9 * * 1" release: types: [published] workflow_dispatch: @@ -17,7 +18,6 @@ permissions: contents: read env: - CMAKE_BUILD_PARALLEL_LEVEL: "2" RAYD_CUDA_GENCODE_ARCHES: "70,75,80,86,87,89,90,100,101,120" RAYD_CUDA_PTX_ARCH: "120" TORCH_CUDA_ARCH_LIST: "7.0;7.5;8.0;8.6;8.7;8.9;9.0;10.0;10.1;12.0+PTX" @@ -32,7 +32,7 @@ jobs: python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] steps: - uses: actions/checkout@v5 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} - run: python -m pip install "tomli>=2; python_version < '3.11'" @@ -44,15 +44,47 @@ jobs: (cd backends/torch && python -m unittest tests.test_project_metadata -v) build-drjit-linux: - name: rayd-drjit / manylinux_2_28 / py3.10-3.14 + name: rayd-drjit / manylinux_2_28 / py${{ matrix.python-version }} runs-on: ubuntu-22.04 - timeout-minutes: 240 + timeout-minutes: 120 needs: metadata + env: + SCCACHE_DIR: ${{ runner.temp }}/rayd-sccache + SCCACHE_CACHE_SIZE: 1G + SCCACHE_IGNORE_SERVER_IO_ERROR: "1" + strategy: + fail-fast: false + matrix: + include: + - {python-version: "3.10", cibw-build: "cp310-manylinux_x86_64"} + - {python-version: "3.11", cibw-build: "cp311-manylinux_x86_64"} + - {python-version: "3.12", cibw-build: "cp312-manylinux_x86_64"} + - {python-version: "3.13", cibw-build: "cp313-manylinux_x86_64"} + - {python-version: "3.14", cibw-build: "cp314-manylinux_x86_64"} steps: - uses: actions/checkout@v5 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: "3.12" + cache: pip + - name: Install sccache + uses: mozilla-actions/sccache-action@v0.0.10 + with: + version: "v0.11.0" + - name: Restore compiler and cibuildwheel caches + uses: actions/cache@v5 + with: + path: | + ${{ runner.temp }}/rayd-sccache + ${{ runner.temp }}/cibuildwheel + key: rayd-sccache-v2-full-linux-drjit-${{ github.sha }} + restore-keys: | + rayd-sccache-v2-full-linux-drjit- + - name: Expose sccache to manylinux + shell: bash + run: | + mkdir -p "$RUNNER_TEMP/rayd-sccache-bin" + cp "$(command -v sccache)" "$RUNNER_TEMP/rayd-sccache-bin/sccache" - name: Free disk space shell: bash run: | @@ -63,8 +95,9 @@ jobs: - name: Build and repair Dr.Jit wheels uses: pypa/cibuildwheel@v3.3.0 env: - CIBW_BUILD: "cp310-manylinux_x86_64 cp311-manylinux_x86_64 cp312-manylinux_x86_64 cp313-manylinux_x86_64 cp314-manylinux_x86_64" + CIBW_BUILD: ${{ matrix.cibw-build }} CIBW_SKIP: "*-musllinux_*" + CIBW_CACHE_PATH: ${{ runner.temp }}/cibuildwheel CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 CIBW_BUILD_VERBOSITY: "1" CIBW_BEFORE_ALL_LINUX: >- @@ -83,8 +116,15 @@ jobs: CUDACXX=/usr/local/cuda/bin/nvcc RAYD_CUDA_GENCODE_ARCHES=70,75,80,86,87,89,90,100,101,120 RAYD_CUDA_PTX_ARCH=120 + RAYD_NVCC_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache PIP_CONSTRAINT=/project/.github/constraints/drjit-build.txt - CMAKE_BUILD_PARALLEL_LEVEL=2 + CMAKE_BUILD_PARALLEL_LEVEL=4 + CMAKE_C_COMPILER_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache + CMAKE_CXX_COMPILER_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache + SCCACHE_DIR=/host${{ runner.temp }}/rayd-sccache + SCCACHE_CACHE_SIZE=1G + SCCACHE_BASEDIRS=/project + SCCACHE_IGNORE_SERVER_IO_ERROR=1 CC=/opt/rh/gcc-toolset-12/root/usr/bin/gcc CXX=/opt/rh/gcc-toolset-12/root/usr/bin/g++ CUDAHOSTCXX=/opt/rh/gcc-toolset-12/root/usr/bin/g++ @@ -105,7 +145,7 @@ jobs: output-dir: dist/drjit - uses: actions/upload-artifact@v4 with: - name: release-rayd-drjit-linux + name: release-rayd-drjit-linux-py${{ matrix.python-version }} path: dist/drjit/*.whl if-no-files-found: error @@ -114,6 +154,10 @@ jobs: runs-on: ubuntu-22.04 timeout-minutes: 180 needs: metadata + env: + SCCACHE_DIR: ${{ runner.temp }}/rayd-sccache + SCCACHE_CACHE_SIZE: 1G + SCCACHE_IGNORE_SERVER_IO_ERROR: "1" strategy: fail-fast: false matrix: @@ -132,9 +176,28 @@ jobs: ref: v8.1.0 path: .optix persist-credentials: false - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: "3.12" + cache: pip + - name: Install sccache + uses: mozilla-actions/sccache-action@v0.0.10 + with: + version: "v0.11.0" + - name: Restore compiler and cibuildwheel caches + uses: actions/cache@v5 + with: + path: | + ${{ runner.temp }}/rayd-sccache + ${{ runner.temp }}/cibuildwheel + key: rayd-sccache-v2-full-linux-torch-${{ github.sha }} + restore-keys: | + rayd-sccache-v2-full-linux-torch- + - name: Expose sccache to manylinux + shell: bash + run: | + mkdir -p "$RUNNER_TEMP/rayd-sccache-bin" + cp "$(command -v sccache)" "$RUNNER_TEMP/rayd-sccache-bin/sccache" - name: Free disk space shell: bash run: | @@ -147,6 +210,7 @@ jobs: env: CIBW_BUILD: ${{ matrix.cibw-build }} CIBW_SKIP: "*-musllinux_*" + CIBW_CACHE_PATH: ${{ runner.temp }}/cibuildwheel CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 CIBW_BUILD_VERBOSITY: "1" CIBW_BEFORE_ALL_LINUX: >- @@ -167,6 +231,14 @@ jobs: CMAKE_CUDA_ARCHITECTURES="70-real;75-real;80-real;86-real;87-real;89-real;90-real;100-real;101-real;120-real;120-virtual" TORCH_CUDA_ARCH_LIST="7.0;7.5;8.0;8.6;8.7;8.9;9.0;10.0;10.1;12.0+PTX" CMAKE_BUILD_PARALLEL_LEVEL=2 + CMAKE_CUDA_FLAGS=--threads=2 + CMAKE_C_COMPILER_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache + CMAKE_CXX_COMPILER_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache + CMAKE_CUDA_COMPILER_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache + SCCACHE_DIR=/host${{ runner.temp }}/rayd-sccache + SCCACHE_CACHE_SIZE=1G + SCCACHE_BASEDIRS=/project + SCCACHE_IGNORE_SERVER_IO_ERROR=1 PIP_EXTRA_INDEX_URL=https://download.pytorch.org/whl/cu128 CC=/opt/rh/gcc-toolset-12/root/usr/bin/gcc CXX=/opt/rh/gcc-toolset-12/root/usr/bin/g++ @@ -211,6 +283,16 @@ jobs: python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] env: CMAKE_CUDA_ARCHITECTURES: "70-real;75-real;80-real;86-real;87-real;89-real;90-real;100-real;101-real;120-real;120-virtual" + CMAKE_BUILD_PARALLEL_LEVEL: ${{ matrix.backend == 'torch' && '2' || '4' }} + CMAKE_CUDA_FLAGS: ${{ matrix.backend == 'torch' && '--threads=2' || '' }} + CMAKE_C_COMPILER_LAUNCHER: sccache + CMAKE_CXX_COMPILER_LAUNCHER: sccache + CMAKE_CUDA_COMPILER_LAUNCHER: sccache + RAYD_NVCC_LAUNCHER: sccache + SCCACHE_DIR: ${{ runner.temp }}\rayd-sccache + SCCACHE_CACHE_SIZE: 1G + SCCACHE_BASEDIRS: ${{ github.workspace }} + SCCACHE_IGNORE_SERVER_IO_ERROR: "1" OPTIX_INCLUDE_DIR: ${{ github.workspace }}\.optix\include steps: - uses: actions/checkout@v5 @@ -222,9 +304,21 @@ jobs: ref: v8.1.0 path: .optix persist-credentials: false - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} + cache: pip + - name: Install sccache + uses: mozilla-actions/sccache-action@v0.0.10 + with: + version: "v0.11.0" + - name: Restore compiler cache + uses: actions/cache@v5 + with: + path: ${{ runner.temp }}\rayd-sccache + key: rayd-sccache-v2-full-windows-${{ matrix.backend }}-${{ github.sha }} + restore-keys: | + rayd-sccache-v2-full-windows-${{ matrix.backend }}- - name: Install CUDA Toolkit 12.8 uses: Jimver/cuda-toolkit@v0.2.35 with: @@ -308,7 +402,7 @@ jobs: steps: - name: Set up compatibility Python - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ matrix.compatibility.python-version }} @@ -370,7 +464,7 @@ jobs: needs: metadata steps: - uses: actions/checkout@v5 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: "3.12" - run: python -m pip install --upgrade pip build twine "setuptools>=77" @@ -388,7 +482,7 @@ jobs: needs: [build-drjit-linux, build-torch-linux, build-windows-wheels, test-stable-torch-abi, build-meta] steps: - uses: actions/checkout@v5 - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: "3.12" - uses: actions/download-artifact@v4 diff --git a/.github/workflows/stable-abi-ci.yml b/.github/workflows/stable-abi-ci.yml index 39ba40f..b44958d 100644 --- a/.github/workflows/stable-abi-ci.yml +++ b/.github/workflows/stable-abi-ci.yml @@ -1,9 +1,6 @@ name: Stable ABI Build on: - push: - branches: - - main pull_request: workflow_dispatch: @@ -22,16 +19,24 @@ jobs: os: [ubuntu-22.04, windows-2022] env: CMAKE_BUILD_PARALLEL_LEVEL: "2" - CMAKE_CUDA_ARCHITECTURES: "70-real;75-real;80-real;86-real;87-real;89-real;90-real;100-real;101-real;120-real;120-virtual" - TORCH_CUDA_ARCH_LIST: "7.0;7.5;8.0;8.6;8.7;8.9;9.0;10.0;10.1;12.0+PTX" + CMAKE_CUDA_FLAGS: "--threads=2" + CMAKE_CUDA_ARCHITECTURES: "87-real;120-real;120-virtual" + CMAKE_C_COMPILER_LAUNCHER: sccache + CMAKE_CXX_COMPILER_LAUNCHER: sccache + CMAKE_CUDA_COMPILER_LAUNCHER: sccache + TORCH_CUDA_ARCH_LIST: "8.7;12.0+PTX" OPTIX_INCLUDE_DIR: ${{ github.workspace }}/.optix/include + SCCACHE_DIR: ${{ runner.temp }}/rayd-sccache + SCCACHE_CACHE_SIZE: 1G + SCCACHE_BASEDIRS: ${{ github.workspace }} + SCCACHE_IGNORE_SERVER_IO_ERROR: "1" steps: - name: Check out RayD - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Check out OptiX 8.1 headers - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: repository: NVIDIA/optix-dev ref: v8.1.0 @@ -39,9 +44,23 @@ jobs: persist-credentials: false - name: Set up Python 3.10 build environment - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.10" + cache: pip + + - name: Install sccache + uses: mozilla-actions/sccache-action@v0.0.10 + with: + version: "v0.11.0" + + - name: Restore compiler cache + uses: actions/cache@v5 + with: + path: ${{ runner.temp }}/rayd-sccache + key: rayd-sccache-v2-quick-${{ runner.os }}-torch-${{ github.sha }} + restore-keys: | + rayd-sccache-v2-quick-${{ runner.os }}-torch- - name: Free disk space on Linux if: runner.os == 'Linux' @@ -115,6 +134,8 @@ jobs: run: | python backends/drjit/scripts/verify_cuda_binary_arches.py \ --stem _stable_ops \ + --expected-sass 87,120 \ + --expected-ptx 120 \ "$RAYD_STABLE_LIBRARY" - name: Upload Stable ABI library diff --git a/backends/drjit/CI_BUILD_MATRIX.md b/backends/drjit/CI_BUILD_MATRIX.md index 02b7591..4ca05c4 100644 --- a/backends/drjit/CI_BUILD_MATRIX.md +++ b/backends/drjit/CI_BUILD_MATRIX.md @@ -10,7 +10,7 @@ This document records the release-wheel compatibility contract shared by RayD an | GitHub runners | `ubuntu-22.04` and `windows-2022` for build/validate jobs; `ubuntu-latest` for the publish jobs | | Python | CPython 3.10, 3.11, 3.12, 3.13, and 3.14 | | CUDA build toolkit | CUDA 12.8 Update 1 on Windows; CUDA 12.8 latest update from the RHEL 8 repository in manylinux | -| Native SASS | `sm_70`, `sm_75`, `sm_80`, `sm_86`, `sm_89`, `sm_90`, `sm_100`, `sm_101`, `sm_120` | +| Native SASS | `sm_70`, `sm_75`, `sm_80`, `sm_86`, `sm_87`, `sm_89`, `sm_90`, `sm_100`, `sm_101`, `sm_120` | | Forward-compatible PTX | `compute_120` | | Oldest explicitly covered consumer GPU | Turing / RTX 2080 class (`sm_75`) | | Newest explicitly covered families | Data-center and GeForce/RTX PRO Blackwell (`sm_100`, `sm_101`, `sm_120`) | @@ -31,13 +31,24 @@ The Dr.Jit backend must not add PyTorch merely to make the matrix look identical ## RayD GitHub Actions matrix -The distribution workflow is `.github/workflows/pypi.yml`. Pushes, pull requests, and manual runs build and audit artifacts but never publish them. Only a published GitHub Release enables the trusted-publishing jobs. The existing `rayd` project uses the `pypi` GitHub Environment; the two pending backend projects use the unique `pypi-rayd-drjit` and `pypi-rayd-torch` environments required by PyPI. +Pull requests use `.github/workflows/ci.yml`: GitHub-hosted Linux and Windows +runners build representative CPython 3.12 wheels with native `sm_87` and +`sm_120` SASS plus `compute_120` PTX. This fast profile proves both native +backends compile and package without paying the full release fan-out on every +commit. + +The complete distribution workflow is `.github/workflows/pypi.yml`. It runs +on `main`, weekly, by manual dispatch, and for published releases. Every run +builds and audits the complete release artifact set; only a published GitHub +Release enables trusted publishing. The existing `rayd` project uses the +`pypi` GitHub Environment; the two backend projects use the unique +`pypi-rayd-drjit` and `pypi-rayd-torch` environments required by PyPI. | Job | Matrix | Purpose | | --- | --- | --- | | `metadata` | Python 3.10-3.14 on Ubuntu | Validate all three distributions and the release configuration on every supported interpreter | -| `build-drjit-linux` | CPython 3.10-3.14 through cibuildwheel | Build and repair five `rayd-drjit` `manylinux_2_28_x86_64` wheels inside the CUDA-enabled manylinux image | -| `build-torch-linux` | CPython 3.10-3.14 through cibuildwheel | Build and repair five full `rayd-torch` wheels; audit `_C`, `_stable_ops`, external framework dependencies, and CUDA images | +| `build-drjit-linux` | Five parallel CPython 3.10-3.14 cibuildwheel jobs | Build and repair five `rayd-drjit` `manylinux_2_28_x86_64` wheels inside CUDA-enabled manylinux images | +| `build-torch-linux` | Five parallel CPython 3.10-3.14 cibuildwheel jobs | Build and repair five full `rayd-torch` wheels; audit `_legacy_ops`, `_stable_ops`, external framework dependencies, and CUDA images | | `build-windows-wheels` | 2 backends x Python 3.10-3.14 on `windows-2022` | Build and audit ten `win_amd64` wheels | | `build-meta` | Python 3.12 on Ubuntu | Build and check the pure Python `rayd` wheel and sdist | | `validate-wheel-set` | Ubuntu, after all four build jobs | Validate the complete release artifact set via `tests.packaging.test_release_artifact_matrix`; gates every publish job | @@ -45,6 +56,29 @@ The distribution workflow is `.github/workflows/pypi.yml`. Pushes, pull requests Both native backends keep `manylinux_2_28` rather than changing to the witwin `manylinux_2_35` tag. This is a stricter backward-compatibility target and matches the Dr.Jit and PyTorch 2.10/cu128 Linux wheels used by the builds. +## Build concurrency and caching + +Standard public GitHub-hosted Linux and Windows runners have four vCPUs. +Dr.Jit uses four build-system jobs because its CUDA sources are separate custom +commands. Torch uses two build-system jobs and `nvcc --threads=2`, which lets +each multi-architecture CUDA compilation use two threads without multiplying +four outer jobs by two inner jobs. + +Both workflows install `sccache` 0.11.0. Torch routes C, C++, and CUDA compiler +invocations through CMake launchers. Dr.Jit's explicit NVCC custom commands use +the generated `RAYD_NVCC_LAUNCHER` wrapper, while Ninja still schedules four +independent translation units. Linux manylinux jobs expose the host-installed +portable sccache binary through cibuildwheel's `/host` mount. Compiler caches +are capped at 1 GiB per +OS/backend/profile namespace, restore by prefix across commits, and report +statistics at job completion. Python matrix jobs share that namespace rather +than multiplying the repository cache footprint. The Linux cibuildwheel tool +cache and the Windows pip download cache are also persisted. + +Cache misses are always supported. Release correctness does not depend on a +warm cache, and the post-build CUDA binary verifier inspects the produced wheel +regardless of whether compilation was cached. + ## RayD CUDA configuration The Dr.Jit backend compiles CUDA translation units through explicit `nvcc` custom commands. `CMAKE_CUDA_ARCHITECTURES` does not affect those commands, so release CI supplies two dedicated environment variables: @@ -61,6 +95,7 @@ RAYD_CUDA_PTX_ARCH=120 -gencode=arch=compute_75,code=sm_75 -gencode=arch=compute_80,code=sm_80 -gencode=arch=compute_86,code=sm_86 +-gencode=arch=compute_87,code=sm_87 -gencode=arch=compute_89,code=sm_89 -gencode=arch=compute_90,code=sm_90 -gencode=arch=compute_100,code=sm_100 diff --git a/backends/drjit/CMakeLists.txt b/backends/drjit/CMakeLists.txt index b4effe4..66f84d7 100644 --- a/backends/drjit/CMakeLists.txt +++ b/backends/drjit/CMakeLists.txt @@ -82,6 +82,35 @@ find_package(CUDA 11.0 REQUIRED) set(CUDA_PROPAGATE_HOST_FLAGS OFF) mark_as_advanced(CLEAR CUDA_64_BIT_DEVICE_CODE) +# FindCUDA does not support CMAKE_CUDA_COMPILER_LAUNCHER for the explicit NVCC +# custom commands below. CI may provide a compiler launcher through a small +# generated wrapper; local builds keep invoking NVCC directly. +set(RAYD_NVCC_LAUNCHER "" CACHE STRING + "Optional compiler cache or launcher placed before NVCC.") +if(DEFINED ENV{RAYD_NVCC_LAUNCHER} + AND NOT "$ENV{RAYD_NVCC_LAUNCHER}" STREQUAL "") + set(RAYD_NVCC_LAUNCHER "$ENV{RAYD_NVCC_LAUNCHER}") +endif() +if(NOT RAYD_NVCC_LAUNCHER STREQUAL "") + set(RAYD_REAL_NVCC_EXECUTABLE "${CUDA_NVCC_EXECUTABLE}") + if(WIN32) + set(RAYD_NVCC_WRAPPER "${CMAKE_CURRENT_BINARY_DIR}/rayd_nvcc.cmd") + file(WRITE "${RAYD_NVCC_WRAPPER}" + "@\"${RAYD_NVCC_LAUNCHER}\" \"${RAYD_REAL_NVCC_EXECUTABLE}\" %*\r\n") + else() + set(RAYD_NVCC_WRAPPER "${CMAKE_CURRENT_BINARY_DIR}/rayd_nvcc") + file(WRITE "${RAYD_NVCC_WRAPPER}" + "#!/bin/sh\nexec \"${RAYD_NVCC_LAUNCHER}\" \"${RAYD_REAL_NVCC_EXECUTABLE}\" \"$@\"\n") + file(CHMOD "${RAYD_NVCC_WRAPPER}" + PERMISSIONS + OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE) + endif() + set(CUDA_NVCC_EXECUTABLE "${RAYD_NVCC_WRAPPER}") + message(STATUS "RayD NVCC launcher: ${RAYD_NVCC_LAUNCHER}") +endif() + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib") diff --git a/backends/drjit/scripts/verify_cuda_binary_arches.py b/backends/drjit/scripts/verify_cuda_binary_arches.py index 4584862..01d66df 100644 --- a/backends/drjit/scripts/verify_cuda_binary_arches.py +++ b/backends/drjit/scripts/verify_cuda_binary_arches.py @@ -87,7 +87,21 @@ def main() -> None: parser = argparse.ArgumentParser(description="Verify CUDA SASS and PTX targets in RayD release binaries.") parser.add_argument("inputs", nargs="+", type=Path) parser.add_argument("--stem", action="append", required=True) + parser.add_argument( + "--expected-sass", + default=",".join(EXPECTED_SASS), + help="Comma-separated native SASS targets. Defaults to the release matrix.", + ) + parser.add_argument( + "--expected-ptx", + default=EXPECTED_PTX_TARGET.removeprefix("sm_"), + help="PTX target without the sm_ prefix. Defaults to the release matrix.", + ) args = parser.parse_args() + expected_sass = tuple(arch.strip() for arch in args.expected_sass.split(",") if arch.strip()) + if not expected_sass: + raise SystemExit("--expected-sass must contain at least one architecture.") + expected_ptx_target = f"sm_{args.expected_ptx.strip().removeprefix('sm_')}" with tempfile.TemporaryDirectory(prefix="rayd_cuda_arch_verify_") as temp_dir: binaries = _collect_binaries(args.inputs, tuple(args.stem), Path(temp_dir)) @@ -96,13 +110,13 @@ def main() -> None: for binary in binaries: elf_listing = _cuobjdump("--list-elf", binary) - missing_sass = [arch for arch in EXPECTED_SASS if f"sm_{arch}" not in elf_listing] + missing_sass = [arch for arch in expected_sass if f"sm_{arch}" not in elf_listing] if missing_sass: raise SystemExit(f"{binary} is missing SASS targets: {', '.join(missing_sass)}") ptx_dump = _cuobjdump("--dump-ptx", binary) - if f".target {EXPECTED_PTX_TARGET}" not in ptx_dump: - raise SystemExit(f"{binary} is missing compute 12.0 PTX.") + if f".target {expected_ptx_target}" not in ptx_dump: + raise SystemExit(f"{binary} is missing PTX target {expected_ptx_target}.") print(f"Verified CUDA architectures in {binary}") diff --git a/backends/drjit/tests/test_project_metadata.py b/backends/drjit/tests/test_project_metadata.py index 5e80ad6..3a47d0b 100644 --- a/backends/drjit/tests/test_project_metadata.py +++ b/backends/drjit/tests/test_project_metadata.py @@ -75,8 +75,10 @@ def test_release_ci_covers_supported_python_and_cuda_architectures(self): pyproject = (ROOT / "pyproject.toml").read_text(encoding="utf-8") self.assertIn('requires-python = ">=3.10,<3.15"', pyproject) - for job in ("drjit:", "torch:", "parity:", "packaging:", "coexistence:"): - self.assertIn(job, workflow) + self.assertIn("native-wheel:", workflow) + self.assertIn("os: [ubuntu-22.04, windows-2022]", workflow) + self.assertIn("backend: [drjit, torch]", workflow) + self.assertNotIn("self-hosted", workflow) self.assertIn("name: pypi-rayd-drjit", release) self.assertIn("name: pypi-rayd-torch", release) self.assertEqual(release.count("name: pypi\n"), 1) @@ -89,6 +91,10 @@ def test_release_ci_covers_supported_python_and_cuda_architectures(self): ) self.assertIn("--query-gpu=compute_cap", cmake) self.assertIn("RayD local CUDA architecture: sm_", cmake) + self.assertIn("RAYD_NVCC_LAUNCHER", cmake) + self.assertIn("rayd_nvcc.cmd", cmake) + self.assertIn("rayd_nvcc", cmake) + self.assertIn("RAYD_NVCC_LAUNCHER=", release) self.assertIn("if(DEFINED ENV{VSCMD_VER})", cmake) self.assertEqual(cmake.count('call \\"${RAYD_VSDEVCMD}\\" -arch=x64'), 1) self.assertTrue((ROOT / "CI_BUILD_MATRIX.md").is_file()) diff --git a/backends/torch/tests/test_project_metadata.py b/backends/torch/tests/test_project_metadata.py index e05e1d0..3e4246d 100644 --- a/backends/torch/tests/test_project_metadata.py +++ b/backends/torch/tests/test_project_metadata.py @@ -99,10 +99,13 @@ def test_ci_cuda_fat_binary_covers_witwin_platform_matrix(self): expected_cmake = "70-real;75-real;80-real;86-real;87-real;89-real;90-real;100-real;101-real;120-real;120-virtual" expected_torch = "7.0;7.5;8.0;8.6;8.7;8.9;9.0;10.0;10.1;12.0+PTX" pypi = (root / ".github/workflows/pypi.yml").read_text(encoding="utf-8") + pull_request = (root / ".github/workflows/ci.yml").read_text(encoding="utf-8") stable = (root / ".github/workflows/stable-abi-ci.yml").read_text(encoding="utf-8") - for workflow in (pypi, stable): - self.assertIn(expected_cmake, workflow) - self.assertIn(expected_torch, workflow) + self.assertIn(expected_cmake, pypi) + self.assertIn(expected_torch, pypi) + self.assertIn("87-real;120-real;120-virtual", stable) + self.assertIn("8.7;12.0+PTX", stable) + self.assertIn("--expected-sass 87,120", stable) torch_linux_env = pypi.split("CIBW_ENVIRONMENT_LINUX:", 2)[2].split( "CIBW_REPAIR_WHEEL_COMMAND_LINUX:", 1 )[0] @@ -127,6 +130,14 @@ def test_ci_cuda_fat_binary_covers_witwin_platform_matrix(self): torch_verifier = "--stem _legacy_ops --stem _stable_ops" self.assertEqual(pypi.count(torch_verifier), 2) self.assertNotIn("--stem _C --stem _stable_ops", pypi) + self.assertIn('CMAKE_BUILD_PARALLEL_LEVEL=4', pypi) + self.assertIn('CMAKE_BUILD_PARALLEL_LEVEL=2', pypi) + self.assertIn('CMAKE_CUDA_FLAGS=--threads=2', pypi) + self.assertIn('CMAKE_CUDA_COMPILER_LAUNCHER=', pypi) + self.assertIn('mozilla-actions/sccache-action@v0.0.10', pypi) + self.assertIn('CMAKE_CUDA_ARCHITECTURES: "87-real;120-real;120-virtual"', pull_request) + self.assertIn("--expected-sass 87,120", pull_request) + self.assertNotIn("self-hosted", pull_request) def test_explicit_torch_architecture_precedes_environment_and_gpu_detection(self): cmake = Path("CMakeLists.txt").read_text(encoding="utf-8") From 69fee774b02648cbfdbb84fac2b59e38005217c4 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 05:48:46 -0700 Subject: [PATCH 23/35] ci: use valid workspace cache paths --- .github/workflows/ci.yml | 22 +++++++-------- .github/workflows/pypi.yml | 44 ++++++++++++++--------------- .github/workflows/stable-abi-ci.yml | 4 +-- backends/drjit/CI_BUILD_MATRIX.md | 4 +-- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d0ca7e4..b0cb96f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,7 +57,7 @@ jobs: CMAKE_CUDA_COMPILER_LAUNCHER: sccache RAYD_NVCC_LAUNCHER: sccache OPTIX_INCLUDE_DIR: ${{ github.workspace }}/.optix/include - SCCACHE_DIR: ${{ runner.temp }}/rayd-sccache + SCCACHE_DIR: ${{ github.workspace }}/.cache/rayd-sccache SCCACHE_CACHE_SIZE: 1G SCCACHE_BASEDIRS: ${{ github.workspace }} SCCACHE_IGNORE_SERVER_IO_ERROR: "1" @@ -84,8 +84,8 @@ jobs: uses: actions/cache@v5 with: path: | - ${{ runner.temp }}/rayd-sccache - ${{ runner.temp }}/cibuildwheel + ${{ github.workspace }}/.cache/rayd-sccache + ${{ github.workspace }}/.cache/cibuildwheel key: rayd-sccache-v2-quick-${{ runner.os }}-${{ matrix.backend }}-${{ github.sha }} restore-keys: | rayd-sccache-v2-quick-${{ runner.os }}-${{ matrix.backend }}- @@ -94,8 +94,8 @@ jobs: if: runner.os == 'Linux' shell: bash run: | - mkdir -p "$RUNNER_TEMP/rayd-sccache-bin" - cp "$(command -v sccache)" "$RUNNER_TEMP/rayd-sccache-bin/sccache" + mkdir -p "$GITHUB_WORKSPACE/.cache/sccache-bin" + cp "$(command -v sccache)" "$GITHUB_WORKSPACE/.cache/sccache-bin/sccache" - name: Free Linux disk space if: runner.os == 'Linux' @@ -112,7 +112,7 @@ jobs: env: CIBW_BUILD: "cp312-manylinux_x86_64" CIBW_SKIP: "*-musllinux_*" - CIBW_CACHE_PATH: ${{ runner.temp }}/cibuildwheel + CIBW_CACHE_PATH: ${{ github.workspace }}/.cache/cibuildwheel CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 CIBW_BUILD_VERBOSITY: "1" CIBW_BEFORE_ALL_LINUX: >- @@ -132,15 +132,15 @@ jobs: OPTIX_INCLUDE_DIR=/project/.optix/include RAYD_CUDA_GENCODE_ARCHES=87,120 RAYD_CUDA_PTX_ARCH=120 - RAYD_NVCC_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache + RAYD_NVCC_LAUNCHER=/project/.cache/sccache-bin/sccache CMAKE_CUDA_ARCHITECTURES="87-real;120-real;120-virtual" TORCH_CUDA_ARCH_LIST="8.7;12.0+PTX" CMAKE_BUILD_PARALLEL_LEVEL=${{ matrix.backend == 'torch' && '2' || '4' }} CMAKE_CUDA_FLAGS=${{ matrix.backend == 'torch' && '--threads=2' || '' }} - CMAKE_C_COMPILER_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache - CMAKE_CXX_COMPILER_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache - CMAKE_CUDA_COMPILER_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache - SCCACHE_DIR=/host${{ runner.temp }}/rayd-sccache + CMAKE_C_COMPILER_LAUNCHER=/project/.cache/sccache-bin/sccache + CMAKE_CXX_COMPILER_LAUNCHER=/project/.cache/sccache-bin/sccache + CMAKE_CUDA_COMPILER_LAUNCHER=/project/.cache/sccache-bin/sccache + SCCACHE_DIR=/project/.cache/rayd-sccache SCCACHE_CACHE_SIZE=1G SCCACHE_BASEDIRS=/project SCCACHE_IGNORE_SERVER_IO_ERROR=1 diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 165a5de..ef55c6d 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -49,7 +49,7 @@ jobs: timeout-minutes: 120 needs: metadata env: - SCCACHE_DIR: ${{ runner.temp }}/rayd-sccache + SCCACHE_DIR: ${{ github.workspace }}/.cache/rayd-sccache SCCACHE_CACHE_SIZE: 1G SCCACHE_IGNORE_SERVER_IO_ERROR: "1" strategy: @@ -75,16 +75,16 @@ jobs: uses: actions/cache@v5 with: path: | - ${{ runner.temp }}/rayd-sccache - ${{ runner.temp }}/cibuildwheel + ${{ github.workspace }}/.cache/rayd-sccache + ${{ github.workspace }}/.cache/cibuildwheel key: rayd-sccache-v2-full-linux-drjit-${{ github.sha }} restore-keys: | rayd-sccache-v2-full-linux-drjit- - name: Expose sccache to manylinux shell: bash run: | - mkdir -p "$RUNNER_TEMP/rayd-sccache-bin" - cp "$(command -v sccache)" "$RUNNER_TEMP/rayd-sccache-bin/sccache" + mkdir -p "$GITHUB_WORKSPACE/.cache/sccache-bin" + cp "$(command -v sccache)" "$GITHUB_WORKSPACE/.cache/sccache-bin/sccache" - name: Free disk space shell: bash run: | @@ -97,7 +97,7 @@ jobs: env: CIBW_BUILD: ${{ matrix.cibw-build }} CIBW_SKIP: "*-musllinux_*" - CIBW_CACHE_PATH: ${{ runner.temp }}/cibuildwheel + CIBW_CACHE_PATH: ${{ github.workspace }}/.cache/cibuildwheel CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 CIBW_BUILD_VERBOSITY: "1" CIBW_BEFORE_ALL_LINUX: >- @@ -116,12 +116,12 @@ jobs: CUDACXX=/usr/local/cuda/bin/nvcc RAYD_CUDA_GENCODE_ARCHES=70,75,80,86,87,89,90,100,101,120 RAYD_CUDA_PTX_ARCH=120 - RAYD_NVCC_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache + RAYD_NVCC_LAUNCHER=/project/.cache/sccache-bin/sccache PIP_CONSTRAINT=/project/.github/constraints/drjit-build.txt CMAKE_BUILD_PARALLEL_LEVEL=4 - CMAKE_C_COMPILER_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache - CMAKE_CXX_COMPILER_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache - SCCACHE_DIR=/host${{ runner.temp }}/rayd-sccache + CMAKE_C_COMPILER_LAUNCHER=/project/.cache/sccache-bin/sccache + CMAKE_CXX_COMPILER_LAUNCHER=/project/.cache/sccache-bin/sccache + SCCACHE_DIR=/project/.cache/rayd-sccache SCCACHE_CACHE_SIZE=1G SCCACHE_BASEDIRS=/project SCCACHE_IGNORE_SERVER_IO_ERROR=1 @@ -155,7 +155,7 @@ jobs: timeout-minutes: 180 needs: metadata env: - SCCACHE_DIR: ${{ runner.temp }}/rayd-sccache + SCCACHE_DIR: ${{ github.workspace }}/.cache/rayd-sccache SCCACHE_CACHE_SIZE: 1G SCCACHE_IGNORE_SERVER_IO_ERROR: "1" strategy: @@ -188,16 +188,16 @@ jobs: uses: actions/cache@v5 with: path: | - ${{ runner.temp }}/rayd-sccache - ${{ runner.temp }}/cibuildwheel + ${{ github.workspace }}/.cache/rayd-sccache + ${{ github.workspace }}/.cache/cibuildwheel key: rayd-sccache-v2-full-linux-torch-${{ github.sha }} restore-keys: | rayd-sccache-v2-full-linux-torch- - name: Expose sccache to manylinux shell: bash run: | - mkdir -p "$RUNNER_TEMP/rayd-sccache-bin" - cp "$(command -v sccache)" "$RUNNER_TEMP/rayd-sccache-bin/sccache" + mkdir -p "$GITHUB_WORKSPACE/.cache/sccache-bin" + cp "$(command -v sccache)" "$GITHUB_WORKSPACE/.cache/sccache-bin/sccache" - name: Free disk space shell: bash run: | @@ -210,7 +210,7 @@ jobs: env: CIBW_BUILD: ${{ matrix.cibw-build }} CIBW_SKIP: "*-musllinux_*" - CIBW_CACHE_PATH: ${{ runner.temp }}/cibuildwheel + CIBW_CACHE_PATH: ${{ github.workspace }}/.cache/cibuildwheel CIBW_MANYLINUX_X86_64_IMAGE: manylinux_2_28 CIBW_BUILD_VERBOSITY: "1" CIBW_BEFORE_ALL_LINUX: >- @@ -232,10 +232,10 @@ jobs: TORCH_CUDA_ARCH_LIST="7.0;7.5;8.0;8.6;8.7;8.9;9.0;10.0;10.1;12.0+PTX" CMAKE_BUILD_PARALLEL_LEVEL=2 CMAKE_CUDA_FLAGS=--threads=2 - CMAKE_C_COMPILER_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache - CMAKE_CXX_COMPILER_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache - CMAKE_CUDA_COMPILER_LAUNCHER=/host${{ runner.temp }}/rayd-sccache-bin/sccache - SCCACHE_DIR=/host${{ runner.temp }}/rayd-sccache + CMAKE_C_COMPILER_LAUNCHER=/project/.cache/sccache-bin/sccache + CMAKE_CXX_COMPILER_LAUNCHER=/project/.cache/sccache-bin/sccache + CMAKE_CUDA_COMPILER_LAUNCHER=/project/.cache/sccache-bin/sccache + SCCACHE_DIR=/project/.cache/rayd-sccache SCCACHE_CACHE_SIZE=1G SCCACHE_BASEDIRS=/project SCCACHE_IGNORE_SERVER_IO_ERROR=1 @@ -289,7 +289,7 @@ jobs: CMAKE_CXX_COMPILER_LAUNCHER: sccache CMAKE_CUDA_COMPILER_LAUNCHER: sccache RAYD_NVCC_LAUNCHER: sccache - SCCACHE_DIR: ${{ runner.temp }}\rayd-sccache + SCCACHE_DIR: ${{ github.workspace }}/.cache/rayd-sccache SCCACHE_CACHE_SIZE: 1G SCCACHE_BASEDIRS: ${{ github.workspace }} SCCACHE_IGNORE_SERVER_IO_ERROR: "1" @@ -315,7 +315,7 @@ jobs: - name: Restore compiler cache uses: actions/cache@v5 with: - path: ${{ runner.temp }}\rayd-sccache + path: ${{ github.workspace }}/.cache/rayd-sccache key: rayd-sccache-v2-full-windows-${{ matrix.backend }}-${{ github.sha }} restore-keys: | rayd-sccache-v2-full-windows-${{ matrix.backend }}- diff --git a/.github/workflows/stable-abi-ci.yml b/.github/workflows/stable-abi-ci.yml index b44958d..816a628 100644 --- a/.github/workflows/stable-abi-ci.yml +++ b/.github/workflows/stable-abi-ci.yml @@ -26,7 +26,7 @@ jobs: CMAKE_CUDA_COMPILER_LAUNCHER: sccache TORCH_CUDA_ARCH_LIST: "8.7;12.0+PTX" OPTIX_INCLUDE_DIR: ${{ github.workspace }}/.optix/include - SCCACHE_DIR: ${{ runner.temp }}/rayd-sccache + SCCACHE_DIR: ${{ github.workspace }}/.cache/rayd-sccache SCCACHE_CACHE_SIZE: 1G SCCACHE_BASEDIRS: ${{ github.workspace }} SCCACHE_IGNORE_SERVER_IO_ERROR: "1" @@ -57,7 +57,7 @@ jobs: - name: Restore compiler cache uses: actions/cache@v5 with: - path: ${{ runner.temp }}/rayd-sccache + path: ${{ github.workspace }}/.cache/rayd-sccache key: rayd-sccache-v2-quick-${{ runner.os }}-torch-${{ github.sha }} restore-keys: | rayd-sccache-v2-quick-${{ runner.os }}-torch- diff --git a/backends/drjit/CI_BUILD_MATRIX.md b/backends/drjit/CI_BUILD_MATRIX.md index 4ca05c4..a460b3c 100644 --- a/backends/drjit/CI_BUILD_MATRIX.md +++ b/backends/drjit/CI_BUILD_MATRIX.md @@ -68,8 +68,8 @@ Both workflows install `sccache` 0.11.0. Torch routes C, C++, and CUDA compiler invocations through CMake launchers. Dr.Jit's explicit NVCC custom commands use the generated `RAYD_NVCC_LAUNCHER` wrapper, while Ninja still schedules four independent translation units. Linux manylinux jobs expose the host-installed -portable sccache binary through cibuildwheel's `/host` mount. Compiler caches -are capped at 1 GiB per +portable sccache binary and cache through cibuildwheel's `/project` mount. +Compiler caches are capped at 1 GiB per OS/backend/profile namespace, restore by prefix across commits, and report statistics at job completion. Python matrix jobs share that namespace rather than multiplying the repository cache footprint. The Linux cibuildwheel tool From 20bd9ebe200964d0a72a61de21ee18c391d2f008 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 06:25:13 -0700 Subject: [PATCH 24/35] ci: reduce CUDA setup and fix Windows parallel builds --- .github/workflows/ci.yml | 6 ++++-- .github/workflows/pypi.yml | 9 ++++++--- .github/workflows/stable-abi-ci.yml | 17 +++++++++++++++-- backends/drjit/CI_BUILD_MATRIX.md | 4 ++++ 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0cb96f..e7c02f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -172,7 +172,8 @@ jobs: if [ "${{ matrix.backend }}" = "torch" ]; then python /project/backends/torch/scripts/verify_stable_abi.py --source-root /project/backends/torch/src/stable {dest_dir}/*.whl; - fi + fi && + /project/.cache/sccache-bin/sccache --show-stats with: package-dir: backends/${{ matrix.backend }} output-dir: dist/${{ matrix.backend }} @@ -182,7 +183,8 @@ jobs: uses: Jimver/cuda-toolkit@v0.2.35 with: cuda: "12.8.1" - method: local + method: network + sub-packages: '["nvcc", "cudart", "cuobjdump", "visual_studio_integration"]' log-file-suffix: "pr-${{ matrix.backend }}-windows" - name: Set up MSVC if: runner.os == 'Windows' diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index ef55c6d..417fc5b 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -139,7 +139,8 @@ jobs: --exclude libnanothread.so -w {dest_dir} {wheel} && python /project/backends/drjit/scripts/verify_cuda_binary_arches.py - --stem _C {dest_dir}/*.whl + --stem _C {dest_dir}/*.whl && + /project/.cache/sccache-bin/sccache --show-stats with: package-dir: backends/drjit output-dir: dist/drjit @@ -261,7 +262,8 @@ jobs: python /project/backends/drjit/scripts/verify_cuda_binary_arches.py --stem _legacy_ops --stem _stable_ops {dest_dir}/*.whl && python /project/backends/torch/scripts/verify_stable_abi.py - --source-root /project/backends/torch/src/stable {dest_dir}/*.whl + --source-root /project/backends/torch/src/stable {dest_dir}/*.whl && + /project/.cache/sccache-bin/sccache --show-stats with: package-dir: backends/torch output-dir: dist/torch @@ -323,7 +325,8 @@ jobs: uses: Jimver/cuda-toolkit@v0.2.35 with: cuda: "12.8.1" - method: local + method: network + sub-packages: '["nvcc", "cudart", "cuobjdump", "visual_studio_integration"]' log-file-suffix: "${{ matrix.backend }}-windows-py${{ matrix.python-version }}" - name: Set up MSVC uses: ilammy/msvc-dev-cmd@v1 diff --git a/.github/workflows/stable-abi-ci.yml b/.github/workflows/stable-abi-ci.yml index 816a628..ae90bd3 100644 --- a/.github/workflows/stable-abi-ci.yml +++ b/.github/workflows/stable-abi-ci.yml @@ -71,12 +71,22 @@ jobs: /usr/local/share/powershell /usr/share/swift || true sudo docker image prune --all --force || true - - name: Install CUDA Toolkit 12.8 + - name: Install CUDA Toolkit 12.8 on Linux + if: runner.os == 'Linux' uses: Jimver/cuda-toolkit@v0.2.35 with: cuda: "12.8.1" method: local - log-file-suffix: "stable-abi-${{ runner.os }}" + log-file-suffix: "stable-abi-linux" + + - name: Install CUDA Toolkit 12.8 on Windows + if: runner.os == 'Windows' + uses: Jimver/cuda-toolkit@v0.2.35 + with: + cuda: "12.8.1" + method: network + sub-packages: '["nvcc", "cudart", "cuobjdump", "visual_studio_integration"]' + log-file-suffix: "stable-abi-windows" - name: Set up MSVC if: runner.os == 'Windows' @@ -106,6 +116,9 @@ jobs: shell: bash run: | cmake -S backends/torch -B artifacts/stable-abi -GNinja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_POLICY_DEFAULT_CMP0141=NEW \ + -DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=Embedded \ -DRAYD_TORCH_BUILD_PYTHON_MODULE=OFF \ -DOPTIX_INCLUDE_DIR="$OPTIX_INCLUDE_DIR" diff --git a/backends/drjit/CI_BUILD_MATRIX.md b/backends/drjit/CI_BUILD_MATRIX.md index a460b3c..3df95ea 100644 --- a/backends/drjit/CI_BUILD_MATRIX.md +++ b/backends/drjit/CI_BUILD_MATRIX.md @@ -74,6 +74,10 @@ OS/backend/profile namespace, restore by prefix across commits, and report statistics at job completion. Python matrix jobs share that namespace rather than multiplying the repository cache footprint. The Linux cibuildwheel tool cache and the Windows pip download cache are also persisted. +Windows hosted jobs use NVIDIA's network installer and install only `nvcc`, +`cudart`, `cuobjdump`, and Visual Studio integration. This keeps compilation +and final-wheel architecture verification intact without spending time on +profilers, samples, and unrelated CUDA libraries. Cache misses are always supported. Release correctness does not depend on a warm cache, and the post-build CUDA binary verifier inspects the produced wheel From a810834423482252ddff0db8be2b7157b55d4a1c Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 06:50:46 -0700 Subject: [PATCH 25/35] ci: persist container caches and trim CUDA installs --- .github/workflows/ci.yml | 24 ++++++++++++------- .github/workflows/pypi.yml | 40 +++++++++++++++++++++---------- backends/drjit/CI_BUILD_MATRIX.md | 19 ++++++++++----- 3 files changed, 56 insertions(+), 27 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e7c02f3..e5e2437 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -120,7 +120,11 @@ jobs: rpm --import https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub && dnf config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/cuda-rhel8.repo && dnf clean expire-cache && - dnf install -y cuda-toolkit-12-8 && + dnf install -y + cuda-compiler-12-8 + cuda-cudart-devel-12-8 + cuda-cuobjdump-12-8 + ${{ matrix.backend == 'torch' && 'libcublas-devel-12-8 libcusparse-devel-12-8 libcusolver-devel-12-8' || '' }} && ln -sfn /usr/local/cuda-12.8 /usr/local/cuda && /usr/local/cuda/bin/nvcc --version CIBW_ENVIRONMENT_LINUX: >- @@ -130,17 +134,18 @@ jobs: CUDA_BIN_PATH=/usr/local/cuda CUDACXX=/usr/local/cuda/bin/nvcc OPTIX_INCLUDE_DIR=/project/.optix/include + RAYD_SCCACHE_ROOT=/host${{ github.workspace }}/.cache RAYD_CUDA_GENCODE_ARCHES=87,120 RAYD_CUDA_PTX_ARCH=120 - RAYD_NVCC_LAUNCHER=/project/.cache/sccache-bin/sccache + RAYD_NVCC_LAUNCHER=$RAYD_SCCACHE_ROOT/sccache-bin/sccache CMAKE_CUDA_ARCHITECTURES="87-real;120-real;120-virtual" TORCH_CUDA_ARCH_LIST="8.7;12.0+PTX" CMAKE_BUILD_PARALLEL_LEVEL=${{ matrix.backend == 'torch' && '2' || '4' }} CMAKE_CUDA_FLAGS=${{ matrix.backend == 'torch' && '--threads=2' || '' }} - CMAKE_C_COMPILER_LAUNCHER=/project/.cache/sccache-bin/sccache - CMAKE_CXX_COMPILER_LAUNCHER=/project/.cache/sccache-bin/sccache - CMAKE_CUDA_COMPILER_LAUNCHER=/project/.cache/sccache-bin/sccache - SCCACHE_DIR=/project/.cache/rayd-sccache + CMAKE_C_COMPILER_LAUNCHER=$RAYD_SCCACHE_ROOT/sccache-bin/sccache + CMAKE_CXX_COMPILER_LAUNCHER=$RAYD_SCCACHE_ROOT/sccache-bin/sccache + CMAKE_CUDA_COMPILER_LAUNCHER=$RAYD_SCCACHE_ROOT/sccache-bin/sccache + SCCACHE_DIR=$RAYD_SCCACHE_ROOT/rayd-sccache SCCACHE_CACHE_SIZE=1G SCCACHE_BASEDIRS=/project SCCACHE_IGNORE_SERVER_IO_ERROR=1 @@ -173,7 +178,7 @@ jobs: python /project/backends/torch/scripts/verify_stable_abi.py --source-root /project/backends/torch/src/stable {dest_dir}/*.whl; fi && - /project/.cache/sccache-bin/sccache --show-stats + $RAYD_SCCACHE_ROOT/sccache-bin/sccache --show-stats with: package-dir: backends/${{ matrix.backend }} output-dir: dist/${{ matrix.backend }} @@ -184,7 +189,10 @@ jobs: with: cuda: "12.8.1" method: network - sub-packages: '["nvcc", "cudart", "cuobjdump", "visual_studio_integration"]' + sub-packages: >- + ${{ matrix.backend == 'torch' + && '["nvcc", "cudart", "cuobjdump", "visual_studio_integration", "cublas", "cublas_dev", "cusparse", "cusparse_dev", "cusolver", "cusolver_dev"]' + || '["nvcc", "cudart", "cuobjdump", "visual_studio_integration"]' }} log-file-suffix: "pr-${{ matrix.backend }}-windows" - name: Set up MSVC if: runner.os == 'Windows' diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 417fc5b..252b6a6 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -105,7 +105,10 @@ jobs: rpm --import https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub && dnf config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/cuda-rhel8.repo && dnf clean expire-cache && - dnf install -y cuda-toolkit-12-8 && + dnf install -y + cuda-compiler-12-8 + cuda-cudart-devel-12-8 + cuda-cuobjdump-12-8 && ln -sfn /usr/local/cuda-12.8 /usr/local/cuda && /usr/local/cuda/bin/nvcc --version CIBW_ENVIRONMENT_LINUX: >- @@ -114,14 +117,15 @@ jobs: CUDA_ROOT=/usr/local/cuda CUDA_BIN_PATH=/usr/local/cuda CUDACXX=/usr/local/cuda/bin/nvcc + RAYD_SCCACHE_ROOT=/host${{ github.workspace }}/.cache RAYD_CUDA_GENCODE_ARCHES=70,75,80,86,87,89,90,100,101,120 RAYD_CUDA_PTX_ARCH=120 - RAYD_NVCC_LAUNCHER=/project/.cache/sccache-bin/sccache + RAYD_NVCC_LAUNCHER=$RAYD_SCCACHE_ROOT/sccache-bin/sccache PIP_CONSTRAINT=/project/.github/constraints/drjit-build.txt CMAKE_BUILD_PARALLEL_LEVEL=4 - CMAKE_C_COMPILER_LAUNCHER=/project/.cache/sccache-bin/sccache - CMAKE_CXX_COMPILER_LAUNCHER=/project/.cache/sccache-bin/sccache - SCCACHE_DIR=/project/.cache/rayd-sccache + CMAKE_C_COMPILER_LAUNCHER=$RAYD_SCCACHE_ROOT/sccache-bin/sccache + CMAKE_CXX_COMPILER_LAUNCHER=$RAYD_SCCACHE_ROOT/sccache-bin/sccache + SCCACHE_DIR=$RAYD_SCCACHE_ROOT/rayd-sccache SCCACHE_CACHE_SIZE=1G SCCACHE_BASEDIRS=/project SCCACHE_IGNORE_SERVER_IO_ERROR=1 @@ -140,7 +144,7 @@ jobs: -w {dest_dir} {wheel} && python /project/backends/drjit/scripts/verify_cuda_binary_arches.py --stem _C {dest_dir}/*.whl && - /project/.cache/sccache-bin/sccache --show-stats + $RAYD_SCCACHE_ROOT/sccache-bin/sccache --show-stats with: package-dir: backends/drjit output-dir: dist/drjit @@ -219,7 +223,13 @@ jobs: rpm --import https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub && dnf config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/cuda-rhel8.repo && dnf clean expire-cache && - dnf install -y cuda-toolkit-12-8 && + dnf install -y + cuda-compiler-12-8 + cuda-cudart-devel-12-8 + cuda-cuobjdump-12-8 + libcublas-devel-12-8 + libcusparse-devel-12-8 + libcusolver-devel-12-8 && ln -sfn /usr/local/cuda-12.8 /usr/local/cuda && /usr/local/cuda/bin/nvcc --version CIBW_ENVIRONMENT_LINUX: >- @@ -229,14 +239,15 @@ jobs: CUDA_BIN_PATH=/usr/local/cuda CUDACXX=/usr/local/cuda/bin/nvcc OPTIX_INCLUDE_DIR=/project/.optix/include + RAYD_SCCACHE_ROOT=/host${{ github.workspace }}/.cache CMAKE_CUDA_ARCHITECTURES="70-real;75-real;80-real;86-real;87-real;89-real;90-real;100-real;101-real;120-real;120-virtual" TORCH_CUDA_ARCH_LIST="7.0;7.5;8.0;8.6;8.7;8.9;9.0;10.0;10.1;12.0+PTX" CMAKE_BUILD_PARALLEL_LEVEL=2 CMAKE_CUDA_FLAGS=--threads=2 - CMAKE_C_COMPILER_LAUNCHER=/project/.cache/sccache-bin/sccache - CMAKE_CXX_COMPILER_LAUNCHER=/project/.cache/sccache-bin/sccache - CMAKE_CUDA_COMPILER_LAUNCHER=/project/.cache/sccache-bin/sccache - SCCACHE_DIR=/project/.cache/rayd-sccache + CMAKE_C_COMPILER_LAUNCHER=$RAYD_SCCACHE_ROOT/sccache-bin/sccache + CMAKE_CXX_COMPILER_LAUNCHER=$RAYD_SCCACHE_ROOT/sccache-bin/sccache + CMAKE_CUDA_COMPILER_LAUNCHER=$RAYD_SCCACHE_ROOT/sccache-bin/sccache + SCCACHE_DIR=$RAYD_SCCACHE_ROOT/rayd-sccache SCCACHE_CACHE_SIZE=1G SCCACHE_BASEDIRS=/project SCCACHE_IGNORE_SERVER_IO_ERROR=1 @@ -263,7 +274,7 @@ jobs: --stem _legacy_ops --stem _stable_ops {dest_dir}/*.whl && python /project/backends/torch/scripts/verify_stable_abi.py --source-root /project/backends/torch/src/stable {dest_dir}/*.whl && - /project/.cache/sccache-bin/sccache --show-stats + $RAYD_SCCACHE_ROOT/sccache-bin/sccache --show-stats with: package-dir: backends/torch output-dir: dist/torch @@ -326,7 +337,10 @@ jobs: with: cuda: "12.8.1" method: network - sub-packages: '["nvcc", "cudart", "cuobjdump", "visual_studio_integration"]' + sub-packages: >- + ${{ matrix.backend == 'torch' + && '["nvcc", "cudart", "cuobjdump", "visual_studio_integration", "cublas", "cublas_dev", "cusparse", "cusparse_dev", "cusolver", "cusolver_dev"]' + || '["nvcc", "cudart", "cuobjdump", "visual_studio_integration"]' }} log-file-suffix: "${{ matrix.backend }}-windows-py${{ matrix.python-version }}" - name: Set up MSVC uses: ilammy/msvc-dev-cmd@v1 diff --git a/backends/drjit/CI_BUILD_MATRIX.md b/backends/drjit/CI_BUILD_MATRIX.md index 3df95ea..879e195 100644 --- a/backends/drjit/CI_BUILD_MATRIX.md +++ b/backends/drjit/CI_BUILD_MATRIX.md @@ -67,17 +67,24 @@ four outer jobs by two inner jobs. Both workflows install `sccache` 0.11.0. Torch routes C, C++, and CUDA compiler invocations through CMake launchers. Dr.Jit's explicit NVCC custom commands use the generated `RAYD_NVCC_LAUNCHER` wrapper, while Ninja still schedules four -independent translation units. Linux manylinux jobs expose the host-installed -portable sccache binary and cache through cibuildwheel's `/project` mount. +independent translation units. Linux manylinux jobs access the host-installed +portable sccache binary and persistent cache through cibuildwheel's default +`/host` mount; `/project` is a container copy and must not hold persistent +compiler state. Compiler caches are capped at 1 GiB per OS/backend/profile namespace, restore by prefix across commits, and report statistics at job completion. Python matrix jobs share that namespace rather than multiplying the repository cache footprint. The Linux cibuildwheel tool cache and the Windows pip download cache are also persisted. -Windows hosted jobs use NVIDIA's network installer and install only `nvcc`, -`cudart`, `cuobjdump`, and Visual Studio integration. This keeps compilation -and final-wheel architecture verification intact without spending time on -profilers, samples, and unrelated CUDA libraries. +Windows hosted jobs use NVIDIA's network installer. Dr.Jit installs only +`nvcc`, `cudart`, `cuobjdump`, and Visual Studio integration. Torch also +installs the cuBLAS, cuSPARSE, and cuSOLVER runtime/development packages needed +by its public CUDA headers. This keeps compilation and final-wheel architecture +verification intact without spending time on profilers, samples, and unrelated +CUDA libraries. +Linux manylinux jobs likewise install only `cuda-compiler`, +`cuda-cudart-devel`, and `cuda-cuobjdump`, plus those three math development +libraries for Torch, rather than the 5 GiB full toolkit metapackage. Cache misses are always supported. Release correctness does not depend on a warm cache, and the post-build CUDA binary verifier inspects the produced wheel From 6876e05c5692835b86bebf8e73956a81bacce9b6 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 11:23:11 -0700 Subject: [PATCH 26/35] ci: complete minimal CUDA dependencies and cache keys --- .github/workflows/ci.yml | 4 ++-- .github/workflows/pypi.yml | 7 ++++--- .github/workflows/stable-abi-ci.yml | 2 +- backends/drjit/CI_BUILD_MATRIX.md | 8 +++++++- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e5e2437..2682107 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,7 +86,7 @@ jobs: path: | ${{ github.workspace }}/.cache/rayd-sccache ${{ github.workspace }}/.cache/cibuildwheel - key: rayd-sccache-v2-quick-${{ runner.os }}-${{ matrix.backend }}-${{ github.sha }} + key: rayd-sccache-v2-quick-${{ runner.os }}-${{ matrix.backend }}-${{ github.event.pull_request.head.sha || github.sha }} restore-keys: | rayd-sccache-v2-quick-${{ runner.os }}-${{ matrix.backend }}- @@ -124,7 +124,7 @@ jobs: cuda-compiler-12-8 cuda-cudart-devel-12-8 cuda-cuobjdump-12-8 - ${{ matrix.backend == 'torch' && 'libcublas-devel-12-8 libcusparse-devel-12-8 libcusolver-devel-12-8' || '' }} && + ${{ matrix.backend == 'torch' && 'cuda-driver-devel-12-8 libcublas-devel-12-8 libcusparse-devel-12-8 libcusolver-devel-12-8' || '' }} && ln -sfn /usr/local/cuda-12.8 /usr/local/cuda && /usr/local/cuda/bin/nvcc --version CIBW_ENVIRONMENT_LINUX: >- diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 252b6a6..ee7d04f 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -77,7 +77,7 @@ jobs: path: | ${{ github.workspace }}/.cache/rayd-sccache ${{ github.workspace }}/.cache/cibuildwheel - key: rayd-sccache-v2-full-linux-drjit-${{ github.sha }} + key: rayd-sccache-v2-full-linux-drjit-${{ github.event.pull_request.head.sha || github.sha }} restore-keys: | rayd-sccache-v2-full-linux-drjit- - name: Expose sccache to manylinux @@ -195,7 +195,7 @@ jobs: path: | ${{ github.workspace }}/.cache/rayd-sccache ${{ github.workspace }}/.cache/cibuildwheel - key: rayd-sccache-v2-full-linux-torch-${{ github.sha }} + key: rayd-sccache-v2-full-linux-torch-${{ github.event.pull_request.head.sha || github.sha }} restore-keys: | rayd-sccache-v2-full-linux-torch- - name: Expose sccache to manylinux @@ -227,6 +227,7 @@ jobs: cuda-compiler-12-8 cuda-cudart-devel-12-8 cuda-cuobjdump-12-8 + cuda-driver-devel-12-8 libcublas-devel-12-8 libcusparse-devel-12-8 libcusolver-devel-12-8 && @@ -329,7 +330,7 @@ jobs: uses: actions/cache@v5 with: path: ${{ github.workspace }}/.cache/rayd-sccache - key: rayd-sccache-v2-full-windows-${{ matrix.backend }}-${{ github.sha }} + key: rayd-sccache-v2-full-windows-${{ matrix.backend }}-${{ github.event.pull_request.head.sha || github.sha }} restore-keys: | rayd-sccache-v2-full-windows-${{ matrix.backend }}- - name: Install CUDA Toolkit 12.8 diff --git a/.github/workflows/stable-abi-ci.yml b/.github/workflows/stable-abi-ci.yml index ae90bd3..9269c58 100644 --- a/.github/workflows/stable-abi-ci.yml +++ b/.github/workflows/stable-abi-ci.yml @@ -58,7 +58,7 @@ jobs: uses: actions/cache@v5 with: path: ${{ github.workspace }}/.cache/rayd-sccache - key: rayd-sccache-v2-quick-${{ runner.os }}-torch-${{ github.sha }} + key: rayd-sccache-v2-quick-${{ runner.os }}-torch-${{ github.event.pull_request.head.sha || github.sha }} restore-keys: | rayd-sccache-v2-quick-${{ runner.os }}-torch- diff --git a/backends/drjit/CI_BUILD_MATRIX.md b/backends/drjit/CI_BUILD_MATRIX.md index 879e195..8a27668 100644 --- a/backends/drjit/CI_BUILD_MATRIX.md +++ b/backends/drjit/CI_BUILD_MATRIX.md @@ -84,7 +84,13 @@ verification intact without spending time on profilers, samples, and unrelated CUDA libraries. Linux manylinux jobs likewise install only `cuda-compiler`, `cuda-cudart-devel`, and `cuda-cuobjdump`, plus those three math development -libraries for Torch, rather than the 5 GiB full toolkit metapackage. +libraries and the CUDA driver stub development package for Torch, rather than +the 5 GiB full toolkit metapackage. + +Pull-request cache keys use the PR head commit rather than the synthetic merge +commit. Push, schedule, release, and manual builds use `github.sha`. Restore +prefixes still allow reuse across commits, while a new head can save updated +compiler results instead of being blocked by an immutable empty cache entry. Cache misses are always supported. Release correctness does not depend on a warm cache, and the post-build CUDA binary verifier inspects the produced wheel From 979bb2f37f2774fb44639445a0129f7454f4c63e Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 11:50:08 -0700 Subject: [PATCH 27/35] ci: finalize Torch CUDA deps and cache ownership --- .github/workflows/ci.yml | 8 +++++--- .github/workflows/pypi.yml | 11 ++++++++--- backends/drjit/CI_BUILD_MATRIX.md | 19 +++++++++++-------- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2682107..7497a1f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -124,7 +124,7 @@ jobs: cuda-compiler-12-8 cuda-cudart-devel-12-8 cuda-cuobjdump-12-8 - ${{ matrix.backend == 'torch' && 'cuda-driver-devel-12-8 libcublas-devel-12-8 libcusparse-devel-12-8 libcusolver-devel-12-8' || '' }} && + ${{ matrix.backend == 'torch' && 'cuda-driver-devel-12-8 cuda-nvrtc-devel-12-8 libcublas-devel-12-8 libcusparse-devel-12-8 libcusolver-devel-12-8' || '' }} && ln -sfn /usr/local/cuda-12.8 /usr/local/cuda && /usr/local/cuda/bin/nvcc --version CIBW_ENVIRONMENT_LINUX: >- @@ -178,7 +178,9 @@ jobs: python /project/backends/torch/scripts/verify_stable_abi.py --source-root /project/backends/torch/src/stable {dest_dir}/*.whl; fi && - $RAYD_SCCACHE_ROOT/sccache-bin/sccache --show-stats + $RAYD_SCCACHE_ROOT/sccache-bin/sccache --show-stats && + chown -R --reference=/host${{ github.workspace }} + $RAYD_SCCACHE_ROOT/rayd-sccache with: package-dir: backends/${{ matrix.backend }} output-dir: dist/${{ matrix.backend }} @@ -188,7 +190,7 @@ jobs: uses: Jimver/cuda-toolkit@v0.2.35 with: cuda: "12.8.1" - method: network + method: ${{ matrix.backend == 'torch' && 'local' || 'network' }} sub-packages: >- ${{ matrix.backend == 'torch' && '["nvcc", "cudart", "cuobjdump", "visual_studio_integration", "cublas", "cublas_dev", "cusparse", "cusparse_dev", "cusolver", "cusolver_dev"]' diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index ee7d04f..f2a5ea4 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -144,7 +144,9 @@ jobs: -w {dest_dir} {wheel} && python /project/backends/drjit/scripts/verify_cuda_binary_arches.py --stem _C {dest_dir}/*.whl && - $RAYD_SCCACHE_ROOT/sccache-bin/sccache --show-stats + $RAYD_SCCACHE_ROOT/sccache-bin/sccache --show-stats && + chown -R --reference=/host${{ github.workspace }} + $RAYD_SCCACHE_ROOT/rayd-sccache with: package-dir: backends/drjit output-dir: dist/drjit @@ -228,6 +230,7 @@ jobs: cuda-cudart-devel-12-8 cuda-cuobjdump-12-8 cuda-driver-devel-12-8 + cuda-nvrtc-devel-12-8 libcublas-devel-12-8 libcusparse-devel-12-8 libcusolver-devel-12-8 && @@ -275,7 +278,9 @@ jobs: --stem _legacy_ops --stem _stable_ops {dest_dir}/*.whl && python /project/backends/torch/scripts/verify_stable_abi.py --source-root /project/backends/torch/src/stable {dest_dir}/*.whl && - $RAYD_SCCACHE_ROOT/sccache-bin/sccache --show-stats + $RAYD_SCCACHE_ROOT/sccache-bin/sccache --show-stats && + chown -R --reference=/host${{ github.workspace }} + $RAYD_SCCACHE_ROOT/rayd-sccache with: package-dir: backends/torch output-dir: dist/torch @@ -337,7 +342,7 @@ jobs: uses: Jimver/cuda-toolkit@v0.2.35 with: cuda: "12.8.1" - method: network + method: ${{ matrix.backend == 'torch' && 'local' || 'network' }} sub-packages: >- ${{ matrix.backend == 'torch' && '["nvcc", "cudart", "cuobjdump", "visual_studio_integration", "cublas", "cublas_dev", "cusparse", "cusparse_dev", "cusolver", "cusolver_dev"]' diff --git a/backends/drjit/CI_BUILD_MATRIX.md b/backends/drjit/CI_BUILD_MATRIX.md index 8a27668..0a15465 100644 --- a/backends/drjit/CI_BUILD_MATRIX.md +++ b/backends/drjit/CI_BUILD_MATRIX.md @@ -70,22 +70,25 @@ the generated `RAYD_NVCC_LAUNCHER` wrapper, while Ninja still schedules four independent translation units. Linux manylinux jobs access the host-installed portable sccache binary and persistent cache through cibuildwheel's default `/host` mount; `/project` is a container copy and must not hold persistent -compiler state. +compiler state. Before the container exits, it resets the cache tree ownership +to match the host workspace so the GitHub cache post-step can archive it. Compiler caches are capped at 1 GiB per OS/backend/profile namespace, restore by prefix across commits, and report statistics at job completion. Python matrix jobs share that namespace rather than multiplying the repository cache footprint. The Linux cibuildwheel tool cache and the Windows pip download cache are also persisted. -Windows hosted jobs use NVIDIA's network installer. Dr.Jit installs only -`nvcc`, `cudart`, `cuobjdump`, and Visual Studio integration. Torch also -installs the cuBLAS, cuSPARSE, and cuSOLVER runtime/development packages needed -by its public CUDA headers. This keeps compilation and final-wheel architecture -verification intact without spending time on profilers, samples, and unrelated -CUDA libraries. +Windows hosted Dr.Jit jobs use NVIDIA's network installer and install only +`nvcc`, `cudart`, `cuobjdump`, and Visual Studio integration. Torch needs the +larger cuBLAS, cuSPARSE, and cuSOLVER runtime/development packages referenced by +its public CUDA headers; it uses the action's GitHub-cached local installer but +still selects only those packages. This avoids parallel matrix jobs competing +for NVIDIA network-installer downloads while excluding profilers, samples, and +unrelated CUDA libraries from installation. Linux manylinux jobs likewise install only `cuda-compiler`, `cuda-cudart-devel`, and `cuda-cuobjdump`, plus those three math development libraries and the CUDA driver stub development package for Torch, rather than -the 5 GiB full toolkit metapackage. +the 5 GiB full toolkit metapackage. Torch also installs the NVRTC development +package required by its Caffe2 CMake targets. Pull-request cache keys use the PR head commit rather than the synthetic merge commit. Push, schedule, release, and manual builds use `github.sha`. Restore From 31294fe631da31ae51762ebf60e478e1c7bd2510 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 12:50:23 -0700 Subject: [PATCH 28/35] ci: activate Windows compiler caching --- .github/workflows/ci.yml | 1 + .github/workflows/pypi.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7497a1f..439a1c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -212,6 +212,7 @@ jobs: } "CUDA_HOME=$cudaRoot" >> $env:GITHUB_ENV "CUDA_PATH=$cudaRoot" >> $env:GITHUB_ENV + "CMAKE_GENERATOR=Ninja" >> $env:GITHUB_ENV - name: Install Windows build dependencies if: runner.os == 'Windows' shell: pwsh diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index f2a5ea4..92d7fa8 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -362,6 +362,7 @@ jobs: } "CUDA_HOME=$cudaRoot" >> $env:GITHUB_ENV "CUDA_PATH=$cudaRoot" >> $env:GITHUB_ENV + "CMAKE_GENERATOR=Ninja" >> $env:GITHUB_ENV - name: Install Dr.Jit build dependencies if: matrix.backend == 'drjit' shell: pwsh From 97d8a1cf1431e4d5a34ed7341ba43fce32ef7627 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 15:01:33 -0700 Subject: [PATCH 29/35] ci: stabilize Windows CUDA installation --- .github/workflows/ci.yml | 2 +- .github/workflows/pypi.yml | 2 +- .github/workflows/stable-abi-ci.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 439a1c1..83b9aed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -190,7 +190,7 @@ jobs: uses: Jimver/cuda-toolkit@v0.2.35 with: cuda: "12.8.1" - method: ${{ matrix.backend == 'torch' && 'local' || 'network' }} + method: local sub-packages: >- ${{ matrix.backend == 'torch' && '["nvcc", "cudart", "cuobjdump", "visual_studio_integration", "cublas", "cublas_dev", "cusparse", "cusparse_dev", "cusolver", "cusolver_dev"]' diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 92d7fa8..dda8001 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -342,7 +342,7 @@ jobs: uses: Jimver/cuda-toolkit@v0.2.35 with: cuda: "12.8.1" - method: ${{ matrix.backend == 'torch' && 'local' || 'network' }} + method: local sub-packages: >- ${{ matrix.backend == 'torch' && '["nvcc", "cudart", "cuobjdump", "visual_studio_integration", "cublas", "cublas_dev", "cusparse", "cusparse_dev", "cusolver", "cusolver_dev"]' diff --git a/.github/workflows/stable-abi-ci.yml b/.github/workflows/stable-abi-ci.yml index 9269c58..cd83fa5 100644 --- a/.github/workflows/stable-abi-ci.yml +++ b/.github/workflows/stable-abi-ci.yml @@ -84,7 +84,7 @@ jobs: uses: Jimver/cuda-toolkit@v0.2.35 with: cuda: "12.8.1" - method: network + method: local sub-packages: '["nvcc", "cudart", "cuobjdump", "visual_studio_integration"]' log-file-suffix: "stable-abi-windows" From 1edcdb595dcf634ead0574f7a15225190fa6ec3c Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 17:26:31 -0700 Subject: [PATCH 30/35] ci: group Torch CUDA code generation --- .github/workflows/pypi.yml | 22 ++++++-- backends/torch/CMakeLists.txt | 51 +++++++++++++++++-- backends/torch/tests/test_project_metadata.py | 13 +++++ 3 files changed, 80 insertions(+), 6 deletions(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index dda8001..e69c5d4 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -304,6 +304,12 @@ jobs: CMAKE_CUDA_ARCHITECTURES: "70-real;75-real;80-real;86-real;87-real;89-real;90-real;100-real;101-real;120-real;120-virtual" CMAKE_BUILD_PARALLEL_LEVEL: ${{ matrix.backend == 'torch' && '2' || '4' }} CMAKE_CUDA_FLAGS: ${{ matrix.backend == 'torch' && '--threads=2' || '' }} + RAYD_TORCH_CUDA_GENCODE_FLAGS: >- + --generate-code=arch=compute_70,code=[sm_70,sm_75] + --generate-code=arch=compute_80,code=[sm_80,sm_86,sm_87,sm_89] + --generate-code=arch=compute_90,code=sm_90 + --generate-code=arch=compute_100,code=[sm_100,sm_101] + --generate-code=arch=compute_120,code=[sm_120,compute_120] CMAKE_C_COMPILER_LAUNCHER: sccache CMAKE_CXX_COMPILER_LAUNCHER: sccache CMAKE_CUDA_COMPILER_LAUNCHER: sccache @@ -382,9 +388,19 @@ jobs: - name: Build Torch wheel if: matrix.backend == 'torch' working-directory: backends/torch - run: >- - python -m build --wheel --no-isolation --outdir ../../dist/torch - -Cbuild-dir=artifacts/skbuild + shell: pwsh + run: | + $startedAt = Get-Date + python -m build --wheel --no-isolation --outdir ../../dist/torch ` + -Cbuild-dir=artifacts/skbuild + if ($LASTEXITCODE -ne 0) { + exit $LASTEXITCODE + } + $elapsedMinutes = ((Get-Date) - $startedAt).TotalMinutes + "Windows Torch full wheel build: {0:N2} minutes" -f $elapsedMinutes + if ($elapsedMinutes -ge 60) { + throw "Windows Torch full wheel build exceeded the 60-minute release limit." + } - name: Verify Dr.Jit wheel if: matrix.backend == 'drjit' shell: pwsh diff --git a/backends/torch/CMakeLists.txt b/backends/torch/CMakeLists.txt index 7a8eb8c..37c3cad 100644 --- a/backends/torch/CMakeLists.txt +++ b/backends/torch/CMakeLists.txt @@ -7,6 +7,42 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CUDA_STANDARD 17) set(CMAKE_CUDA_STANDARD_REQUIRED ON) +set( + RAYD_TORCH_CUDA_GENCODE_FLAGS + "" + CACHE STRING + "Optional explicit NVCC gencode flags used to share CUDA front-end work across compatible real architectures.") +if(DEFINED ENV{RAYD_TORCH_CUDA_GENCODE_FLAGS} + AND NOT "$ENV{RAYD_TORCH_CUDA_GENCODE_FLAGS}" STREQUAL "") + set( + RAYD_TORCH_CUDA_GENCODE_FLAGS + "$ENV{RAYD_TORCH_CUDA_GENCODE_FLAGS}" + CACHE STRING + "Optional explicit NVCC gencode flags used to share CUDA front-end work across compatible real architectures." + FORCE) +endif() +if(NOT RAYD_TORCH_CUDA_GENCODE_FLAGS STREQUAL "") + separate_arguments( + RAYD_TORCH_CUDA_GENCODE_OPTIONS + NATIVE_COMMAND + "${RAYD_TORCH_CUDA_GENCODE_FLAGS}") + set( + CMAKE_CUDA_ARCHITECTURES + OFF + CACHE STRING + "CUDA architectures are supplied by RAYD_TORCH_CUDA_GENCODE_FLAGS." + FORCE) +endif() + +function(rayd_torch_apply_cuda_gencode target) + foreach(option IN LISTS RAYD_TORCH_CUDA_GENCODE_OPTIONS) + target_compile_options( + "${target}" + PRIVATE + "$<$:${option}>") + endforeach() +endfunction() + if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type for RayD Torch native targets." FORCE) endif() @@ -158,13 +194,20 @@ if(RAYD_TORCH_BUILD_NATIVE) endif() endif() find_package(Torch REQUIRED) - if(NOT CMAKE_CUDA_ARCHITECTURES STREQUAL "${RAYD_TORCH_REQUESTED_CUDA_ARCHITECTURES}") + if(NOT RAYD_TORCH_CUDA_GENCODE_FLAGS STREQUAL "") + set(CMAKE_CUDA_ARCHITECTURES OFF) + elseif(NOT CMAKE_CUDA_ARCHITECTURES STREQUAL "${RAYD_TORCH_REQUESTED_CUDA_ARCHITECTURES}") set(CMAKE_CUDA_ARCHITECTURES "${RAYD_TORCH_REQUESTED_CUDA_ARCHITECTURES}") endif() - if(NOT CMAKE_CUDA_ARCHITECTURES OR CMAKE_CUDA_ARCHITECTURES STREQUAL "OFF") + if(RAYD_TORCH_CUDA_GENCODE_FLAGS STREQUAL "" + AND (NOT CMAKE_CUDA_ARCHITECTURES OR CMAKE_CUDA_ARCHITECTURES STREQUAL "OFF")) message(FATAL_ERROR "CMAKE_CUDA_ARCHITECTURES resolved to '${CMAKE_CUDA_ARCHITECTURES}'; RayD Torch kernels would build without -gencode flags.") endif() - message(STATUS "RayD Torch CUDA architectures: ${CMAKE_CUDA_ARCHITECTURES}") + if(NOT RAYD_TORCH_CUDA_GENCODE_FLAGS STREQUAL "") + message(STATUS "RayD Torch grouped CUDA gencode flags: ${RAYD_TORCH_CUDA_GENCODE_FLAGS}") + else() + message(STATUS "RayD Torch CUDA architectures: ${CMAKE_CUDA_ARCHITECTURES}") + endif() message(STATUS "RayD Torch/Caffe2 CUDA architectures: ${TORCH_CUDA_ARCH_LIST}") # Stable ABI shims are exported by torch_cpu and torch_cuda. Link those @@ -196,6 +239,7 @@ if(RAYD_TORCH_BUILD_NATIVE) PREFIX "" OUTPUT_NAME "_stable_ops" POSITION_INDEPENDENT_CODE ON) + rayd_torch_apply_cuda_gencode(rayd_torch_stable_ops) target_compile_definitions( rayd_torch_stable_ops PRIVATE @@ -755,6 +799,7 @@ if(RAYD_TORCH_BUILD_NATIVE) add_library(rayd_torch_native_core STATIC ${RAYD_TORCH_NATIVE_CORE_SOURCES}) set_target_properties(rayd_torch_native_core PROPERTIES POSITION_INDEPENDENT_CODE ON) + rayd_torch_apply_cuda_gencode(rayd_torch_native_core) target_include_directories( rayd_torch_native_core PUBLIC diff --git a/backends/torch/tests/test_project_metadata.py b/backends/torch/tests/test_project_metadata.py index 3e4246d..b4ee433 100644 --- a/backends/torch/tests/test_project_metadata.py +++ b/backends/torch/tests/test_project_metadata.py @@ -135,6 +135,19 @@ def test_ci_cuda_fat_binary_covers_witwin_platform_matrix(self): self.assertIn('CMAKE_CUDA_FLAGS=--threads=2', pypi) self.assertIn('CMAKE_CUDA_COMPILER_LAUNCHER=', pypi) self.assertIn('mozilla-actions/sccache-action@v0.0.10', pypi) + for grouped_flag in ( + "--generate-code=arch=compute_70,code=[sm_70,sm_75]", + "--generate-code=arch=compute_80,code=[sm_80,sm_86,sm_87,sm_89]", + "--generate-code=arch=compute_90,code=sm_90", + "--generate-code=arch=compute_100,code=[sm_100,sm_101]", + "--generate-code=arch=compute_120,code=[sm_120,compute_120]", + ): + self.assertIn(grouped_flag, pypi) + self.assertIn("Windows Torch full wheel build exceeded the 60-minute release limit.", pypi) + cmake = (root / "backends/torch/CMakeLists.txt").read_text(encoding="utf-8") + self.assertIn("RAYD_TORCH_CUDA_GENCODE_FLAGS", cmake) + self.assertIn("rayd_torch_apply_cuda_gencode(rayd_torch_stable_ops)", cmake) + self.assertIn("rayd_torch_apply_cuda_gencode(rayd_torch_native_core)", cmake) self.assertIn('CMAKE_CUDA_ARCHITECTURES: "87-real;120-real;120-virtual"', pull_request) self.assertIn("--expected-sass 87,120", pull_request) self.assertNotIn("self-hosted", pull_request) From af355abb1621d317f83039d294abb0b68c1d7918 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 17:40:46 -0700 Subject: [PATCH 31/35] fix: isolate grouped Torch gencode flags --- backends/torch/CMakeLists.txt | 22 +++++++++++++++++++ backends/torch/tests/test_project_metadata.py | 2 ++ 2 files changed, 24 insertions(+) diff --git a/backends/torch/CMakeLists.txt b/backends/torch/CMakeLists.txt index 37c3cad..2166269 100644 --- a/backends/torch/CMakeLists.txt +++ b/backends/torch/CMakeLists.txt @@ -26,6 +26,7 @@ if(NOT RAYD_TORCH_CUDA_GENCODE_FLAGS STREQUAL "") RAYD_TORCH_CUDA_GENCODE_OPTIONS NATIVE_COMMAND "${RAYD_TORCH_CUDA_GENCODE_FLAGS}") + set(RAYD_TORCH_CALLER_CUDA_FLAGS "$ENV{CMAKE_CUDA_FLAGS}") set( CMAKE_CUDA_ARCHITECTURES OFF @@ -195,6 +196,26 @@ if(RAYD_TORCH_BUILD_NATIVE) endif() find_package(Torch REQUIRED) if(NOT RAYD_TORCH_CUDA_GENCODE_FLAGS STREQUAL "") + string( + REGEX REPLACE + "(^|[ \t])-gencode[ \t]+arch=[^ \t]+,code=[^ \t]+" + "" + CMAKE_CUDA_FLAGS + "${CMAKE_CUDA_FLAGS}") + string(STRIP "${CMAKE_CUDA_FLAGS}" CMAKE_CUDA_FLAGS) + if(NOT RAYD_TORCH_CALLER_CUDA_FLAGS STREQUAL "") + string( + FIND + "${CMAKE_CUDA_FLAGS}" + "${RAYD_TORCH_CALLER_CUDA_FLAGS}" + RAYD_TORCH_CALLER_CUDA_FLAGS_INDEX) + if(RAYD_TORCH_CALLER_CUDA_FLAGS_INDEX EQUAL -1) + string( + PREPEND + CMAKE_CUDA_FLAGS + "${RAYD_TORCH_CALLER_CUDA_FLAGS} ") + endif() + endif() set(CMAKE_CUDA_ARCHITECTURES OFF) elseif(NOT CMAKE_CUDA_ARCHITECTURES STREQUAL "${RAYD_TORCH_REQUESTED_CUDA_ARCHITECTURES}") set(CMAKE_CUDA_ARCHITECTURES "${RAYD_TORCH_REQUESTED_CUDA_ARCHITECTURES}") @@ -205,6 +226,7 @@ if(RAYD_TORCH_BUILD_NATIVE) endif() if(NOT RAYD_TORCH_CUDA_GENCODE_FLAGS STREQUAL "") message(STATUS "RayD Torch grouped CUDA gencode flags: ${RAYD_TORCH_CUDA_GENCODE_FLAGS}") + message(STATUS "RayD Torch CUDA flags after removing Torch gencode flags: ${CMAKE_CUDA_FLAGS}") else() message(STATUS "RayD Torch CUDA architectures: ${CMAKE_CUDA_ARCHITECTURES}") endif() diff --git a/backends/torch/tests/test_project_metadata.py b/backends/torch/tests/test_project_metadata.py index b4ee433..7d7688e 100644 --- a/backends/torch/tests/test_project_metadata.py +++ b/backends/torch/tests/test_project_metadata.py @@ -146,6 +146,8 @@ def test_ci_cuda_fat_binary_covers_witwin_platform_matrix(self): self.assertIn("Windows Torch full wheel build exceeded the 60-minute release limit.", pypi) cmake = (root / "backends/torch/CMakeLists.txt").read_text(encoding="utf-8") self.assertIn("RAYD_TORCH_CUDA_GENCODE_FLAGS", cmake) + self.assertIn("RAYD_TORCH_CALLER_CUDA_FLAGS", cmake) + self.assertIn("-gencode[ \\t]+arch=[^ \\t]+,code=[^ \\t]+", cmake) self.assertIn("rayd_torch_apply_cuda_gencode(rayd_torch_stable_ops)", cmake) self.assertIn("rayd_torch_apply_cuda_gencode(rayd_torch_native_core)", cmake) self.assertIn('CMAKE_CUDA_ARCHITECTURES: "87-real;120-real;120-virtual"', pull_request) From eca63e5c106f61175b3ffe12abcca49816c72cd3 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 18:57:23 -0700 Subject: [PATCH 32/35] fix: avoid grouped NVCC thread race --- .github/workflows/pypi.yml | 1 - backends/torch/tests/test_project_metadata.py | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index e69c5d4..139bcd4 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -303,7 +303,6 @@ jobs: env: CMAKE_CUDA_ARCHITECTURES: "70-real;75-real;80-real;86-real;87-real;89-real;90-real;100-real;101-real;120-real;120-virtual" CMAKE_BUILD_PARALLEL_LEVEL: ${{ matrix.backend == 'torch' && '2' || '4' }} - CMAKE_CUDA_FLAGS: ${{ matrix.backend == 'torch' && '--threads=2' || '' }} RAYD_TORCH_CUDA_GENCODE_FLAGS: >- --generate-code=arch=compute_70,code=[sm_70,sm_75] --generate-code=arch=compute_80,code=[sm_80,sm_86,sm_87,sm_89] diff --git a/backends/torch/tests/test_project_metadata.py b/backends/torch/tests/test_project_metadata.py index 7d7688e..d7a420a 100644 --- a/backends/torch/tests/test_project_metadata.py +++ b/backends/torch/tests/test_project_metadata.py @@ -133,6 +133,8 @@ def test_ci_cuda_fat_binary_covers_witwin_platform_matrix(self): self.assertIn('CMAKE_BUILD_PARALLEL_LEVEL=4', pypi) self.assertIn('CMAKE_BUILD_PARALLEL_LEVEL=2', pypi) self.assertIn('CMAKE_CUDA_FLAGS=--threads=2', pypi) + windows_wheel_job = pypi.split(" build-windows-wheels:", 1)[1] + self.assertNotIn("CMAKE_CUDA_FLAGS:", windows_wheel_job) self.assertIn('CMAKE_CUDA_COMPILER_LAUNCHER=', pypi) self.assertIn('mozilla-actions/sccache-action@v0.0.10', pypi) for grouped_flag in ( From 49f14e3981a8184299a5285b4a3d4efa0e2047eb Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 19:01:20 -0700 Subject: [PATCH 33/35] ci: isolate manual distribution runs by commit --- .github/workflows/pypi.yml | 2 +- backends/torch/tests/test_project_metadata.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 139bcd4..773175d 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -11,7 +11,7 @@ on: workflow_dispatch: concurrency: - group: distributions-${{ github.ref }} + group: distributions-${{ github.ref }}-${{ github.event_name == 'workflow_dispatch' && github.sha || github.event_name }} cancel-in-progress: ${{ github.event_name != 'release' }} permissions: diff --git a/backends/torch/tests/test_project_metadata.py b/backends/torch/tests/test_project_metadata.py index d7a420a..a4fe847 100644 --- a/backends/torch/tests/test_project_metadata.py +++ b/backends/torch/tests/test_project_metadata.py @@ -133,6 +133,10 @@ def test_ci_cuda_fat_binary_covers_witwin_platform_matrix(self): self.assertIn('CMAKE_BUILD_PARALLEL_LEVEL=4', pypi) self.assertIn('CMAKE_BUILD_PARALLEL_LEVEL=2', pypi) self.assertIn('CMAKE_CUDA_FLAGS=--threads=2', pypi) + self.assertIn( + "github.event_name == 'workflow_dispatch' && github.sha", + pypi, + ) windows_wheel_job = pypi.split(" build-windows-wheels:", 1)[1] self.assertNotIn("CMAKE_CUDA_FLAGS:", windows_wheel_job) self.assertIn('CMAKE_CUDA_COMPILER_LAUNCHER=', pypi) From e005f3db0b65b173f67b04dd337e1eaccff4cf48 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 19:13:52 -0700 Subject: [PATCH 34/35] fix: bypass sccache for grouped Windows CUDA --- .github/workflows/pypi.yml | 2 +- backends/torch/tests/test_project_metadata.py | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 773175d..7e2146c 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -311,7 +311,7 @@ jobs: --generate-code=arch=compute_120,code=[sm_120,compute_120] CMAKE_C_COMPILER_LAUNCHER: sccache CMAKE_CXX_COMPILER_LAUNCHER: sccache - CMAKE_CUDA_COMPILER_LAUNCHER: sccache + CMAKE_CUDA_COMPILER_LAUNCHER: ${{ matrix.backend == 'torch' && '' || 'sccache' }} RAYD_NVCC_LAUNCHER: sccache SCCACHE_DIR: ${{ github.workspace }}/.cache/rayd-sccache SCCACHE_CACHE_SIZE: 1G diff --git a/backends/torch/tests/test_project_metadata.py b/backends/torch/tests/test_project_metadata.py index a4fe847..a4eed2c 100644 --- a/backends/torch/tests/test_project_metadata.py +++ b/backends/torch/tests/test_project_metadata.py @@ -139,6 +139,11 @@ def test_ci_cuda_fat_binary_covers_witwin_platform_matrix(self): ) windows_wheel_job = pypi.split(" build-windows-wheels:", 1)[1] self.assertNotIn("CMAKE_CUDA_FLAGS:", windows_wheel_job) + self.assertIn( + "CMAKE_CUDA_COMPILER_LAUNCHER: " + "${{ matrix.backend == 'torch' && '' || 'sccache' }}", + windows_wheel_job, + ) self.assertIn('CMAKE_CUDA_COMPILER_LAUNCHER=', pypi) self.assertIn('mozilla-actions/sccache-action@v0.0.10', pypi) for grouped_flag in ( From a6f3e54907ce0a61679cb92a9f4bc00601edd221 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Thu, 23 Jul 2026 19:28:24 -0700 Subject: [PATCH 35/35] ci: add focused Windows Torch validation --- .github/workflows/pypi.yml | 17 ++++++++++++++--- backends/torch/tests/test_project_metadata.py | 11 ++++++++++- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 7e2146c..fdb3ed6 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -9,6 +9,15 @@ on: release: types: [published] workflow_dispatch: + inputs: + scope: + description: Manual validation scope + required: true + default: full + type: choice + options: + - full + - windows-torch-smoke concurrency: group: distributions-${{ github.ref }}-${{ github.event_name == 'workflow_dispatch' && github.sha || github.event_name }} @@ -48,6 +57,7 @@ jobs: runs-on: ubuntu-22.04 timeout-minutes: 120 needs: metadata + if: inputs.scope != 'windows-torch-smoke' env: SCCACHE_DIR: ${{ github.workspace }}/.cache/rayd-sccache SCCACHE_CACHE_SIZE: 1G @@ -161,6 +171,7 @@ jobs: runs-on: ubuntu-22.04 timeout-minutes: 180 needs: metadata + if: inputs.scope != 'windows-torch-smoke' env: SCCACHE_DIR: ${{ github.workspace }}/.cache/rayd-sccache SCCACHE_CACHE_SIZE: 1G @@ -298,8 +309,8 @@ jobs: strategy: fail-fast: false matrix: - backend: [drjit, torch] - python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"] + backend: ${{ fromJSON(inputs.scope == 'windows-torch-smoke' && '["torch"]' || '["drjit","torch"]') }} + python-version: ${{ fromJSON(inputs.scope == 'windows-torch-smoke' && '["3.10"]' || '["3.10","3.11","3.12","3.13","3.14"]') }} env: CMAKE_CUDA_ARCHITECTURES: "70-real;75-real;80-real;86-real;87-real;89-real;90-real;100-real;101-real;120-real;120-virtual" CMAKE_BUILD_PARALLEL_LEVEL: ${{ matrix.backend == 'torch' && '2' || '4' }} @@ -311,7 +322,7 @@ jobs: --generate-code=arch=compute_120,code=[sm_120,compute_120] CMAKE_C_COMPILER_LAUNCHER: sccache CMAKE_CXX_COMPILER_LAUNCHER: sccache - CMAKE_CUDA_COMPILER_LAUNCHER: ${{ matrix.backend == 'torch' && '' || 'sccache' }} + CMAKE_CUDA_COMPILER_LAUNCHER: ${{ matrix.backend == 'drjit' && 'sccache' || '' }} RAYD_NVCC_LAUNCHER: sccache SCCACHE_DIR: ${{ github.workspace }}/.cache/rayd-sccache SCCACHE_CACHE_SIZE: 1G diff --git a/backends/torch/tests/test_project_metadata.py b/backends/torch/tests/test_project_metadata.py index a4eed2c..18e50fd 100644 --- a/backends/torch/tests/test_project_metadata.py +++ b/backends/torch/tests/test_project_metadata.py @@ -137,11 +137,20 @@ def test_ci_cuda_fat_binary_covers_witwin_platform_matrix(self): "github.event_name == 'workflow_dispatch' && github.sha", pypi, ) + self.assertIn("windows-torch-smoke", pypi) + self.assertIn( + "inputs.scope == 'windows-torch-smoke' && '[\"torch\"]'", + pypi, + ) + self.assertIn( + "inputs.scope == 'windows-torch-smoke' && '[\"3.10\"]'", + pypi, + ) windows_wheel_job = pypi.split(" build-windows-wheels:", 1)[1] self.assertNotIn("CMAKE_CUDA_FLAGS:", windows_wheel_job) self.assertIn( "CMAKE_CUDA_COMPILER_LAUNCHER: " - "${{ matrix.backend == 'torch' && '' || 'sccache' }}", + "${{ matrix.backend == 'drjit' && 'sccache' || '' }}", windows_wheel_job, ) self.assertIn('CMAKE_CUDA_COMPILER_LAUNCHER=', pypi)