CUDA против Vulkan в llama.cpp на RTX 5080: пять граблей и 21% скорости
После разлочки мощности видеокарты локальная Qwen3.8-27B давала 31 токен в секунду. Потом unsloth перевыпустила тот же квант по новой методике, я перешёл на свежий вариант — стало 35. И я считал это потолком.
Потом прикинул по пропускной способности памяти: карта отдавала 46% возможного. То есть половина простаивала.
Очевидный подозреваемый — Vulkan вместо CUDA. Я это уже пробовал, в те самые двое суток тупиков перед разлочкой мощности. Разницы не было, вопрос закрыл. Оказалось, зря.
Грабля первая: компилятор не знал мою карту
Тот замер был кривой. У каждой видеокарты NVIDIA есть номер версии набора инструкций — compute capability, его пишут как compute_90 или sm_90. Компилятор надо явно просить собрать код под нужную версию, а о версиях новее себя он попросту не знает.
Системный nvcc 12.4 умеет максимум compute_90 — это Hopper, серверные H100. А RTX 5080 Laptop — compute_120, потребительский Blackwell. Сборка работала через промежуточный PTX с трансляцией на ходу, без родных ядер. Мы с Claude Code мерили запасной путь и приняли его за CUDA.
Грабля вторая: установщик, который молча ждал Enter
Официальных сборок llama.cpp с CUDA для Linux нет вовсе, только для Windows. Значит собирать самому. Скачал установщик NVIDIA на 5 ГБ — и он молча повис, открыв крошечное окно X11 с просьбой нажать Enter. Нужен флаг --nox11.
А позже выяснилось, что установщик и не нужен: те же компоненты лежат отдельными архивами, и хватает 0.86 ГБ вместо пяти гигабайт.
Грабля третья: CUDA не собирается с новой glibc
CUDA 12.8 не собирается с glibc 2.43. Новая glibc добавила функции cospi, sinpi, rsqrt, а заголовки CUDA объявляют их сами, с другой спецификацией исключений. Правил руками (ну, руками Claude Code) шесть объявлений — этот же способ, как потом выяснилось, описан в документации llama.cpp.
Грабля четвёртая, самая опасная: замер, который врал
Собрал, замерил: CUDA даёт +20% генерации. Уже собирался переключать рабочие скрипты. Померил на настоящем промпте в 64 тысячи токенов — CUDA оказалась медленнее на 45%.
За день я поймал этот разворот трижды: спекулятивное декодирование через MTP давало +25% на коротком запросе и −12% на длинном, догадка по n-граммам +400% и −34%, черновая модель DFlash2 +29% и −43%. Любой короткий замер на этой задаче меняет выводы на реальной длине.
Грабля пятая: вывод, который мне не понравился
Вывод был такой: у CUDA нет быстрого пути для квантованного KV-кэша, остаёмся на Vulkan. Вывод мне не понравился, попросил копнуть ещё раз.
Оказалось: путь есть, ядро собирается по умолчанию. Медленно оно из-за конкретной ошибки, на которую уже есть отчёт — причём поданный на той же архитектуре и том же ядре Linux, что у меня, — и открытое исправление.
Что получилось
Собрал заново: CUDA 13.3, ветка с исправлением, родная архитектура sm_120.
| Было | Стало | |
|---|---|---|
| Префилл на 64к токенов | 555 tok/s | 768 tok/s |
| Шаг агента | 149 с | 123 с |
| Стенд из 12 задач | 12 мин | 9 мин |
Минус 21% времени на реальном шаге. Контекст при этом не пострадал — те же 196 тысяч токенов.
Потолок оказался подвесным
Главный вывод у меня получился такой: потолок каждый раз оказывается подвесным. Сверху всегда есть ещё немного места, надо только постучать.
Несколько дней назад — 20.8 токена в секунду, и это был предел: карта работала на 80 ваттах из паспортных 175. Разлочил мощность — 31. Unsloth перевыпустила тот же квант по новой методике, с калибровкой под агентное программирование — та же модель, просто пересобранная, — перешёл на него, стало 35.
А CUDA прибавила не там, где я ждал. Генерация на коротком запросе выросла с 35 до 44 токенов в секунду, но на рабочем промпте в 64 тысячи токенов прибавка скромная: с 27.8 до 29.5. Зато префилл — обработка самого промпта перед ответом — ускорился с 555 до 768 токенов в секунду, почти на 40%.
И для кодинга это ценнее, чем прибавка к генерации. Агент читает много, а пишет мало: на 64 тысячи токенов промпта приходится около тысячи токенов ответа, три четверти времени уходит на чтение. Отсюда и минус 21% на шаге целиком.
Путь от 20.8 до 44 токенов в секунду и плюс 38% к обработке промпта — за несколько дней. На живых задачах шаг агента укладывается в две минуты вместо двух с половиной. И вот с этим уже можно работать, а не ждать у экрана.