
Запуск llama.cpp на Nvidia Tesla K40 на Vulkan
Эта статья является продолжением эпопеи с выжиманием AI-соков из старой серверной видеокарты Nvidia Tesla K40, начатой в статьях «Локальный ИИ на Nvidia Tesla K40: сборка и настройка компьютера» и «Запуск llama.cpp на Nvidia Tesla K40».
В данном материале описываются результаты работы по сборке бэкенда llama.cpp для Nvidia Tesla K40 под Vulkan. Такой вариант интересен своей универсальностью. При этом не требуется модификация исходников llama.cpp, отвечающих за работу с CUDA, что значительно упрощает не только процесс сборки, но и уменьшает вероятность появления сбоев при работе в составе кластера.
Основной проблемой в этом случае является относительно устаревшая версия Vulkan 1.2.175, аппаратно поддерживаемая Nvidia Tesla K40m:

Сборка llama.cpp из исходного кода под Vulkan
Для сборки llama.cpp под Vulkanиз команды, использовавшейся ранее, нужно удалить все, что относится к CUDA.
Для чистоты эксперимента переименовываем папку с исходниками, модифицированными для работы с CUDA:
mv ~/llama.cpp ~/llama.cpp_cuda_backup
Затем заново скачиваем исходники llama.cpp и запускаем команду сборки без модификаций:
cd $HOME && git clone https://github.com/ggml-org/llama.cpp.git
cd llama.cpp && cmake -B build -DCMAKE_BUILD_TYPE=Release -DGGML_VULKAN=ON -DGGML_RPC=ON -DCMAKE_C_FLAGS="-O3 -march=native -pipe" -DCMAKE_CXX_FLAGS="-O3 -march=native -pipe" && cmake --build build -j$(nproc)
Получаем ошибку:
CMake Error at /usr/share/cmake-4.2/Modules/FindPackageHandleStandardArgs.cmake:290 (message):
Could NOT find Vulkan (missing: Vulkan_LIBRARY Vulkan_INCLUDE_DIR glslc)
(found version "")
Call Stack (most recent call first):
/usr/share/cmake-4.2/Modules/FindPackageHandleStandardArgs.cmake:654 (_FPHSA_FAILURE_MESSAGE)
/usr/share/cmake-4.2/Modules/FindVulkan.cmake:694 (find_package_handle_standard_args)
ggml/src/ggml-vulkan/CMakeLists.txt:9 (find_package)
-- Configuring incomplete, errors occurred!
Ставим официальный Vulkan-стек для разработчиков из репозиториев Ubuntu:
sudo apt install -y vulkan-tools libvulkan-dev vulkan-utility-libraries-dev glslc
запускаем сборку заново:
cd ~/llama.cpp && rm -rf /build && cmake -B build -DCMAKE_BUILD_TYPE=Release -DGGML_VULKAN=ON -DGGML_RPC=ON -DCMAKE_C_FLAGS="-O3 -march=native -pipe" -DCMAKE_CXX_FLAGS="-O3 -march=native -pipe" && cmake --build build -j$(nproc)
Получаем ошибку:
-- Found Vulkan: /usr/lib/x86_64-linux-gnu/libvulkan.so (found version "1.4.341") found components: glslc missing components: glslangValidator
CMake Error at ggml/src/ggml-vulkan/CMakeLists.txt:14 (find_package):
Could not find a package configuration file provided by "SPIRV-Headers" with any of the following names:
SPIRV-HeadersConfig.cmake
spirv-headers-config.cmake
Add the installation prefix of "SPIRV-Headers" to CMAKE_PREFIX_PATH or set "SPIRV-Headers_DIR" to a directory containing one of the above files. If "SPIRV-Headers" provides a separate development package or SDK, be sure it has been installed.

Ставим SPIRV-Headers и glslangValidator:
sudo apt install -y spirv-headers glslang-tools
и заново запускаем сборку, которая в этот раз идет успешно:

Логи сборки:
-- llama.cpp version: 0.1.0-dev
CMAKE_BUILD_TYPE=Release
-- Warning: ccache not found - consider installing it for faster compilation or disable this warning with GGML_CCACHE=OFF
-- CMAKE_SYSTEM_PROCESSOR: x86_64
-- GGML_SYSTEM_ARCH: x86
-- Including CPU backend
-- x86 detected
-- Adding CPU backend variant ggml-cpu: -march=native
-- Using RPC backend
-- RDMA transport enabled (auto-detected)
-- Including RPC backend
-- Vulkan found
-- GL_KHR_cooperative_matrix supported by glslc
-- GL_NV_cooperative_matrix2 supported by glslc
-- GL_NV_cooperative_matrix_decode_vector not supported by glslc
-- GL_EXT_integer_dot_product supported by glslc
-- GL_EXT_bfloat16 supported by glslc
-- GL_EXT_float_e2m1 not supported by glslc
-- GL_EXT_float_e4m3 supported by glslc
-- Including Vulkan backend
-- ggml version: 0.20.0
-- ggml commit: adb55e514
-- OpenSSL found: 3.5.5
-- Generating embedded license file for target: llama-app
-- Configuring done (1.2s)
-- Generating done (0.4s)
-- Build files have been written to: /home/intel51/llama.cpp/build
[ 0%] Performing build step for 'vulkan-shaders-gen'
[ 0%] Built target llama-common-base
[ 0%] Built target cpp-httplib
[ 1%] Built target ggml-base
[ 1%] Built target sha256
[ 1%] Built target sha1
[ 2%] Built target xxhash
[ 2%] Built target llama-ui-embed
[ 2%] Built target llama-llava-cli
[ 2%] Built target llama-gemma3-cli
[100%] Built target vulkan-shaders-gen
[ 2%] Built target llama-minicpmv-cli
[ 2%] Performing install step for 'vulkan-shaders-gen'
[ 2%] Built target llama-qwen2vl-cli
[ 2%] Building CXX object ggml/src/ggml-rpc/CMakeFiles/ggml-rpc.dir/ggml-rpc.cpp.o
-- Up-to-date: /home/intel51/llama.cpp/build/Release/./vulkan-shaders-gen
[ 4%] Built target ggml-cpu
[ 4%] Provisioning UI assets
[ 5%] Completed 'vulkan-shaders-gen'
[ 6%] Building CXX object ggml/src/ggml-rpc/CMakeFiles/ggml-rpc.dir/transport.cpp.o
-- UI: npm not found, skipping npm build
-- UI: downloading from b10446: https://huggingface.co/buckets/ggml-org/llama-ui/resolve/b10446/dist.tar.gz
[ 6%] Built target vulkan-shaders-gen
[ 40%] Built target ggml-vulkan
-- UI: download dist.tar.gz from b10446 failed: "HTTP response code said error"
-- UI: downloading from latest: https://huggingface.co/buckets/ggml-org/llama-ui/resolve/latest/dist.tar.gz
-- UI: archive verified and extracted
-- UI: HF download succeeded, stamp updated (latest)
-- UI: gzip compression applied (/home/intel51/llama.cpp/build/tools/ui/dist/_gzip)
[ 40%] Built target llama-ui-assets
[ 40%] Built target llama-ui
[ 40%] Linking CXX shared library ../../../bin/libggml-rpc.so
[ 40%] Built target ggml-rpc
[ 40%] Building CXX object ggml/src/CMakeFiles/ggml.dir/ggml-backend-dl.cpp.o
...
[100%] Linking CXX executable ../../bin/llama-cli
[100%] Built target llama-cli
[100%] Linking CXX executable ../bin/llama
[100%] Built target llama-app
[100%] Linking CXX executable ../bin/test-chat
[100%] Built target test-chat

Согласно логу:
- Vulkan found (found version «1.4.341») — Ubuntu Server успешно подхватила SDK и инициализировала архитектуру Vulkan 1.4;
- GL_KHR_cooperative_matrix supported by glslc — то есть компилятор шейдеров glslc подтвердил, что API Vulkan на чипе Kepler GK110B поддерживает расширение Cooperative Matrices (совместные матрицы) на уровне компиляции шейдеров. Как будет видно из логов rpc-сервера ниже, само аппаратное исполнение этих инструкций чипом не поддерживается — расширение доступно лишь номинально, а не как реальная замена отсутствующих у видеокарты тензорных ядер;
- Built target vulkan-shaders-gen — llama.cpp успешно скомпилировала все внутренние математические ядра нейросети в бинарный код шейдеров видеокарты;
- Built target ggml-vulkan — Vulkan-модуль полностью и успешно скомпилировалась без ошибок синтаксиса или совместимости;
Копируем готовые файлы из /llama.cpp/build/bin/ в рабочую папку llama_cpp:
rsync -av --delete --exclude='*.sh' $HOME/llama.cpp/build/bin/ $HOME/llama_cpp/
Приступаем к тестированию llama.cpp, собранного для Nvidia Tesla K40m под универсальную экосистему Vulkan.

Запуск llama.cpp, собранного для Vulkan на Nvidia Tesla K40
Для тестирования производим запуск rpc-ноды для работы в составе домашнего бюджетного AI-кластера командой:
CUDA_MODULE_LOADING=LAZY $HOME/llama_cpp/ggml-rpc-server -H 0.0.0.0 -p 50052
Так как на ноде в ходе написания предыдущих статей был настроен systemd-сервис автозапуска, перезапускаем его с новыми файлами llama.cpp:
sudo systemctl daemon-reload && sudo systemctl restart llama-rpc.service
В этот раз используем немного улучшенный вариант службы в сравнении с прошлой версией, описанной в статье Запуск llama.cpp на Nvidia Tesla K40, где llama.cpp запускалась на устаревшем пропатченом коде CUDA Compute Capability 3.5:
sudo nano /etc/systemd/system/llama-rpc.service
Вставляем текст:
[Unit]
Description=Llama.cpp RPC Server for Tesla K40 (Root Mode)
After=network.target
[Service]
Type=simple
User=root
Group=root
# --- ПЕРЕМЕННЫЕ ОКРУЖЕНИЯ КЛАСТЕРА ---
Environment=CUDA_MODULE_LOADING=LAZY
Environment=GGML_CUDA_ENABLE_HUGEPAGES=1
ExecStart=/home/intel51/llama_cpp/ggml-rpc-server -H 0.0.0.0 -p 50052
Restart=always
# --- БЕЗОПАСНАЯ ФИЛЬТРАЦИЯ ЛОГОВ ---
StandardOutput=null
StandardError=journal
[Install]
WantedBy=multi-user.target
Запуск RPC сервера по прежнему осуществляется от root чтобы получить доступ к большим страницам памяти. После сохранения файла обновляем диспетчер конфигураций systemd и перезапускаем его демон:
sudo systemctl daemon-reload && sudo systemctl restart llama-rpc.service
В случае необходимости, для остановки:
sudo systemctl stop llama-rpc.service
Проверка состояния:
sudo systemctl status llama-rpc.service
llama-rpc.service - Llama.cpp RPC Server for Tesla K40 (Root Mode)
Loaded: loaded (/etc/systemd/system/llama-rpc.service; enabled; preset: enabled)
Active: active (running) since Sat 2026-08-15 13:16:58 UTC; 5min ago
Invocation: 592fb9fef035435cb6fdd0ba8b058bfc
Main PID: 32167 (ggml-rpc-server)
Tasks: 1 (limit: 15136)
Memory: 338.2M (peak: 339.4M)
CPU: 370ms
CGroup: /system.slice/llama-rpc.service
└─32167 /home/intel51/llama_cpp/ggml-rpc-server -H 0.0.0.0 -p 50052
Aug 15 13:16:58 intel51 systemd[1]: Started llama-rpc.service - Llama.cpp RPC Server for Tesla K40 (Root Mode).
Aug 15 13:17:04 intel51 ggml-rpc-server[32167]: ggml_vulkan: Found 1 Vulkan devices:
Aug 15 13:17:04 intel51 ggml-rpc-server[32167]: ggml_vulkan: 0 = Tesla K40m (NVIDIA) | uma: 0 | fp16: 0 | bf16: 0 | fp4: 0 | warp size: 32 | shared memory: 49152 | int dot: 0 | matrix cores>
Aug 15 13:17:04 intel51 ggml-rpc-server[32167]: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Aug 15 13:17:04 intel51 ggml-rpc-server[32167]: WARNING: Host ('0.0.0.0') is != '127.0.0.1'
Aug 15 13:17:04 intel51 ggml-rpc-server[32167]: Never expose the RPC server to an open network!
Aug 15 13:17:04 intel51 ggml-rpc-server[32167]: This is an experimental feature and is not secure!
Aug 15 13:17:04 intel51 ggml-rpc-server[32167]: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Согласно логу видно:
- fp16: 0 | bf16: 0 | fp4: 0 — чип Kepler не умеет аппаратно вычислять форматы половинной точности (FP16/BF16) и новые ИИ-форматы (FP4) через Vulkan-шейдеры. Vulkan-бэкенд llama.cpp будет вынужден на лету программно эмулировать эти вычисления по поддерживаемому формату FP32, что уберет ошибки несовместимости типов, но создаст повышенную нагрузку на вычислительные блоки;
- uma: 0 (Unified Memory Architecture) — показывает наличие дискретной видеокарты со своей VRAM (12 ГБ);
- int dot: 0 | matrix cores — аппаратная поддержка целочисленного скалярного умножения (integer dot product) и матричных ядер (matrix cores / кооперативных матриц) на уровне Vulkan-рантайма для этой видеокарты сброшена в ноль. Лог CMake, который наблюдался при сборке (supported by glslc), означал, что компилятор шейдеров умеет собирать такой код, но сам чип выполнять его в рантайме Vulkan 1.4 не может. Математические вычисления будут производиться по классическому стандартному конвейеру.
На мастере запускаем скрипт с указанием локального адреса Vulkan rpc-ноды:
"$LLAMA_SERVER" -m "$MODEL_PATH" \
--host "$HOST" \
--port "$PORT" \
--rpc 192.168.2.51:50052 \
-ngl auto \
-t -1 \
--prio -1 \
--load-mode mlock \
-sm layer \
--perf \
--jinja \
--temp 0.6 \
--repeat-penalty 1.15 \
--cache-type-k q4_0 \
--cache-type-v q4_0 \
-c 8196 \
--flash-attn on

Бэкенд llama.cpp, собранный на Vulkan, работает немного медленнее, но зато нет никаких проблем при сборке, не нужно делать никаких патчей и постоянно ловить «косяки»:
cmn common_param: common_params_print_info: verbosity = 3 (adjust with the `-lv N` CLI arg)
0.10.093.069 W srv llama_server: -----------------
0.10.093.071 W srv llama_server: CORS is set to allow all origins ('*') and no API key is set
0.10.093.071 W srv llama_server: this can be a security risk (cross-origin attacks)
0.10.093.071 W srv llama_server: more info: https://github.com/ggml-org/llama.cpp/pull/25655
0.10.093.071 W srv llama_server: -----------------
0.10.094.397 I srv load_model: loading model '/home/intel35/AI_Models/DavidAU_Qwen3.6-27B-Fable-Fusion-711-Uncensored-Heretic-NM-DAU-NEO-MAX-MTP-GGUF/Qwen3.6-27B-Fable-Fus-711-UnHeretic-NM-DAU-NEO-MAX-NEO-MTP-Q4_K_M.gguf'
0.17.069.759 W model has unused tensor blk.64.attn_norm.weight (size = 20480 bytes) -- ignoring
0.17.069.785 W model has unused tensor blk.64.post_attention_norm.weight (size = 20480 bytes) -- ignoring
0.17.069.794 W model has unused tensor blk.64.attn_q.weight (size = 66846720 bytes) -- ignoring
0.17.069.797 W model has unused tensor blk.64.attn_k.weight (size = 5570560 bytes) -- ignoring
0.17.069.800 W model has unused tensor blk.64.attn_v.weight (size = 5570560 bytes) -- ignoring
0.17.069.811 W model has unused tensor blk.64.attn_output.weight (size = 33423360 bytes) -- ignoring
0.17.069.815 W model has unused tensor blk.64.attn_q_norm.weight (size = 1024 bytes) -- ignoring
0.17.069.819 W model has unused tensor blk.64.attn_k_norm.weight (size = 1024 bytes) -- ignoring
0.17.069.823 W model has unused tensor blk.64.ffn_gate.weight (size = 94699520 bytes) -- ignoring
0.17.069.826 W model has unused tensor blk.64.ffn_down.weight (size = 94699520 bytes) -- ignoring
0.17.069.829 W model has unused tensor blk.64.ffn_up.weight (size = 94699520 bytes) -- ignoring
0.17.069.833 W model has unused tensor blk.64.nextn.eh_proj.weight (size = 55705600 bytes) -- ignoring
0.17.069.837 W model has unused tensor blk.64.nextn.enorm.weight (size = 20480 bytes) -- ignoring
0.17.069.841 W model has unused tensor blk.64.nextn.hnorm.weight (size = 20480 bytes) -- ignoring
0.17.069.850 W model has unused tensor blk.64.nextn.shared_head_norm.weight (size = 20480 bytes) -- ignoring
4.22.932.410 W resolve_fused_ops: layer 0 is assigned to device CPU but fused Gated Delta Net (chunked) is assigned to device CUDA0 (usually due to missing support)
4.22.932.413 W resolve_fused_ops: fused Gated Delta Net (chunked) not supported, set to disabled
4.23.006.484 I cmn init: llama threadpool init, n_threads = 16
4.26.234.522 I srv load_model: initializing, n_slots = 4, n_ctx_slot = 8448, kv_unified = 'true'
4.26.238.497 I srv init: chat template supports preserving reasoning, consider enabling it via --reasoning-preserve
4.26.238.520 I srv llama_server: model loaded
4.26.238.522 I srv llama_server: listening on http://127.0.0.1:8080
4.26.238.522 W srv llama_server: NOTICE: server default port will be changed to :9931 in a future release
4.26.238.522 W srv llama_server: ref: https://github.com/ggml-org/llama.cpp/pull/26508
5.30.814.516 I slot get_availabl: id 3 | task -1 | selected slot by LRU, t_last = -1
5.30.814.593 I slot launch_slot_: id 3 | task 0 | processing task, is_child = 0
5.35.989.828 I slot print_timing: id 3 | task 0 | prompt processing, n_tokens = 121, progress = 0.19, t = 5.18 s / 23.38 tokens per second
5.51.160.121 I slot print_timing: id 3 | task 0 | prompt processing, n_tokens = 633, progress = 0.99, t = 20.35 s / 31.11 tokens per second
6.14.271.607 I slot print_timing: id 3 | task 0 | n_gen = 100, tg = 4.66 t/s, tg_3s = 4.71 t/s
...
15.13.088.071 I slot print_timing: id 3 | task 0 | prompt eval time = 22227.32 ms / 637 tokens ( 34.89 ms per token, 28.66 tokens per second)
15.13.088.074 I slot print_timing: id 3 | task 0 | eval time = 560046.10 ms / 2599 tokens ( 215.57 ms per token, 4.64 tokens per second)
15.13.088.074 I slot print_timing: id 3 | task 0 | total time = 582273.42 ms / 3236 tokens
15.13.088.075 I slot print_timing: id 3 | task 0 | graphs reused = 2588
15.13.088.145 I slot release: id 3 | task 0 | stop processing: n_tokens = 3235, truncated = 0

Как видно из лога, Vulkan-сборка уступает CUDA 16% скорости (см. статью Запуск llama.cpp на Nvidia Tesla K40).
Предупреждающая строка
W resolve_fused_ops: layer 0 is assigned to device CPU but fused Gated Delta Net (chunked) is assigned to device CUDA0...fused Gated Delta Net (chunked) not supported, set to disabled
свидетельствует о том, что:
- В сборке на Vulkan потеряны оптимизации Fused-операций. Современная архитектура Qwen использует сложные «склеенные» математические операции (fused Gated Delta Net), которые на бэкенде CUDA упаковывались в аппаратные инструкции видеокарты. Драйвер Vulkan 1.4 для Kepler эти склейки выполнять не может, расчеты этих микро-операций производятся в базовом, пошаговом режиме, что снижает итоговый TPS с 5.48 до 4.70 токенов в секунду.
- Двукратный завал на промпте при использовании Vulkan (около 30 t/s против 64 t/s) связан с потерей оптимизированных ассемблерных интринсиков памяти, работающих напрямую с регистрами чипа GK110b, использовавшихся в CUDA-бэкенде. Универсальные шейдеры Vulkan SPIR-V вынуждены гонять эти данные через общую абстракцию графического конвейера, из-за чего первичный сетевой залив контекста с мастера на 2.5G-ноду занял в два раза больше времени (20 секунд против 12).
Сеанс генерации занял почти 10 минут непрерывной работы, при этом сетевой кластер не выдал ни единой ошибки синхронизации, ни одного потерянного пакета по каналу связи 2.5G и ни разу не вылетел по нехватке памяти (OOM).- В ходе вычислений наблюдалась нулевая деградация скорости под нагрузкой (tg = 4.64 t/s). Этот результат означает, что 4-битное сжатие кэша в команде запуска (q4_0) полностью нивелировало сетевой затор. Турбина системы охлаждения обеспечивала надежное охлаждение, не сваливаясь в аппаратный и программный троттлинг (см. скрипт контроля температуры в предыдущей части).
Таблица со сравнительным анализом бэкендов llama.cpp с CUDA и Vulkan на Nvidia Tesla K40m:

Заключение
По мнению автора, Vulkan-бэкенд llama.cpp является более подходящим выбором для устаревшей видеокарты Nvidia Tesla K40 благодаря простоте настройки и надежной работе без сбоев и разрывов связи. Потеря 16% производительности в сравнении с CUDA-сборкой является разумной ценой за освобождение пользователя от мучений корректировки исходного кода под устаревшую архитектуру и борьбы с бесконечными ошибками…


