Skip to content

Commit feca367

Browse files
author
Abraham Sewill
committed
build.rs: gate NVIDIA auto-detect on sm_61 minimum (our README floor)
Dual-vendor host hit: AMD W5700 + ancient secondary NVIDIA (sm_52, Maxwell 1). nvidia-smi reports the NVIDIA, so build.rs routed onto the CUB/BUILD_CUDA=ON + ACPP_TARGETS=generic (SSCP) path — ignoring the actually-useful AMD card. Compile then failed inside AdaptiveCpp's half.hpp: it references __hadd/__hsub/__hmul/__hdiv/ __hlt/__hle/__hgt/__hge unconditionally in any nvcc device pass, but cuda_fp16.h guards those behind __CUDA_ARCH__ >= 530. So the existing `-include=cuda_fp16.h` workaround can't save a sm_52 user: the symbols literally aren't in the header at that arch. Our own README minimum is sm_61 (Pascal / GTX 10-series). Anything below that is unsupported by design and shouldn't be steering vendor-precedence. Add `usable_nvidia_arch()` that returns Some only when `detect_cuda_arch` reports ≥ 61; emit a cargo:warning and return None otherwise. Route both the ACPP_TARGETS and XCHPLOT2_BUILD_CUDA defaults through it so the W5700 user's build correctly falls through to AMD detection → BUILD_CUDA=OFF + ACPP_TARGETS=hip:gfx1013 automatically. Explicit CUDA_ARCHITECTURES / XCHPLOT2_BUILD_CUDA / ACPP_TARGETS env overrides still win.
1 parent 114f17b commit feca367

1 file changed

Lines changed: 42 additions & 2 deletions

File tree

build.rs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,37 @@ fn detect_cuda_arch() -> Option<String> {
3636
Some(arch.to_string())
3737
}
3838

39+
/// Same probe as `detect_cuda_arch`, but filters out NVIDIA GPUs
40+
/// below our README-documented minimum compute capability (sm_61,
41+
/// Pascal / GTX 10-series). Below sm_53 the GPU also lacks native
42+
/// FP16 intrinsics (`__hadd` / `__hsub` / `__hmul` / `__hdiv` /
43+
/// `__hlt` / `__hle` / `__hgt` / `__hge`) that AdaptiveCpp's
44+
/// `half.hpp` emits unconditionally in any nvcc device pass —
45+
/// `cuda_fp16.h` guards those behind `__CUDA_ARCH__ >= 530`. Users
46+
/// with an ancient secondary NVIDIA card (e.g. a GTX 750 Ti sitting
47+
/// next to a real AMD / NVIDIA workhorse) otherwise get routed onto
48+
/// the CUB fast path via vendor-precedence and fail to compile
49+
/// SortCuda.cu with a cascade of "identifier `__hXXX` is undefined".
50+
///
51+
/// Returns Some(arch) only when nvidia-smi reports a card at or
52+
/// above our minimum; emits a cargo:warning and returns None
53+
/// otherwise so callers fall through to the AMD / Intel detection.
54+
fn usable_nvidia_arch() -> Option<String> {
55+
let arch = detect_cuda_arch()?;
56+
let n: u32 = arch.parse().ok()?;
57+
if n < 61 {
58+
println!(
59+
"cargo:warning=xchplot2: nvidia-smi detected sm_{arch} — below our \
60+
minimum supported compute capability (sm_61 / Pascal). Ignoring \
61+
NVIDIA for default targeting; set CUDA_ARCHITECTURES={arch} + \
62+
XCHPLOT2_BUILD_CUDA=ON to force-build the CUB path anyway (not \
63+
recommended — AdaptiveCpp half.hpp references sm_53+ FP16 \
64+
intrinsics that your card's headers don't provide).");
65+
return None;
66+
}
67+
Some(arch)
68+
}
69+
3970
/// Check whether nvcc is on $PATH and runnable. Used as the fall-back
4071
/// signal for XCHPLOT2_BUILD_CUDA when no GPU is enumerable (headless
4172
/// CI / container builds). Runs `nvcc --version` rather than a simple
@@ -146,7 +177,11 @@ fn main() {
146177
// them, and acpp rejects an empty target string.
147178
Ok(v) if !v.is_empty() => (v, "$ACPP_TARGETS"),
148179
Ok(_) | Err(_) => {
149-
if source != "fallback (no nvidia-smi)" {
180+
// Prefer a USABLE NVIDIA GPU (sm_61+) over AMD, otherwise fall
181+
// through to AMD / fallback. `detect_cuda_arch` alone would
182+
// trigger on an ancient secondary NVIDIA card even when AMD is
183+
// the real plotting target (see usable_nvidia_arch).
184+
if usable_nvidia_arch().is_some() {
150185
("generic".to_string(), "NVIDIA detected — using SSCP")
151186
} else if let Some(gfx) = detect_amd_gfx() {
152187
(format!("hip:{gfx}"), "rocminfo probe")
@@ -172,7 +207,12 @@ fn main() {
172207
let (build_cuda, bc_source) = match env::var("XCHPLOT2_BUILD_CUDA") {
173208
Ok(v) if !v.is_empty() => (v, "$XCHPLOT2_BUILD_CUDA"),
174209
_ => {
175-
let nvidia_gpu = detect_cuda_arch().is_some();
210+
// Same usable-arch gate as the ACPP_TARGETS block: an
211+
// ancient secondary NVIDIA card (e.g. sm_52 alongside an
212+
// AMD W5700) must NOT claim the CUB path, because
213+
// AdaptiveCpp half.hpp references sm_53+ FP16 intrinsics
214+
// that the old card's cuda_fp16.h guards out.
215+
let nvidia_gpu = usable_nvidia_arch().is_some();
176216
let amd_gpu = detect_amd_gfx().is_some();
177217
let intel_gpu = detect_intel_gpu();
178218
if nvidia_gpu {

0 commit comments

Comments
 (0)