MAATRIX / Блог / Проброс GPU в виртуальную машину: полный разбор

Проброс GPU в виртуальную машину: полный разбор

MAATRIX

Виртуальная машина по умолчанию видит не физическую видеокарту, а её эмулированный или виртуализованный образ — этого достаточно для рабочего стола, но не для обучения модели или рендера, где каждый лишний слой между приложением и железом съедает производительность. Проброс GPU (GPU passthrough) решает эту проблему буквально — отдаёт виртуальной машине физическое устройство напрямую. Разберём, как это работает на уровне IOMMU и vfio-pci, что реально нужно настроить и где эта настройка ломается на практике.

Почему обычная виртуализация не подходит для GPU-нагрузки

Когда виртуальной машине не пробрасывают устройство напрямую, гипервизор эмулирует его сам или подставляет паравиртуализированный драйвер. Для сетевой карты или диска это работает приемлемо: разница в накладных расходах заметна, но не критична для большинства задач. Для видеокарты в GPU-интенсивном сценарии — обучении нейросетей, инференсе больших моделей, рендере — та же схема означает, что каждый вызов к GPU проходит через дополнительный программный слой трансляции команд, а не напрямую к драйверу производителя.

На практике это выражается в трёх вещах:

  • Эмулированный видеоадаптер (стандартный VGA/QXL в QEMU) вообще не даёт доступа к вычислительным блокам физической карты — это просто видеовыход для консоли, без CUDA, без ROCm, без реального ускорения.
  • Виртуализация GPU уровня vGPU/MIG (когда одна физическая карта делится на несколько виртуальных срезов) даёт доступ к вычислениям, но урезанную долю ресурсов карты — и требует поддержки со стороны самой карты и лицензии на технологию у производителя.
  • Проброс (passthrough) убирает прослойку целиком: гостевая ОС получает устройство на шине PCIe так, будто оно физически подключено именно к ней, ставит родной драйвер производителя и работает с картой напрямую.

Разница между вторым и третьим вариантом — это ровно разница между «разделить карту между несколькими арендаторами, потеряв часть производительности каждому» и «отдать всю карту одной ВМ, не деля ни с кем». Для обучения модели или тяжёлого рендера вариант почти всегда один — passthrough. Подробнее о том, где именно виртуализация теряет производительность, разобрано в статье про потери производительности при виртуализации.

IOMMU: механизм, который делает проброс безопасным

Ключевой механизм, без которого проброс устройства в ВМ вообще не может считаться безопасным — IOMMU, Input-Output Memory Management Unit. Это блок в процессоре и чипсете, который управляет прямым доступом устройств к оперативной памяти (DMA — Direct Memory Access).

Без IOMMU устройство на шине PCIe теоретически может обратиться к любому адресу физической памяти — в том числе к памяти хоста или других виртуальных машин. Это не проблема, пока устройство под управлением ОС хоста. Но как только его передают напрямую гостевой системе, это становится дырой в изоляции: без ограничения DMA-доступа нестабильная гостевая ОС могла бы читать и писать в память соседних ВМ и хоста через переданное устройство.

IOMMU решает эту задачу, создавая для устройства отдельное адресное пространство и транслируя обращения к памяти через таблицы трансляции — аналогично тому, как MMU процессора транслирует виртуальные адреса в физические. У Intel эта функция называется VT-d (Virtualization Technology for Directed I/O), у AMD — AMD-Vi (часть AMD-V).

Что нужно проверить и включить, прежде чем переходить к остальным шагам:

  1. Поддержка процессором. Не все модели, особенно бюджетные и мобильные линейки, реализуют VT-d/AMD-Vi — наличие обычной виртуализации (VT-x/AMD-V) не гарантирует наличия этой отдельной функции.
  2. Поддержка материнской платой и её прошивкой. Чипсет и BIOS/UEFI должны реализовывать функцию — серверные платы и платы с чипсетами для энтузиастов (не самые бюджетные модели) обычно справляются лучше настольных бюджетных решений.
  3. Явное включение в BIOS/UEFI. Пункт обычно называется «Intel VT-d», «IOMMU» или «AMD-Vi», иногда спрятан в подразделе Advanced/Chipset Configuration. По умолчанию чаще всего выключен даже там, где поддерживается.
  4. Включение поддержки в ядре хоста. Для Linux — параметры загрузки intel_iommu=on (Intel) или amd_iommu=on (AMD), плюс iommu=pt для режима passthrough остальных устройств. Прописываются в загрузчике, например в /etc/default/grub:
GRUB_CMDLINE_LINUX="intel_iommu=on iommu=pt"

После изменения — update-grub (Debian/Ubuntu) или grub2-mkconfig (RHEL-семейство) и перезагрузка. Проверить, что IOMMU действительно активен, можно командой:

dmesg | grep -i -e DMAR -e IOMMU

Если в выводе есть строки вида IOMMU enabled — механизм включён на уровне ядра. Если строк нет — либо не включено в BIOS, либо процессор/плата не поддерживают функцию, и дальше двигаться некуда без замены железа.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть ИИ на сервере

Изоляция GPU от хоста через vfio-pci

Даже с включённым IOMMU видеокарта по умолчанию продолжает управляться штатным драйвером хоста (nouveau, amdgpu, или проприетарный драйвер производителя). Прежде чем отдать устройство в ВМ, его нужно «отвязать» от этого драйвера и передать под управление vfio-pci — специального драйвера ядра Linux, который не работает с устройством сам, а резервирует его для передачи через VFIO framework в гостевую систему.

Практическая последовательность на Linux-хосте с QEMU/KVM:

  1. Определить PCI-адрес видеокарты и связанных с ней функций (обычно карта — это одна PCI-функция для видео и отдельная для звука HDMI):
lspci -nn | grep -i nvidia

Вывод покажет что-то вроде 01:00.0 VGA compatible controller [0300]: NVIDIA Corporation ... [10de:2504] и 01:00.1 Audio device [0403]: NVIDIA Corporation ... [10de:228e]. Пара чисел в квадратных скобках в конце строки — это vendor:device ID, они понадобятся дальше.

  1. Указать ядру, что для этих ID нужно использовать vfio-pci вместо штатного драйвера — через параметр загрузки или конфиг модуля:
options vfio-pci ids=10de:2504,10de:228e

(строка в /etc/modprobe.d/vfio.conf, значения ID — свои, из вывода lspci).

  1. Убедиться, что vfio-pci загружается раньше штатных видеодрайверов — иначе они успеют захватить устройство первыми. На практике для этого либо добавляют vfio-модули в initramfs раньше остальных, либо явно чернят (blacklist) штатный драйвер для этой карты.
  1. После перезагрузки проверить, что устройство действительно висит на vfio-pci:
lspci -nnk -s 01:00.0

В строке Kernel driver in use: должно значиться vfio-pci, а не nouveau/amdgpu/nvidia.

Только после этого шага видеокарта готова к передаче в ВМ — через libvirt/virt-manager добавлением PCI-устройства в XML-описание домена, либо опцией -device vfio-pci,host=01:00.0 в командной строке QEMU.

IOMMU-группы: главное практическое ограничение

Здесь начинается часть, которая ломает планы чаще всего. IOMMU не работает с устройствами по одному — оно группирует устройства шины PCIe в IOMMU-группы на основе топологии самой шины (какие устройства сидят за одним и тем же мостом PCIe). Пробросить в ВМ можно только целую группу целиком — не отдельное устройство внутри неё.

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

for d in /sys/kernel/iommu_groups/*/devices/*; do
  n=${d#*/iommu_groups/*}; n=${n%%/*}
  echo "IOMMU Group ${n}: $(lspci -nns ${d##*/})"
done

Идеальный случай — видеокарта (и её аудио-функция) находятся в отдельной группе, где больше ничего нет: тогда пробрасывается ровно она. Проблемный случай — в одной группе с картой оказываются другие устройства: например, контроллер USB, к которому подключена клавиатура сервера, или слот с картой, которую нужно оставить хосту. Тогда просто так пробросить только видеокарту нельзя — придётся отдавать всю группу целиком либо разбираться с изоляцией на уровне железа.

Что реально влияет на качество разбиения на группы:

  • Реализация IOMMU в чипсете и BIOS материнской платы. Разброс между производителями и даже моделями одной линейки существенный: одни платы аккуратно разносят слоты PCIe по отдельным группам, другие сваливают половину слотов в одну группу без возможности разделить программно.
  • Физический слот, в который установлена карта. На части плат один и тот же чипсет даёт разное разбиение групп в зависимости от слота PCIe — иногда помогает просто переставить карту.
  • ACS override patch — обходной путь (патч ядра или параметр загрузки), который заставляет ядро считать устройства изолированными даже когда чипсет этого физически не гарантирует. Работает, но снижает реальную изоляцию внутри группы — компромисс, приемлемый для домашней лаборатории и куда менее приемлемый там, где на одном хосте чужие данные или несколько независимых арендаторов.

Практический вывод: перед покупкой железа под самостоятельную настройку passthrough стоит заранее проверить, как конкретная модель платы бьёт слоты на IOMMU-группы — эта информация известна в сообществах вокруг проброса GPU и сильно разнится даже в пределах одного чипсета.

Потребительские видеокарты: дополнительное препятствие

Отдельная головная боль — проброс карт потребительского сегмента (GeForce, часть Radeon), которые не позиционируются производителем как «серверные» или предназначенные для виртуализации. Здесь возможна ситуация, когда IOMMU настроен идеально, устройство привязано к vfio-pci и передано в ВМ корректно, а драйвер производителя внутри гостевой системы всё равно отказывается инициализировать карту или падает с ошибкой.

Причина — некоторые версии драйверов проверяют признаки того, что они выполняются в виртуализированном окружении (характерные строки в CPUID, специфичный для гипервизора vendor ID), и намеренно блокируют работу для карт, не относящихся к сертифицированной для виртуализации линейке. Это не ограничение самого IOMMU/vfio, а решение на уровне драйвера производителя.

Обходной путь задокументирован в сообществе passthrough-энтузиастов: гипервизору можно указать скрыть от гостевой ОС признаки виртуализации — например, в libvirt добавлением в XML-описание домена блока <hidden state='on'/> внутри секции <kvm>, а также подменой vendor ID гипервизора на нейтральное значение. Такие обходы рабочие и массово используются, но:

  • они не гарантированы производителем и могут перестать работать после обновления драйвера — это по сути гонка между обходом сообщества и очередной версией драйвера;
  • часть настроек (например, точный набор скрываемых CPUID-флагов) зависит от конкретной модели карты и версии драйвера, единого рецепта «на все случаи» нет;
  • на серверных картах, изначально сертифицированных производителем под виртуализацию, этой проблемы просто не возникает — драйвер не проверяет признаки гипервизора или разрешает работу явно.

Это одна из причин, по которой связка «потребительская карта + самостоятельный passthrough» — рабочий, но не всегда предсказуемый путь: часть времени в такой настройке уходит не на IOMMU и не на vfio, а именно на обход поведения драйвера, специально для этого не предназначенного.

Эксклюзивность: один GPU — одна виртуальная машина

Стоит проговорить прямо следствие, которое иногда упускают на старте: после того как видеокарта проброшена в конкретную ВМ, она эксклюзивно занята этой машиной. Хост к ней доступа не имеет (драйвер хоста отвязан в пользу vfio-pci), другие виртуальные машины — тоже. Если нужно переключить карту на другую ВМ, требуется остановить текущую машину, освободить устройство и передать его следующей — параллельного использования одной физической карты несколькими системами passthrough не даёт в принципе (это как раз задача vGPU/MIG, а не passthrough).

Практически это значит: если на хосте одна карта и запущены несколько ВМ, которым нужен GPU, passthrough решает задачу только для одной из них одновременно; если нужен доступ к GPU на самом хосте (например, nvidia-smi или задачи вне ВМ), после передачи карты в vfio-pci хост эту возможность теряет, пока карта не возвращена; для нескольких ВМ с независимым доступом к GPU нужно либо несколько физических карт (каждая в своей IOMMU-группе), либо решение уровня vGPU на серверных картах, поддерживающих разделение.

Это не недостаток технологии, а её прямое следствие: passthrough существует именно для того, чтобы отдать все ресурсы карты одной задаче без компромиссов, и монопольность — часть этой сделки, а не побочный эффект.

Своё железо или готовый сервер с настроенным пробросом

Собрав всю картину вместе — IOMMU в BIOS, привязка к vfio-pci, состав IOMMU-групп, возможные обходы для потребительских карт — стоит честно оценить, где эта работа оправдана, а где нет.

Настройка с нуля на непроверенном железе имеет смысл, если у вас уже есть конкретная плата и процессор и вы готовы проверить методом проб разбиение на IOMMU-группы, задача разовая или экспериментальная, и важен полный контроль над конфигурацией гипервизора на своём железе.

Аренда сервера с уже настроенным пробросом оправдана, если нужен предсказуемый результат к сроку, а не эксперимент с неизвестным железом, нет времени разбираться с IOMMU-группами и обходами для конкретной карты, и задача практическая (инференс, обучение, рендер), а не изучение passthrough как такового.

Для второго случая логика простая: провайдер уже прошёл весь путь — подобрал железо с чистым разбиением IOMMU-групп, настроил vfio-pci, проверил совместимость драйверов — и отдаёт готовую ВМ с рабочим GPU. Если конечная цель — результат работы модели, а не сама конфигурация гипервизора, экономия времени обычно перевешивает. Про то, когда выгоднее держать свою карту, а когда арендовать готовую, разобрано в статье своя видеокарта против аренды GPU; более широкий обзор самой технологии — в статье GPU passthrough: основы.

Если нужен уже готовый инференс-сервер с пробросом, сделанным на стороне провайдера, для практических задач с LLM подойдёт разбор конфигураций в статье GPU-сервер в Великобритании для инференса LLM.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Развернуть ИИ на сервере

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли настроить GPU passthrough без включения IOMMU?

Нет. IOMMU (VT-d/AMD-Vi) — обязательное условие безопасной передачи DMA-доступа устройству в гостевую систему.

Почему видеокарта после привязки к vfio-pci пропадает из вывода в хостовой ОС?

Так и должно быть — vfio-pci резервирует устройство для передачи в ВМ. Чтобы вернуть карту хосту, её отвязывают от vfio-pci и возвращают штатному драйверу.

Что делать, если видеокарта оказалась в одной IOMMU-группе с нужным хосту устройством?

Переставить карту в другой слот PCIe (иногда меняет разбиение групп), проверить обновление BIOS платы, либо применить ACS override patch, понимая, что это снижает изоляцию между устройствами группы.

Обязательно ли использовать серверную видеокарту для passthrough?

Нет, потребительские карты пробрасываются тоже, но с вероятностью столкнуться с проверкой признаков виртуализации в драйвере — потребуется обход (скрытие CPUID-признаков гипервизора). Серверные карты этой проблемы обычно не имеют.

Можно ли одновременно использовать одну видеокарту в хосте и в ВМ?

Нет. После передачи в vfio-pci карта эксклюзивно занята той ВМ, куда пробрасывается, пока не будет возвращена.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →