【Bug已解决】sm110: torch.AcceleratorError: CUDA error: an illegal instruction was encountered 解决方案

【Bug已解决】sm110: torch.AcceleratorError: CUDA error: an illegal instruction was encountered 解决方案

一、现象长什么样

sm_110(Blackwell 架构,如 B200 / B300 的 compute capability 12.0/12.1 相关代号)设备上运行 CUDA 相关代码(模型加载、推理、或某个自定义 kernel)时,进程崩溃,报非法指令错误。典型日志:

torch.AcceleratorError: CUDA error: an illegal instruction was encountered at <some kernel launch>

或者更笼统:

sm110: torch.AcceleratorError: CUDA error: an illegal instruction was encountered

几个特征,帮你判断是不是同一个坑:

  • 报错是illegal instruction was encountered,这是 GPU kernel 执行了当前架构不支持的指令,属于底层硬件级错误。
  • 错误里明确出现sm110或设备架构相关字样,且发生在某个 kernel 启动/执行时,不是 Python 层逻辑错。
  • 同一份代码在 sm_90(H100)等老架构能跑,一到 sm_110 就崩——说明是「为某架构编译的 kernel 在 sm_110 上用了不支持的指令」,或反过来「为 sm_110 编译的 kernel 在老卡上不支持」(这里聚焦前者)。
  • 崩溃可能发生在第一次 kernel 调用,也可能在运行一段时间后的某个特定算子(如某个 FlashAttention / 量化 kernel)。

二、背景

「illegal instruction」在 CUDA 语境下,几乎总是架构与指令集不匹配:GPU kernel 的 PTX/SASS 里用了一条当前 GPU 不认识的指令。对 sm_110(Blackwell)来说,常见诱因有:

1. kernel 编译目标架构不对

CUDA kernel 编译时通过-gencode arch=compute_XX,code=sm_XX指定目标架构。如果:

  • 一个 kernel 被编译成sm_90的 SASS,但在sm_110上运行——通常向后兼容,不会非法指令;
  • 反过来,一个 kernel 被错误地编译成sm_110的 SASS(用了 Blackwell 专属指令,如新的 TMA、新的 fp4/fp8 指令、新的张量核心 mma),却在不支持这些新指令的环境里跑(比如驱动太老、或实际设备不是真 sm_110),就会非法指令。

更常见的是中间态:kernel 用了某个只有 sm_110 才有的内建(intrinsic),但在编译/运行时被分发到了一个「名义 sm_110、实际指令集残缺」的路径,于是执行未定义指令。

2.TORCH_CUDA_ARCH_LIST与环境不匹配

PyTorch / 扩展在安装时TORCH_CUDA_ARCH_LIST预编译 kernel。如果安装时该变量包含sm_110,于是编译出了 Blackwell 专属 kernel;但运行时环境(驱动版本、容器里的 CUDA 版本)并不真正支持这些指令 → 执行即非法指令。

3. JIT / 运行时编译(如 Triton、cutlass 模板)生成了 sm_110 专属指令

Triton / CUTLASS 在运行时根据设备架构生成 kernel。如果生成逻辑「误判」设备为 sm_110、生成了 Blackwell 专属指令,而实际硬件/驱动不支持 → 非法指令。

4. 量化 kernel 用了新数据类型指令

NVFP4 / fp8 在 Blackwell 上有新的 load/mma 指令。若量化 kernel 假设 sm_110 支持这些指令、实际却在不完全支持的环境执行 → 非法指令。

5. 二进制/库版本错配

加载了为更高架构编译的.so(如别人机器 sm_110 编译的扩展,拷到你机器但驱动不匹配),运行即崩。

核心:kernel 的「指令集」与「实际运行硬件+驱动」不一致

三、根因

根因一句话:在 sm_110(Blackwell)上运行的某个 CUDA kernel,其编译产物里包含了一条当前「硬件 + 驱动 + 运行时」组合实际不支持的指令(常见于 Blackwell 专属的 fp4/fp8/TMA/新 mma 指令,或TORCH_CUDA_ARCH_LIST与运行时环境错配),GPU 执行到该指令时抛出 illegal instruction,被 PyTorch 包装成torch.AcceleratorError: CUDA error

具体成因:

  1. 编译目标过新:kernel 按sm_110编译出 Blackwell 专属指令,但运行时驱动/CUDA 不支持 → 非法指令。
  2. TORCH_CUDA_ARCH_LIST错配:安装时含sm_110预编译,运行时环境不支持这些指令。
  3. JIT 误判架构:Triton/CUTLASS 运行时把设备当 sm_110 生成专属指令,实际不支持。
  4. 量化 kernel 用新数据类型指令:NVFP4/fp8 的 Blackwell 专属 load/mma 在不完全支持的环境执行。
  5. 库/二进制版本错配:加载了为更高架构编译的扩展.so,运行即崩。
  6. 缺少能力探测:代码在调用 kernel 前没确认「当前 sm 是否支持该 kernel 用到的指令集」,直接调用 → 非法指令。

核心矛盾:kernel 假设运行环境支持某架构的全部指令,但「编译期目标」与「运行时真实能力」不一致,中间没有任何能力校验,于是把「不支持的指令」直接送进 GPU 执行

四、最小可运行复现

下面用纯 Python 模拟「kernel 按 sm_110 编译、但运行时设备不支持该指令集、执行即非法指令」的探测逻辑:

# reproduce_illegal_insn.py # 复现:kernel 用的指令集 > 运行时设备支持的指令集 -> 非法指令 class Device: def __init__(self, sm: str, supported_features: set): self.sm = sm self.features = supported_features def launch_kernel(device: Device, kernel_requires: set): missing = kernel_requires - device.features if missing: raise RuntimeError( f"illegal instruction: kernel 需要 {missing},但 {device.sm} 不支持" ) return "kernel ok" if __name__ == "__main__": # 编译时按 sm_110 用了 Blackwell 专属 fp4 指令 kernel_requires = {"fp4_mma", "tma"} # 运行时环境实际只支持到 sm_90 能力 runtime_device = Device("sm_110_nominal", {"fp8_mma"}) try: launch_kernel(runtime_device, kernel_requires) except RuntimeError as e: print("复现成功:", e)

运行python reproduce_illegal_insn.py,会看到「kernel 需要的指令超出设备支持」直接触发非法指令类错误。

五、解决方案(第一层:最小直接修复)

最小修复,按见效快慢:

招式 A——重设TORCH_CUDA_ARCH_LIST并重装/重编译:让 PyTorch 及扩展按「运行时真实支持」的架构编译,而非盲目含 sm_110。

# fix_layer1_arch.py def recommended_arch_list(device_sm: str, driver_cuda: str) -> str: """按运行时真实能力给出编译架构列表,避免过度包含 sm_110。""" # 仅当驱动确实支持 Blackwell 时才编 sm_110 if device_sm.startswith("sm_11") and driver_cuda >= "12.4": return "7.5;8.0;9.0;11.0;12.0" # 否则回退到稳妥的 sm_90 return "7.5;8.0;9.0" if __name__ == "__main__": print(recommended_arch_list("sm_110", "12.4")) # 含 12.0 print(recommended_arch_list("sm_110", "12.0")) # 回退 sm_90

招式 B——运行时能力探测 + kernel 回退:调用 Blackwell 专属 kernel 前,先探测设备是否真支持;不支持就回退到 sm_90 兼容路径。

def launch_safe(device_sm: str, has_blackwell_kernel: bool): if device_sm.startswith("sm_11") and has_blackwell_kernel: return "blackwell_kernel" return "sm90_fallback" # 用兼容 kernel,避免非法指令

六、解决方案(第二层:结构性改进)

把「kernel 指令集能力」做成探测模块,明确记录设备支持哪些指令集,调用前校验:

# fix_layer2_cap.py from dataclasses import dataclass, field @dataclass class DeviceFeature: sm: str features: set = field(default_factory=set) @classmethod def detect(cls, sm: str, driver_cuda: str) -> "DeviceFeature": feats = {"fp8_mma", "tma"} if sm.startswith(("sm_9",)) else set() if sm.startswith("sm_11") and driver_cuda >= "12.4": feats |= {"fp4_mma", "tma_v2"} return cls(sm, feats) def can_run(self, kernel_requires: set) -> bool: return kernel_requires <= self.features def select_kernel(self, kernels: dict): """kernels: {required_features: impl_name},选第一个能跑的。""" for req, name in kernels.items(): if self.can_run(req): return name raise RuntimeError(f"无可用 kernel,设备 {self.sm} 不支持任何候选") if __name__ == "__main__": dev = DeviceFeature.detect("sm_110", "12.4") kernels = { frozenset({"fp4_mma"}): "blackwell_fp4", frozenset({"fp8_mma"}): "sm90_fp8", } print("选中的 kernel:", dev.select_kernel(kernels))

这样:换设备/换驱动时,kernel 选择自动按真实能力走,绝不会把「设备不支持的指令」送进 GPU。

七、解决方案(第三层:断言 / CI 守护)

把「kernel 指令集能力校验」钉进断言和 CI:

# fix_layer3_guard.py # ---- pytest 用例,进 CI ---- def test_sm110_driver_ok_runs_fp4(): from fix_layer2_cap import DeviceFeature dev = DeviceFeature.detect("sm_110", "12.4") assert dev.can_run({"fp4_mma"}) def test_old_driver_falls_back(): from fix_layer2_cap import DeviceFeature dev = DeviceFeature.detect("sm_110", "12.0") # 驱动不支持 Blackwell 专属 assert not dev.can_run({"fp4_mma"}) kernels = {frozenset({"fp4_mma"}): "b", frozenset({"fp8_mma"}): "a"} assert dev.select_kernel(kernels) == "a" def test_no_kernel_raises(): from fix_layer2_cap import DeviceFeature dev = DeviceFeature.detect("sm_90", "12.0") try: dev.select_kernel({frozenset({"fp4_mma"}): "b"}) assert False except RuntimeError: pass

再加启动断言:

def assert_kernel_compatible(device: DeviceFeature, kernel_requires: set): assert device.can_run(kernel_requires), ( f"kernel 需要 {kernel_requires},但 {device.sm} 仅支持 {device.features}," "请重设 TORCH_CUDA_ARCH_LIST 并重编译,或回退到兼容 kernel" )

八、排查清单

sm_110 上illegal instruction崩溃,按序查:

  1. 确认真实设备与驱动nvidia-smi看 GPU 型号与驱动 CUDA 版本,确认是否为真 sm_110 且驱动足够新(≥12.4)。
  2. TORCH_CUDA_ARCH_LIST:安装时是否含 sm_110;若运行时环境不支持,重设为真实支持的架构并重编译。
  3. 看崩溃在哪个 kernel:定位是 FlashAttention / 量化 / 自定义 kernel,缩小到「用了哪类新指令」。
  4. 确认驱动支持 Blackwell 指令:fp4/fp8 新 mma、TMA 等新指令需要匹配驱动,版本不够就非法指令。
  5. 检查扩展.so来源:是否拷了别人 sm_110 编译的扩展,与本地驱动错配。
  6. 运行时能力探测:调用 Blackwell 专属 kernel 前先探测设备是否真支持,不支持回退 sm_90 路径。
  7. Triton/CUTLASS JIT 误判:确认 JIT 没把设备误当 sm_110 生成专属指令。
  8. 降低编译目标:把 kernel 编译目标降到 sm_90(若功能允许),避开 Blackwell 专属指令。
  9. 升级配套库:PyTorch / flash-attn / vLLM 新版对 sm_110 支持更完整。
  10. 最后才动 kernel 源码:优先在编译目标/能力探测/回退逻辑上解决,不要为兼容去改 kernel 指令。

九、小结

sm_110(Blackwell)上torch.AcceleratorError: CUDA error: an illegal instruction was encountered,根子是某个 CUDA kernel 的编译产物包含了当前「硬件+驱动+运行时」组合实际不支持的指令(常为 Blackwell 专属 fp4/fp8/TMA/新 mma 指令,或TORCH_CUDA_ARCH_LIST与运行时环境错配),GPU 执行到该指令即抛非法指令。修复三层:第一层重设TORCH_CUDA_ARCH_LIST按真实能力编译、运行时探测+回退兼容 kernel;第二层抽DeviceFeature明确设备支持的指令集,调用前校验并自动选 kernel;第三层用 pytest 把「sm_110+新驱动可跑 fp4」「旧驱动回退」「无 kernel 即报错」钉进 CI。核心认识——kernel 的指令集必须「运行时真实能力」说了算,而不是「编译期目标架构」说了算;任何 Blackwell 专属 kernel 在启动前都必须校验设备与驱动是否真支持,否则就把非法指令直接喂给了 GPU