Удвоение скорости Multi-GPU в llama.cpp: диагностика PCI-E и настройка | AiManual
AiManual Logo Ai / Manual.
17 Мар 2026 Гайд

Как удвоить скорость Multi-GPU в llama.cpp: диагностика асимметричных PCI-E lanes и настройка CUDA_VISIBLE_DEVICES

Узнайте, как диагностировать асимметричные PCI-E lanes и настроить CUDA_VISIBLE_DEVICES для удвоения скорости multi-GPU в llama.cpp. Готовые команды и пошаговое

Почему ваша 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. Вот и причина тормозов. Если у вас больше двух карт, проверьте каждую.

💡
Если вы видите Width x1 или x2 - это критично. Такой линк не потянет обмен тензорами между GPU. Подробнее о диагностике PCI-E читайте в статье "Как выжать +50% скорости из vLLM на 4x RTX 3090".

Но 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.

💡
Подробнее о том, как работает тензорный параллелизм в llama.cpp, читайте в отдельной статье.

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%. Потому что теперь обмен данными идет по быстрым линкам.

💡
Для точного бенчмарка используйте больше токенов (-n 2048) и отключайте вывод (-s 0). А еще лучше - используйте скрипт бенчмарка из репозитория llama.cpp.

Что может пойти не так (и как это исправить)

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.

И помните: железо должно работать на вас, а не вы на него. Настройте его и забудьте.

Подписаться на канал