CUDA PTX vs SASS: toolchain и архитектура GPU решают, запустится ли модель

Симптом

Свежая модель meta-models/Muse-Glimmer-30B (релиз 9 августа 2026) падала при загрузке с крашем в rms_norm_f32_cuda, даже если llama.cpp был собран из master: поддержка архитектуры muse_glimmer уже была влита в PR #26841. Ошибка из лога:

CUDA error: the provided PTX was compiled with an unsupported toolchain.

При этом:

Контекст

Железо:

Обе архитектуры сверяются по официальной таблице compute capability NVIDIA.

Драйвер NVIDIA 595.84 соответствует ветке CUDA 13.2. Для CUDA 13.3 NVIDIA указывает драйвер 610.43.02, но внутри одной major-ветки действует minor version compatibility с ограничениями.

Софт:

Корневая причина

Проблем было три слоя. Каждый маскировал следующий.

1. CUDA toolkit 12.0 не подходил текущему host toolchain

При сборке с nvcc 12.0 системные хидеры stdlib.h и wchar.h содержали типы _Float32, _Float64 и _Float128, которые появились в текущей связке GCC 13 и glibc 2.39, но этот старый CUDA compiler их не понимал:

/usr/include/stdlib.h:141:8: error: '_Float32' does not name a type

Это не поддерживаемая NVIDIA комбинация: в матрице CUDA 12.0 нет GCC 13 и glibc 2.39.

Фикс - явно указать nvcc из /usr/local/cuda-13.3/bin/ и host compiler gcc-12:

cmake -DCMAKE_CUDA_HOST_COMPILER=/usr/bin/gcc-12 \
      -DCMAKE_C_COMPILER=/usr/bin/gcc-12 \
      -DCMAKE_CXX_COMPILER=/usr/bin/g++-12 ...

2. PDL и cudaFuncGetAttributes

После починки первого слоя модель грузилась, но падала в ggml_cuda_kernel_can_use_pdl, который вызывает cudaFuncGetAttributes для каждого ядра. На драйвере 13.2 с toolkit 13.3 этот вызов возвращал ошибку о неподдерживаемом PTX.

В использованном коммите llama.cpp GGML_CUDA_USE_PDL включался по версии CUDART. Флаг -DGGML_CUDA_NO_PDL читался CMake, но не отключал этот макрос в common.cuh. Помогло только ручное отключение GGML_CUDA_USE_PDL в исходнике.

Это согласуется с ограничением NVIDIA: PTX, собранный новым toolkit, не работает на старом драйвере в режиме minor compatibility.

3. CMAKE_CUDA_ARCHITECTURES не соответствовала железу

RTX 5060 Ti - sm_120, а сборка шла под 89 для Ada и 86 для Ampere. Нативного cubin для Blackwell в бинарнике не было, поэтому драйвер переходил к PTX JIT и упирался в несовместимую версию PTX toolchain.

Рабочий набор:

-DCMAKE_CUDA_ARCHITECTURES="120;86"

Без суффиксов CMake генерирует для перечисленных архитектур и real, и virtual code - это прямо описано в CUDA_ARCHITECTURES. После этого nvcc положил в бинарник нативный SASS для Blackwell и Ampere, и PTX JIT для этих карт больше не требовался.

Исправление

Рабочая команда сборки, с полной пересборкой после каждого изменения common.cuh:

export PATH=/usr/local/cuda-13.3/bin:$PATH
export CUDACXX=/usr/local/cuda-13.3/bin/nvcc

cmake -B build \
  -DBUILD_SHARED_LIBS=OFF \
  -DGGML_CUDA=ON \
  -DCMAKE_CUDA_ARCHITECTURES="120;86" \
  -DCMAKE_CUDA_HOST_COMPILER=/usr/bin/gcc-12 \
  -DCMAKE_C_COMPILER=/usr/bin/gcc-12 \
  -DCMAKE_CXX_COMPILER=/usr/bin/g++-12

cmake --build build --config Release -j 8 \
  --target llama-server llama-cli llama-mtmd-cli

Дополнительно в ggml/src/ggml-cuda/common.cuh строка перед #define GGML_CUDA_USE_PDL была заменена с #if на #if 0, чтобы отключить PDL.

Стартовый скрипт ~/llama.cpp/start-glimmer.sh:

export LD_LIBRARY_PATH=/usr/local/cuda-13.3/lib64:${LD_LIBRARY_PATH}

./build/bin/llama-server \
  -m ~/models/glimmer/Muse-Glimmer-30B-KQuant-17GB-Q4_K_M.gguf \
  --mmproj ~/models/glimmer/mmproj-Muse-Glimmer-30B-Q4_K_M.gguf \
  -ngl 99 -c 32768 \
  -a muse-glimmer-30b \
  --host 0.0.0.0 --port 8082 \
  --jinja --temp 1.0 --top-p 0.95 --top-k 64 -np 2

Результат

Выводы

  1. Проверяй compute capability каждой карты через nvidia-smi --query-gpu=compute_cap, а не по имени GPU. Для этой машины различие между sm_89 и sm_120 означало переход к PTX JIT и краш.

  2. nvcc из PATH может быть древнее реально установленного toolkit. Здесь /usr/bin/nvcc указывал на CUDA 12.0 из apt, а актуальный 13.3 жил в /usr/local/cuda-13.3/bin. Поэтому CUDACXX лучше задавать явно.

  3. В этом build graph изменение common.cuh не всегда приводило к пересборке всех зависимых объектов. После патча потребовались удаление build/ и чистая пересборка; иначе оставались старые .o.

  4. PDL доступен начиная с compute capability 9.0 и может перекрывать выполнение зависимых ядер. Но если crash происходит в ggml_cuda_kernel_can_use_pdl на несовместимой связке toolkit и driver, сначала надо проверить PTX compatibility, а затем временно отключить PDL.

  5. По данным карточки Muse Glimmer, KQuant-17GB теряет в среднем 1.0% на 15 бенчмарках, а KQuant-Dynamic - 0.2%. Это делает 16 GB файл практичным для 24 GB карты с запасом под KV-кэш.

  6. Когда появляется GPU с новой major compute capability, пересобирай под неё CUDA-бинарники. Нативные cubin несовместимы между major-архитектурами, а fallback на PTX JIT зависит от совместимости toolkit и драйвера.