Обзоры

Запуск 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-сборкой является разумной ценой за освобождение пользователя от мучений корректировки исходного кода под устаревшую архитектуру и борьбы с бесконечными ошибками…

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *