AI и DIY,  Hardware,  Статьи

Локальный ИИ на Nvidia Tesla K40: сборка и настройка компьютера

Высокие цены на видеокарты и память ограничивают возможности многих желающих локально запускать средние и большие модели ИИ. В связи с этим, при ограниченном бюджете, вызывает интерес возможность использования старых серверных видеокарт.
В данной статье рассматриваются возможности инференса и генерации изображений на старой видеокарте Nvidia Tesla K40M с 12GB VRAM, которая у автора около 10 лет провалялась в дальнем ящике… Для этого использовалась материнская плата ASRock H81 Pro BTC R2.0 с BIOS P1.40 (опция Above 4G Decoding активирована по умолчанию, PCIE1 Link Speed выставлен на максимум для этой платы — в Gen2) + CPU Intel i5-4570R (4C/4T), 16 ГБ RAM DDR3 1600MHz, HDD 500GB и сетевая плата Realtek RTL8125B (2.5GBit). Установка последней обусловлена необходимостью обеспечить более быстрый инференс при работе в кластере. На встроенной Realtek RTL8111GR все будет работать, с просадкой по скорости в случае использования Tesla K40 для расширения совокупной памяти AI-кластера.

При сборке стенда пришлось преодолеть ряд трудностей, основными из которых были:

в итоге было принято решение остановиться на новейшей версии ubuntu-server (ядро 7.0.x), так как она устанавливается за несколько минут, в сети есть готовые работающие патчи под эту систему;

  • установка устаревшей версии Cuda Toolkit 11.8 на новую систему со штатным gcc 15.2;
  • сборка llama.cpp и других AI-приложений под устаревшую Nvidia архитектуру SM3.5, решение проблем совместиомсти Си-библиотек 2026 года с CUDA 2022 года;
  • другие мелкие проблемы и неудобства, которые решались в ходе настройки «AI-бомж сборки». Например, попытка оптимизировать задержки сети и памяти под инференс через агрессивные параметры sysctl.conf ломала инициализацию видеокарт. Отключение watchdog, перераспределение шины PCIe (pci=assign-busses,realloc) в связке со старым проприетарным драйвером NVIDIA 470 приводило к потере физического доступа к адресам Tesla K40 и Kernel Panic (Oops).

Кроме того, попутно решалась задача по «доведению до ума» китайского райзера x16 с тоненькими проводами питания (приводят к просадкам напряжения при нагрузке) и отсутствием экранировки (негативное влияние помех и пульсаций).

Визуальное сравнение оригинального и слегка доработонного райзера PCI-E x16, который вполне достойно работал по стандарту GEN2, максимально возможному на легендарной материнской плате ASRock H81 Pro BTC R2.0:

На noname-райзер были припаяны неустановленные китайским производителем сглаживающие конденсаторы (2 шт) по линии +12В, а также сделано кустарная экранировка с помощью фольги (правда, она не была подключена к GND, что должно значительно увеличить эффективность экрана):

Бомж-AI-нода на Tesla K40M, сделанная из г…. и палок деревянных деталей и компонентов, валявшихся на полке со времен майнинга:

Для обеспечения тишины при работе Dual Ball турбины GDB1232 (12V, 1A) использовался понижающий DC_DC преобразователь с настройкой частоты вращения потенциометром до достижения максимальной тишины.

Установка и настройка операционной системы под Nvidia Tesla K40, llama.cpp, sd.cpp и comfyui

В этом разделе изложены сокращенная последовательность работы, команды по установке и настройке компьютера для запуска в максимально производительном серверном (headless) режиме.

Работа с приложениями искусственного интеллекта на видеокарте Nvidia поколения Kepler (Tesla K40M, sm_35) в описывается во второй части.

Главным секретом бюджетной AI-ноды является повсеместное использование самодельных и б.у.-компонентов:

Установка базовой ubuntu-server производится без особых проблем в штатном режиме, с флешки, которую можно подготовить в balena-etcher.

Установить драйвера Nvidia для архитектуры Kepler, пропатченные под современное ядро linux можно, используя плоды трудов уважаемого joanbm на портале github (репозиторий /joanbm/nvidia-470xx-linux-mainline):

Команды для полуавтоматической установки драйвера Nvidia с нужными патчами:

git clone https://github.com/joanbm/nvidia-470xx-linux-mainline    
cd nvidia-470xx-linux-mainline
./install
    

Установку нужно производить с выключенной графикой, в конце процесса должно появиться сообщение об успехе.

При проблемах с загрузкой в linux может понадобиться LiveCD-дистрибутив и работа в chroot. Для этого сначала смотрим названия загрузочного и root-дисков командой:

  fdisk -l

Затем выполняем команды с идентификатором диска из предыдущего шага:

mkdir -p /mnt

mount /dev/sda2 /mnt

cp /etc/resolv.conf /mnt/etc/resolv.conf

mount --bind /dev /mnt/dev

mount --bind /proc /mnt/proc

mount --bind /sys /mnt/sys

mount -t devpts devpts /dev/pts

chroot /mnt

Выход из chroot:

  exit
  umount /mnt/dev /mnt/proc /mnt/sys /mnt

Маленькие, но важные настройки системы, помогающие добиться максимального быстродействия

Очистка от мусора:

  sudo apt-get clean && sudo apt-get autoremove --purge -y && sudo journalctl --vacuum-time=2d && sudo rm -rf /var/crash/* /var/tmp/* /tmp/* ~/.cache/* 2>/dev/null

Обновление и очистка:

  sudo apt update && sudo apt -y upgrade && sudo apt -y dist-upgrade && sudo apt -y autoremove

Установка нужных компонентов:

  sudo apt install autoconf automake btop build-essential cmake cron curl extra-cmake-modules fastfetch gcc git inxi landscape-common libcurl4-openssl-dev libelf-dev libgmp-dev libhwloc-dev libjansson-dev libmicrohttpd-dev  libncurses5-dev libnuma-dev libpci-dev libssl-dev libtool libuv1-dev make nano nvtop ocl-icd-opencl-dev pkg-config wget screen zlib1g-dev wget linux-headers-generic libglvnd-dev

Настраиваем ZRAM как системную службу:

  sudo nano /etc/systemd/system/zram-swap.service

Вставляем туда конфигурационный скрипт zram:

[Unit]

Description=Кастомный Ultra-Low Latency zRAM Swap (24GB)

After=local-fs.target

[Service]

Type=oneshot

RemainAfterExit=yes

# 1. Загрузка модуля ядра

ExecStartPre=/sbin/modprobe zram num_devices=1

# 2. Настройка алгоритма и размера в байтах

ExecStart=/bin/sh -c 'echo zstd > /sys/block/zram0/comp_algorithm'

ExecStart=/bin/sh -c 'echo 25769803776 > /sys/block/zram0/disksize'

# 3. Форматирование и активация свопа с приоритетом 32767

ExecStart=/sbin/mkswap /dev/zram0

ExecStart=/sbin/swapon -p 32767 /dev/zram0

# Корректное отключение при выключении ПК (защита от зависаний)

ExecStop=/sbin/swapoff /dev/zram0

ExecStop=/bin/sh -c 'echo 1 > /sys/block/zram0/reset'

[Install]

WantedBy=multi-user.target

Актвируем:

  sudo systemctl enable --now zram-swap.service

Проверка работоспособности:

  systemctl status zram-swap.service

Просмотр информации о ZRAM и свопе:

  zramctl
  swapon --show

Пример настроек grub:

  sudo nano /etc/default/grub
  GRUB_CMDLINE_LINUX_DEFAULT="preempt=voluntary transparent_hugepage=always nowatchdog nmi_watchdog=0 audit=0 msr.allow_writes=on mitigations=off intel_iommu=on iommu=pt pci=assign-busses,realloc,pcie_bus_perf,nocrs,earlydump ibt=off fsck.mode=force fsck.repair=yes rcupdate.rcu_expedited=1 i915.enable_gvt=0 nomodeset"
  sudo update-grub

На ubuntu-server для уменьшения потребления оперативки, разгрузки процессора и системы ввода-вывода можно (на свой страх и риск) отключить лишние навороты:

sudo apt remove --purge avahi-daemon colord thunderbird ppp ufw whoopsie modemmanager timidity timidity-daemon  cups cups-browsed unattended-upgrades wpasupplicant rsyslog ufw whoopsie crash packagekit plymouth   -y

При очистке нужно внимтаельно следить за тем, чтобы не снести зависимые важные модули, включая ядро. Например, автор успешно снес ядрос системы, пытаясь подчистить вроде бы ненужный на сервере snap.

ubuntu-server версии 26.04 тянет как зависимости бесполезные apparmor apport-core-dump-handler kexec-tools snapd unattended-upgrades apport kdump-tools lvm2 thin-provisioning-tools.

Их нельзя удалять, но можно отключить:

sudo systemctl disable --now apparmor apport apport-forwarder kexec-tools snapd snapd.socket snapd.seeded unattended-upgrades kdump-tools-dump lvm2-monitor lvm2-lvmpollddm-event

плюс, понимая последствия, можно дополнительно отключить:

sudo systemctl disable --now cloud-init cloud-init-local cloud-config cloud-final multipathd
sudo systemctl mask cloud-init cloud-init-local cloud-config cloud-final multipathd
sudo systemctl stop systemd-networkd-wait-online.service && sudo systemctl mask systemd-networkd-wait-online.service
sudo systemctl stop systemd-journald.service && systemctl mask systemd-journald.service

Благодаря сносу бесполезного мусора и отключения ненужных программ можно снизить потребление оперативной памяти до нескольких сотен мегабайт:

На плате ASRock H81 Pro BTC R2.0 с BIOS P1.40 автору не удалось полностью аппаратно отключить встроенную графику, поэтому из физических 16GB было доступно только 15, из которых «голая» система кушала около 600-700MB.

Для уменьшения времени ожидания завершения/запуска процессов (оно может длиться от нескольких минут до бесконечности) можно снизить его до 5 секунд (это особенно полезно при первоначальной настройке, когда еще не устранены все «косяки»):

sudo nano /etc/systemd/system.conf
DefaultTimeoutStartSec=5s
DefaultTimeoutStopSec=5s

Применение:

sudo systemctl daemon-reload

Также пришлось дополнительно установить acpid (чтобы корректно передавать материнской плате аппаратную команду ACPI на перезагрузку или выключение):

sudo apt install acpid -y


sudo systemctl enable --now acpid

а также заблеклистить нтегрированную видеокарту (и, для освобождения ресурсов, встроенную сетевую), иначе сервер нормально не выключался и не перезагружался, происходило зависание на строке Reached target Reboot (Reached target Power-Off).

Включенная интегрированная видеокарта на этапе загрузки приводила к ошибке BUG: kernel NULL pointer dereference, вызванной конфликтом модуля встроенной графики Intel Haswell — i915 (GPU Iris Pro 5200) и аппаратной виртуализацией ввода-вывода (intel_iommu=on в grub) при «дележе» адресов памяти встроенного видеоядра (Scratch setup failed). При перезагрузке драйвер Intel (i915) пытался освободить ресурсы виртуализации графики (intel_gvt). В этот же момент выгружался патченый драйвер NVIDIA 470. Происходил конфликт NULL pointer dereference в памяти ядра, намертво вешавший процессор до физического ресета кнопки.

Для решения проблемы настраиваем Blacklist встроенной графики Intel:

sudo nano /etc/modprobe.d/blacklist-intel-gpu.conf

вставляем туда текст:

blacklist i915
blacklist intel_gvt
options i915 modeset=0

Также в конфигурацию GRUB нужно добавит флаг i915.enable_gvt=0:

sudo nano /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="... i915.enable_gvt=0 nomodeset"
sudo update-grub
sudo update-initramfs -u -k all

Спасением от жесткого ребута, вредного для итак изношенного HDD, стало использование магической комбинации Alt+PrtScn+REISUB.

Установка драйверов для сетевого адаптера r8125 (штатный работает медленнее):

sudo apt update
sudo apt install r8125-dkms -y

Настройка сети на компьютере под свой роутер с указанием статического локального адреса в файле 00-installer-config.yaml:

sudo nano /etc/netplan/00-installer-config.yaml

добавляем в файл текст:

           network:
version: 2
renderer: networkd
ethernets:
enp2s0:
dhcp4: no
addresses:
- 192.168.2.51/24
routes:
- to: default
via: 192.168.2.1
nameservers:
addresses:
- 1.1.1.1
- 1.0.0.1
enp3s0:
dhcp4: no
optional: true

В BIOS отключить встроенную сетевую карту у автора не получилось, поэтому пришлось ее «забанить» программно:

sudo nano /etc/modprobe.d/blacklist-r8169.conf

прописываем:

blacklist r8169

Неотключенная служба systemd-networkd-wait-online.service по умолчанию ждет подключения целых две минуты. Это время пришлось сократить:

sudo systemctl edit systemd-networkd-wait-online.service
           [Service]
ExecStart=
ExecStart=/lib/systemd/systemd-networkd-wait-online --any --timeout=3


Кроме того, чтобы драйвер NVIDIA не вешал ядро при выключении, был создан файл правил выгрузки модулей:

sudo nano /etc/modprobe.d/nvidia-unload.conf
           options nvidia-current NVreg_PreserveVideoMemoryAllocations=1
options nvidia Nvreg_Mobile=0

Применение:

sudo update-initramfs -u -k all

Полезные команды для просмотра режима работы видеокарты, конфигурации системы, драйверов и прочего

Проверка ошибок:

sudo dmesg -l err,crit,alert,emerg

Просмотр информации о сетевых адаптерах:

lspci -v -d 10de: -d 10ec

Настройки сетевой карты (нужно ввести свое значение вместо enp2s0):

  sudo ethtool enp2s0

Проверочные команды для видеокарты Nvidia

Проверка физического присутствия видеокарты Nvidia на шине PCI-E:

  lspci -k | grep -A 3 -i nvidia

Поиск ошибок нехватки ресурсов в логе ядра (dmesg):

  sudo dmesg | grep -E -i "bar|alloc|pci.*bridge|resource|disabled"

Проверка текущей карты BAR-памяти (/proc/iomem)

  sudo grep -i nvidia /proc/iomem

Детальный просмотр информации о видеокарте:

  lspci -v -s $(lspci | grep -i nvidia | awk '{print $1}')

Другие проверочные команды:

  nvidia-smi

  sudo lspci -vvv -s 01:00.0 | grep -A 10 -i "DevSta:"

Аппаратный счетчик ошибок AER (Advanced Error Reporting):

  sudo dmesg | grep -E -i "aer|pcieport|poison|bus error|correctable|fatal"

Проверка нехватки адресных ресурсов шины (BAR Allocation):

  sudo dmesg | grep -E -i "pci.*bridge|resource conflict|failed to assign|disabled"

Настройка температурного режима и разгона видеокарты Tesla K40

Пример скрипта термоконтроля (tesla-thermal-control.sh:

В нем выставляется лимит троттлинга на 72°C (критическая температура чипа GK110b составляет 85°C), с возвратом к полноценной работе при 65°C.

  sudo nano /usr/local/bin/tesla-thermal.sh
#!/bin/bash

GPU_ID=0

GPU_LIMIT=72 # Температура паники (включаем троттлинг)

GPU_HYST=65 # Температура возврата (карта остыла)

GPU_LOW_CLOCK="324,324" # Сброс в энергосбережение

GPU_HIGH_CLOCK="3004,1006" # Boost-режим

GPU_THROTTLED=0

echo "================================================================"

echo "Запущен термоконтроль для Tesla K40m (GPU $GPU_ID)..."

echo "Лимит: ${GPU_LIMIT}°C | Гистерезис: ${GPU_HYST}°C"

echo "================================================================"

while true; do

# Запрашиваем температуру чипа GK110b

TEMP=$(nvidia-smi -i $GPU_ID --query-gpu=temperature.gpu --format=csv,noheader,nounits 2>/dev/null)

if [ -z "$TEMP" ]; then

sleep 2

continue

fi

# Условие 1: Карта перегрелась

if [ "$TEMP" -ge "$GPU_LIMIT" ] && [ "$GPU_THROTTLED" -eq 0 ]; then

# Сбрасываем частоты памяти и чипа на абсолютный минимум

nvidia-smi -i $GPU_ID -ac $GPU_LOW_CLOCK > /dev/null 2>&1

GPU_THROTTLED=1

echo "[$(date +%T)] ⚠️ ВНИМАНИЕ: Температура ${TEMP}°C >= ${GPU_LIMIT}°C!"

echo " Сброс частот в режим охлаждения: $GPU_LOW_CLOCK"

# Условие 2: Карта успешно остыла

elif [ "$TEMP" -le "$GPU_HYST" ] && [ "$GPU_THROTTLED" -eq 1 ]; then

# Возвращаем карту в максимальный режим вычислений P0

nvidia-smi -i $GPU_ID -ac $GPU_HIGH_CLOCK > /dev/null 2>&1

GPU_THROTTLED=0

echo "[$(date +%T)] ✅ СТАБИЛИЗАЦИЯ: Карта остыла до ${TEMP}°C."

echo " Возврат частот на максимум: $GPU_HIGH_CLOCK"

fi

sleep 2

done

Делаем файл исполняемым:

  sudo chmod +x /usr/local/bin/tesla-thermal.sh

Системная служба для автоматического запуска троттлинга:

  sudo nano /etc/systemd/system/tesla-thermal.service
[Unit]

Description=Tesla K40 Thermal Control Daemon

After=zram-swap.service

[Service]

Type=simple

Restart=always

RestartSec=2

ExecStart=/usr/local/bin/tesla-thermal.sh

[Install]

WantedBy=multi-user.target

Активируем и запускаем службу:

  sudo systemctl daemon-reload
  sudo systemctl enable --now tesla-thermal.service

Проверить работу демона и его логи можно стандартной командой:

  sudo journalctl -u tesla-thermal.service -f

Контроль за состоянием видеокарты во время инференса с помощью nvtop:

Настройка NCCL, решение конфликтов компиляторов GCC 15/CUDA 11.8, сборка llama.cpp, sd.cpp описываются в отдельных статьях.

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

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