Skip to content

Fix CUDA arch flags being silently dropped on CMake < 3.18 - #15506

Merged
Nir-Az merged 3 commits into
realsenseai:developmentfrom
zhoubincalder:fix-cuda-arch-flags-older-cmake
Aug 13, 2026
Merged

Nir-Az merged 3 commits into
realsenseai:developmentfrom
zhoubincalder:fix-cuda-arch-flags-older-cmake

Conversation

@zhoubincalder

Copy link
Copy Markdown
Contributor

Summary

The pre-3.18 fallback in CMake/cuda_config.cmake appends the -gencode flags to CUDA_NVCC_FLAGS, but that variable is only read by FindCUDA's cuda_add_library() / cuda_compile(). This project enables CUDA as a first-class language (enable_language(CUDA) at the top of the same file) and adds the .cu files with target_sources(), so CUDA_NVCC_FLAGS never reaches nvcc — the entire CUDA_ARCH_LIST is silently discarded and nvcc builds for its own default architecture only.

This PR switches the fallback to CMAKE_CUDA_FLAGS, which the CUDA language driver does pass to nvcc, and emits both the real (sm_) and virtual (compute_) targets so the fallback matches the code=[compute_X,sm_X] that CMAKE_CUDA_ARCHITECTURES generates on the modern path.

Why it matters

Jetson is the main casualty: the stock apt cmake is below 3.18 on the host OS of JetPack 4 and 5 (3.10.2 on Ubuntu 18.04, 3.16.3 on 20.04), so those builds take the fallback. The sm_72 (Xavier) and sm_87 (Orin) entries recently added to CUDA_ARCH_LIST therefore have no effect there at all — which is exactly the "no kernel image available" situation the comment above them warns about. Today those builds survive only because nvcc's default happens to embed PTX that the driver can JIT, so there is no native SASS for the device and a JIT cost on first launch.

cmake_minimum_required(VERSION 3.10) in this file and in the top-level CMakeLists.txt means pre-3.18 is a supported configuration, so the fallback is a live path rather than dead code.

Verification

Done on CUDA 13.0 / CMake 3.28 / aarch64, using this repo's cuda_config.cmake with only the if(POLICY CMP0104) check stubbed to if(FALSE) to force the fallback branch, then cuobjdump on the resulting object:

Before

CUDA_FLAGS = -std=c++17
ELF file    1: k.cu.1.sm_75.cubin          <- nvcc default, whole arch list lost

After

CUDA_FLAGS =  -gencode arch=compute_75,code=sm_75 -gencode arch=compute_75,code=compute_75 \
              -gencode arch=compute_80,code=sm_80 ... -std=c++17
ELF file    1..8: sm_75, sm_80, sm_86, sm_89, sm_90, sm_100, sm_120, sm_110 cubins
PTX file    1..8: matching PTX for each

Additional checks:

  • The modern (CMake >= 3.18) path is untouched — a full cmake configure of the project with -DBUILD_WITH_CUDA=ON still generates the same --generate-code=arch=compute_X,code=[compute_X,sm_X] set as before this change.
  • src/cuda/cuda-conversion.cu, src/cuda/cuda-pointcloud.cu and src/proc/cuda/cuda-align.cu all compile with the new flags.

I do not have a Xavier or Orin on hand, so the Jetson impact above is reasoned from the arch list and CMake version rather than measured on the device.

Notes

  • Build-system only; no runtime or API change.
  • Found while investigating FPS drop and stream latency on Jetson ROS #9879 (FPS drop with pointcloud/align on Jetson). The rest of that investigation is unrelated to this patch — most of the SDK-side causes there have already been fixed on development (NEON paths, pointcloud_cuda inheriting pointcloud_neon, the zero-distortion early-out, persistent device buffers).

The pre-3.18 fallback in cuda_config.cmake appends the -gencode flags to
CUDA_NVCC_FLAGS, but that variable is only consumed by FindCUDA's
cuda_add_library()/cuda_compile(). This project enables CUDA as a
first-class language (enable_language(CUDA)) and adds the .cu files with
target_sources(), so CUDA_NVCC_FLAGS never reaches nvcc: the whole
CUDA_ARCH_LIST is discarded and nvcc builds for its own default
architecture only.

Use CMAKE_CUDA_FLAGS, which is what the CUDA language driver actually
passes to nvcc, and emit both the real (sm_) and virtual (compute_)
targets so the fallback matches the code=[compute_X,sm_X] that
CMAKE_CUDA_ARCHITECTURES generates on the modern path.

This matters most on Jetson, where the stock apt cmake is older than 3.18
(3.10.2 on Ubuntu 18.04, 3.16.3 on 20.04). On those hosts the sm_72
(Xavier) and sm_87 (Orin) entries added to CUDA_ARCH_LIST have no effect
at all, which is the "no kernel image available" case the comment above
them warns about.

Verified with cuobjdump on CUDA 13.0 / CMake 3.28, using this file with
only the CMP0104 check stubbed out to force the fallback:

  before: CUDA_FLAGS = -std=c++17
          -> sm_75 cubin only (nvcc default)
  after:  CUDA_FLAGS = -gencode arch=compute_75,code=sm_75 ... -std=c++17
          -> cubin + PTX for every arch in CUDA_ARCH_LIST

The modern (CMake >= 3.18) path is untouched; its generated flags are
unchanged. cuda-conversion.cu, cuda-pointcloud.cu and cuda-align.cu all
compile with the new flags.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Comment thread CMake/cuda_config.cmake Resolved

@Nir-Az Nir-Az left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Verified the diagnosis independently and it holds: CUDA_NVCC_FLAGS is only consumed by FindCUDA's cuda_add_library()/cuda_compile(), and this project adds the .cu files with target_sources() (src/cuda/CMakeLists.txt), so the fallback branch was a no-op. Scope is fine too — cuda_config.cmake is included from CMake/global_config.cmake in the top-level directory scope, the same scope where add_library(${LRS_TARGET}) lives, so CMAKE_CUDA_FLAGS does reach nvcc for the library and for src/gl. Using a normal (non-cache) set is also the right call: no accumulation across re-configures and nothing left behind when BUILD_WITH_CUDA is turned off.

The JetPack 5 case checks out concretely: CUDA 11.4 puts both 72 and 87 in CUDA_ARCH_LIST, and stock Ubuntu 20.04 cmake is 3.16.3, so that build takes the fallback and today gets nvcc's default sm_52 only — working purely by PTX JIT. After this change it gets real SASS.

Two things outside the diff hunk:

1. Same bug class two lines up. set(CUDA_PROPAGATE_HOST_FLAGS OFF) and set(CUDA_SEPARABLE_COMPILATION ON) (lines 13-14) are also FindCUDA-only variables, so they are dead in language mode on both branches — separable compilation is silently not applied today. The language-mode equivalent is the target property (set_target_properties(${LRS_TARGET} PROPERTIES CUDA_SEPARABLE_COMPILATION ON)) or CMAKE_CUDA_SEPARABLE_COMPILATION. Worth either fixing here or explicitly calling out as a follow-up, since it is the same root cause: find_package(CUDA REQUIRED) (line 5) coexisting with enable_language(CUDA) (line 3).

2. This path has no CI coverage. No job builds CUDA on a pre-3.18 cmake, and the verification stubbed if(POLICY CMP0104) on cmake 3.28 rather than running a real 3.10-3.17. Residual risk is low (CMAKE_CUDA_FLAGS has been honored since 3.8, and the arch entries are CUDA-version gated so no unknown-arch flags can be emitted), but it is worth stating in the PR that the branch stays untested after merge.

🤖 Generated by AI

Comment thread CMake/cuda_config.cmake Resolved

@Nir-Az Nir-Az left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Great improvement, thanks!

@sysrsbuild-gh

Copy link
Copy Markdown

Can one of the admins verify this patch?

@Nir-Az

Nir-Az commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

ok to test

@Nir-Az
Nir-Az merged commit 40daebe into realsenseai:development Aug 13, 2026
35 checks passed
@zhoubincalder
zhoubincalder deleted the fix-cuda-arch-flags-older-cmake branch August 13, 2026 09:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants