Почему ваша multi-GPU система тормозит, хотя должна летать
Вы поставили две RTX 4090 в материнку на x570, запустили llama.cpp с тензорным параллелизмом и... получили прирост в 1.2 раза вместо 2. А то и вовсе одну карту видите, а вторая простаивает. Знакомая история? Поздравляю, вы столкнулись с асимметричными PCI-E lanes - тихой болезнью multi-GPU систем, которая съедает до 50% производительности.
В теории, две карты должны делить нагрузку поровну. На практике, если одна карта сидит на PCI-E x16, а вторая на PCI-E x4 (или того хуже, на x1), то обмен данными между GPU превращается в узкое горлышко. И llama.cpp, который пытается распределить вычисления, упирается в медленный линк.
Хуже всего то, что система может работать без ошибок. Просто медленно. И вы будете месяцами думать, что проблема в драйверах, модели или коде. А дело в трех строчках конфигурации.
Эта статья - не про разгон или покупку нового железа. Это про то, как за 15 минут бесплатно получить то, что вы уже купили. Если у вас multi-GPU система и llama.cpp, читайте дальше.
1Снимите показания: какой слот какой скорости
Первым делом - понять, как ваша материнская плата распределяет PCI-E lanes. Особенно это актуально для плат на AMD x570, где второй PCI-E x16 слот часто работает на x4. Но и на Intel бывают сюрпризы.
Откройте терминал и выполните:
lspci -vv | grep -A 10 "VGA compatible controller"Вы увидите список ваших GPU. Обратите внимание на строку LnkSta. Например:
LnkSta: Speed 16GT/s, Width x16
LnkSta: Speed 8GT/s, Width x4Первый GPU работает на x16, второй на x4. Вот и причина тормозов. Если у вас больше двух карт, проверьте каждую.
Но lspci показывает теоретическую ширину. А что в реальности, под нагрузкой? Для этого переходим к шагу 2.
2Замерьте пульс под нагрузкой с nvtop
Установите nvtop - это htop для GPU. Он покажет не только загрузку, но и скорость передачи данных по PCI-E.
sudo apt install nvtop # для Ubuntu/Debian
# или
sudo dnf install nvtop # для FedoraЗапустите nvtop в одном терминале, а в другом запустите llama.cpp с multi-GPU. Смотрите на столбец "PCIe" - там будет отображаться текущая скорость передачи данных.
Если одна карта показывает высокую скорость (например, несколько ГБ/с), а вторая близка к нулю - значит, она не используется. Или если обе показывают, но одна на низкой скорости, то это узкое место.
nvtop не всегда точно отображает скорость на некоторых системах. Если сомневаетесь, используйте nvidia-smi dmon для мониторинга. Но nvtop дает более наглядную картину.
Теперь, когда диагноз ясен, переходим к лечению.
3Поймите, как llama.cpp выбирает GPU
По умолчанию llama.cpp использует все доступные GPU, начиная с нулевого. Но он не знает, что один слот быстрее другого. Он просто распределяет слои модели по очереди.
Если у вас асимметричные линки, то GPU на медленном слоте будет тормозить всю цепочку. Потому что данные для следующего слоя должны пройти через узкое горлышко.
Решение? Вручную указать, какие GPU использовать. И здесь на помощь приходит CUDA_VISIBLE_DEVICES.
4Отрежьте медленный GPU или поменяйте порядок
Переменная окружения CUDA_VISIBLE_DEVICES определяет, какие GPU видит CUDA. Индексы в ней начинаются с 0.
Допустим, у вас три GPU: GPU0 на x16, GPU1 на x4, GPU2 на x16. Вы хотите использовать только быстрые GPU0 и GPU2. Тогда:
export CUDA_VISIBLE_DEVICES=0,2Теперь llama.cpp увидит только два GPU, оба быстрых. И будет распределять нагрузку между ними.
А если вы хотите использовать все GPU, но поменять порядок, чтобы быстрые шли первыми? Нельзя. CUDA_VISIBLE_DEVICES только скрывает GPU, но не меняет их порядок. Однако вы можете физически переставить карты в слоты или настроить BIOS.
Как это сделать в запуске llama.cpp:
CUDA_VISIBLE_DEVICES=0,2 ./main -m model.gguf -ngl 100 --tensor-parallel 2Обратите внимание на флаг --tensor-parallel 2 - он указывает, сколько GPU использовать для тензорного параллелизма. Должно совпадать с количеством GPU в CUDA_VISIBLE_DEVICES.
Не путайте --tensor-parallel с --split-mode или --main-gpu. В llama.cpp 2026 года эти флаги могут измениться. Всегда проверяйте ./main --help для актуальной версии.
Теперь переходим к тестированию.
5Замерьте скорость до и после
Без цифр все это просто слова. Запустите бенчмарк до и после настройки.
Сначала без CUDA_VISIBLE_DEVICES, со всеми GPU:
./main -m model.gguf -ngl 100 --tensor-parallel 2 -p "Привет" -n 512 -t 1Запишите tokens/s. Затем с CUDA_VISIBLE_DEVICES, только с быстрыми GPU:
CUDA_VISIBLE_DEVICES=0,2 ./main -m model.gguf -ngl 100 --tensor-parallel 2 -p "Привет" -n 512 -t 1Сравните. Если у вас была асимметрия, то прирост может быть от 30% до 100%. Потому что теперь обмен данными идет по быстрым линкам.
Что может пойти не так (и как это исправить)
1. BIOS режет линии. Некоторые материнские платы по умолчанию делят PCI-E lanes между несколькими устройствами. Зайдите в BIOS и проверьте настройки PCI-E. Установите режим Gen4 или Gen5 для скорости, и убедитесь, что слоты работают на максимальной ширине.
2. Порядок GPU меняется после перезагрузки. Это классика. Иногда система перенумеровывает GPU после обновления драйверов или изменения конфигурации. Всегда проверяйте nvidia-smi -L перед запуском.
3. Другие приложения используют GPU. Если у вас запущен X сервер на одном GPU, то он может занимать память и ресурсы. Используйте CUDA_VISIBLE_DEVICES и для других приложений, чтобы изолировать GPU для llama.cpp.
4. Нехватка мощности. Две карты на полной нагрузке могут выжать более 1000 ватт. Убедитесь, что блок питания справляется. Иначе будет троттлинг и падение производительности. Подробнее об оптимизации питания читайте в статье "Оптимизация AI-станции на Threadripper".
Частые вопросы
| Вопрос | Ответ |
|---|---|
| Можно ли использовать GPU на x4 для LLM? | Да, но он будет узким местом. Лучше использовать его для слоев, которые не требуют частого обмена данными, или для отдельной модели. |
| Почему nvidia-smi показывает другой порядок GPU? | Порядок в nvidia-smi определяется драйвером. CUDA_VISIBLE_DEVICES использует этот порядок. Если вы переставите карты в слотах, порядок может измениться. |
| А если у меня три карты, две на x16 и одна на x4? | Используйте CUDA_VISIBLE_DEVICES=0,1 для двух быстрых. Или, если модель большая, попробуйте использовать все три, но будьте готовы к падению скорости из-за x4. |
| Работает ли это с vLLM или другими инференс-движками? | Да, принцип тот же. vLLM также чувствителен к скорости PCI-E. Подробнее в статье "Как ускорить multi-GPU системы для LLM". |
Последний совет, который вам не дадут в мануалах
Иногда лучше вообще не использовать multi-GPU. Звучит еретически, но это так. Если у вас одна карта на x16 и вторая на x4, то запуск модели только на одной быстрой карте может быть быстрее, чем на двух с асимметрией. Потому что не будет накладных расходов на обмен данными.
Проверьте это. Запустите модель на одном GPU (CUDA_VISIBLE_DEVICES=0) и на двух (CUDA_VISIBLE_DEVICES=0,1). Если прирост меньше 30%, возможно, игра не стоит свеч. И лучше докупить еще одну карту и материнку с нормальными линками.
А если вы используете LLM для инференса, а не для тренировки, то подумайте о разделении одной GPU на несколько пользователей. Это может быть эффективнее, чем мучиться с multi-GPU.
И помните: железо должно работать на вас, а не вы на него. Настройте его и забудьте.