Конфликты драйверов GPU на сервере с ускорителями
Как находить конфликты драйверов GPU, сверять CUDA и ROCm, восстанавливать модуль после обновления ядра и безопасно изолировать ускорители.

Конфликты драйверов GPU редко начинаются с честного сообщения «драйвер и библиотека несовместимы». Чаще одна задача видит четыре ускорителя, другая два, nvidia-smi работает на узле, но контейнер возвращает CUDA driver version is insufficient for CUDA runtime version, а после перезагрузки исчезают все карты. Эти симптомы похожи, хотя возникают на разных уровнях.
Я разбираю такой отказ снизу вверх: PCIe, модуль ядра, пользовательские библиотеки, контейнер, вычислительный фреймворк, планировщик. Если начать с переустановки CUDA или ROCm, можно случайно замаскировать причину и оставить сервер в состоянии, которое сломается при следующем обновлении. На многоускорительном узле особенно важно сначала определить границу отказа, а уже потом менять пакеты.
Одинаковая ошибка не означает одинаковую поломку
Первый осмотр должен ответить на один вопрос: на каком слое ускоритель перестал быть доступен. Не запускайте сразу обучающую задачу на восемь карт. Соберите короткий снимок состояния, который можно сравнить с исправным узлом или предыдущей загрузкой.
uname -r
lspci -Dnn | grep -Ei 'VGA|3D|Display'
lsmod | grep -E 'nvidia|amdgpu'
modinfo nvidia 2>/dev/null | grep -E '^(version|vermagic):'
nvidia-smi -L 2>&1
nvidia-smi -q | grep -E 'Product Name|GPU UUID|Bus Id'
Для AMD замените последние две команды на rocminfo и rocm-smi. Запишите также dmesg -T, но не выгружайте весь журнал в чат: сначала отберите строки с NVRM, Xid, amdgpu, kfd, IOMMU, AER и pcie.
journalctl -k -b | grep -Ei 'NVRM|Xid|amdgpu|kfd|IOMMU|AER|pcie'
Интерпретация проста. Если lspci не видит карту, CUDA и контейнеры пока ни при чем. Ищите питание, посадку карты, кабель райзера, настройки BIOS, распределение PCIe-линий или отказ самого устройства. Если PCIe видит все карты, но модуль ядра не загружен, проверяйте сборку модуля, Secure Boot и журналы ядра. Если служебная утилита перечисляет карты, а приложение падает, переходите к пользовательским библиотекам и окружению задачи.
Есть неприятный промежуточный случай: nvidia-smi показывает часть карт, а lspci показывает все. Тогда сравните PCI-адреса, а не номера GPU. Номер GPU 0 меняется после перестановки устройств, обновления прошивки или иного порядка обнаружения. PCI-адрес и UUID лучше подходят для расследования.
Проверьте, кто уже держит устройство. Зависший процесс может пережить остановку задачи, сохранить контекст и помешать сбросу карты или выгрузке модуля:
fuser -v /dev/nvidia* 2>/dev/null
lsof /dev/nvidia* 2>/dev/null
nvidia-smi pmon -c 1
Не завершайте найденный PID вслепую. Сопоставьте его с заданием планировщика, контейнером и владельцем. Демон мониторинга, MPS-сервер или служба фабрики тоже открывают устройства, хотя пользовательская задача уже закончилась. Принудительное завершение системной службы способно распространить отказ на исправные карты.
Сохраните снимок до любых изменений. Минимальный набор включает время, имя узла, загруженное ядро, список PCIe-устройств, UUID, ветку драйвера, активные процессы и выбранные строки журнала. После переустановки многие следы исчезают, и администратор остается с рассказом «вчера не работало», который нельзя проверить.
Версия в nvidia-smi не равна установленной CUDA
Строка CUDA Version в nvidia-smi показывает максимальную версию CUDA, которую поддерживает загруженный драйвер, а не версию Toolkit внутри системы или контейнера. NVIDIA прямо поясняет это в CUDA Toolkit, Driver, and Architecture Matrix. Поэтому вывод CUDA Version: 12.4 не доказывает, что /usr/local/cuda содержит Toolkit 12.4.
Проверьте четыре разных объекта отдельно:
- версию загруженного модуля ядра через
cat /proc/driver/nvidia/version; - версию пользовательской
libcuda.so, которую разрешает динамический загрузчик; - версию CUDA Runtime или ROCm в образе задачи;
- версию и сборку фреймворка, например PyTorch.
cat /proc/driver/nvidia/version
ldconfig -p | grep 'libcuda\.so'
readlink -f /usr/lib/x86_64-linux-gnu/libcuda.so.1
nvcc -V 2>/dev/null || true
python3 -c 'import torch; print(torch.__version__, torch.version.cuda); print(torch.cuda.is_available())'
Команда nvcc -V отвечает только за Toolkit, найденный в PATH. Она ничего не говорит о библиотеке, которую реально загрузил процесс. Для спорного процесса используйте LD_DEBUG=libs на коротком тесте или проверьте отображение библиотек через /proc/<PID>/maps. Так быстро обнаруживается старая libcuda.so в нестандартном каталоге, которую приложение подхватило раньше системной.
Документ NVIDIA Minor Version Compatibility разрешает некоторым приложениям работать с более новым Toolkit в пределах одной основной ветки при достаточно новом драйвере. Но это не общая индульгенция. Код, который полагается на новую возможность драйвера, может вернуть cudaErrorCallRequiresNewerDriver, а PTX-код на старом драйвере имеет отдельные ограничения. У cuDNN, cuBLAS, NCCL и фреймворка также есть собственные зависимости.
Для ROCm нельзя переносить правила CUDA по аналогии. AMD публикует Compatibility Matrix с проверенными сочетаниями ОС, ядра, архитектуры GPU, ROCm и фреймворков. Сверяйте конкретную ветку, а не рассуждайте, что разница в один минорный релиз «наверняка допустима». Совместимость должна быть записанным сочетанием, а не надеждой администратора.
На узле, где одновременно установлены разные версии Toolkit, символическая ссылка /usr/local/cuda часто вводит в заблуждение. Один сервис получает PATH из системного профиля, другой из unit-файла, третий из контейнера. Запишите окружение именно падающего процесса и сравните абсолютные пути. Менять общую ссылку ради одного приложения опасно: вы можете исправить интерактивный тест и сломать фоновую службу.
Смешивание ускорителей NVIDIA и AMD на одном хосте требует еще большей дисциплины. Модули ядра могут сосуществовать, но задачи должны получать правильные device nodes, runtime и переменные окружения. Ошибка, при которой ROCm-задаче передают только /dev/dri/render*, но не /dev/kfd, выглядит как проблема библиотеки. Ошибка, при которой CUDA-контейнеру открывают все устройства обоих производителей, становится проблемой изоляции. Проверяйте каждый стек отдельно, а затем совместный режим планировщика.
Версии библиотек из имени пакета тоже недостаточно. Образ может содержать дубликат в каталоге приложения, виртуальном окружении или wheel-пакете. Для одного короткого запуска LD_DEBUG=libs показывает поиск и выбранный файл, хотя вывод получается шумным. Отберите строки по libcuda, libcudart, libnvidia-ml, libamdhip64, libhsa-runtime и сохраните их рядом с версией образа.
Обновление ядра ломает модуль раньше библиотек
После обновления ядра сервер часто загружается успешно, но драйвер GPU остается собранным для предыдущего ядра. Это отдельный отказ от несовместимости CUDA Runtime. Установка другого Toolkit его не исправит.
Сначала сопоставьте текущее ядро, vermagic модуля и состояние DKMS:
uname -r
modinfo -F vermagic nvidia 2>/dev/null
dkms status
find /lib/modules/$(uname -r) -type f -name 'nvidia*.ko*' -o -name 'amdgpu*.ko*'
Первые компоненты строки vermagic должны соответствовать загруженному ядру. Если файла модуля для него нет, посмотрите журнал сборки DKMS. Типовые причины просты: отсутствуют заголовки именно для текущего ядра, компилятор не подходит, модуль не собирается с новым API ядра либо пакет драйвера установлен смешанными способами.
NVIDIA Driver Installation Guide требует заголовки и пакеты разработки, соответствующие результату uname -r, не просто самые новые заголовки в репозитории. В руководстве также отмечено, что после обновления ядра DKMS иногда приходится запустить вручную и затем перезагрузить узел. Это хороший совет, но ручная пересборка имеет смысл только после чтения журнала: повтор одной и той же неудачной команды ничего не лечит.
Secure Boot создает другой вариант той же картины. Модуль собрался, лежит на диске, но ядро не принимает неподписанный файл. Ищите Lockdown, Required key not available или отказ проверки подписи в журнале. Решение состоит в корректной подписи и регистрации ключа по правилам вашей ОС. Отключать Secure Boot как постоянный обходной путь на сервере не стоит.
Не смешивайте пакетный драйвер дистрибутива с установщиком .run. NVIDIA рекомендует пакетный метод для поддерживаемых дистрибутивов, потому что он учитывает зависимости, ветки и обновления ядра. Когда часть файлов принадлежит пакетному менеджеру, а часть записана независимым установщиком, версия модуля и версия пользовательских библиотек легко расходятся после обычного обновления.
Еще один частый сценарий выглядит так. Обновление устанавливает новое ядро и новый пакет драйвера, но сервер продолжает работать без перезагрузки со старым ядром и старым модулем в памяти. На диске пользовательские библиотеки уже новые. Часть долгоживущих процессов держит старые отображения библиотек, а новые процессы загружают новые файлы. До перезагрузки узел имеет сразу несколько временных состояний, которые невозможно честно описать одной версией пакета.
В таком состоянии не пытайтесь обновить модуль «на ходу» на занятом вычислительном узле. Сначала выведите сервер из расписания, завершите задачи и проверьте, какие процессы держат устройства. Выгрузка nvidia, nvidia_uvm или amdgpu при активных клиентах обычно не проходит, а принудительные приемы рискуют повредить работу соседних задач. Контролируемая перезагрузка после успешной сборки понятнее и воспроизводимее.
Если нужно быстро вернуть сервис, загрузитесь в заранее сохраненное рабочее ядро вместе с подходящим модулем. Не подменяйте только один файл .ko из старого каталога: модуль состоит из нескольких частей, зависит от конфигурации ядра и должен соответствовать пользовательским компонентам своей ветки. После восстановления сохраните неудачный журнал DKMS для разбора, иначе следующая автоматическая установка повторит отказ.
Одна пропавшая карта указывает на топологию
Если после загрузки работают семь карт из восьми, глобальная переустановка драйвера обычно слишком груба. Сначала сравните путь исправной и пропавшей карты от PCIe до служебной утилиты.
lspci -tv
lspci -s 0000:65:00.0 -vv
nvidia-smi topo -m
nvidia-smi -q -i GPU-UUID
В lspci -vv проверьте состояние и скорость линии, сообщения AER, назначенный драйвер и IOMMU-группу. В журнале ищите Xid или ошибки amdgpu. Один и тот же Xid нельзя толковать без контекста: важны карта, момент, повторяемость и действие непосредственно перед ошибкой. Например, ошибка появляется только при обмене между конкретной парой карт, но одиночный тест каждой карты проходит. Тогда версия CUDA менее подозрительна, чем путь P2P, PCIe-коммутатор, NVLink или служба управления фабрикой.
На системах с NVSwitch версия Fabric Manager должна соответствовать ветке драйвера. Приложение может видеть устройства, но не поднимать коллективный обмен, если эта служба не запущена или не совпадает по версии. Проверьте состояние службы и журнал до перезапуска задач.
Смешанные поколения ускорителей добавляют ограничение по архитектуре. Новый драйвер обычно запускает код, собранный старым Toolkit, но конкретный Toolkit или фреймворк может уже не поддерживать старую compute capability. Обратная ситуация тоже встречается: образ собран без кода для новой архитектуры и пытается JIT-компиляцию PTX, которую старый драйвер не понимает. Зафиксируйте модели, compute capability и список архитектур, использованных при сборке приложения.
Для коллективных операций сначала отделите локальную видимость от межкарточной связи. Небольшое вычисление на каждой карте доказывает, что процесс может создать контекст. Оно не проверяет NCCL, RCCL, P2P, общую память или путь через сетевой адаптер. Если одиночные тесты проходят, запустите обмен только на одной паре, затем меняйте пары. Так проблемная ветка топологии находится быстрее, чем в общем тесте на всех картах.
Сравнивайте карту ошибки с физическим расположением. UUID связывает журнал приложения с устройством, PCI-адрес связывает устройство со слотом, а схема сервера связывает слот с процессором, PCIe-коммутатором и питанием. Без этих трех связей фраза «падает GPU 3» почти бесполезна. После перезагрузки этим номером может называться другая карта.
Ошибки AER требуют отдельного внимания. Исправляемые сообщения могут сопровождать деградацию линии, а неисправимые способны удалить устройство из шины. Не стирайте их переустановкой программного набора. Сохраните счетчики, проверьте посадку, райзер, питание и прошивку платформы, затем повторите нагрузку. Если ошибка следует за картой при перестановке, это один вывод; если остается за слотом, это другой.
Сброс отдельной карты допустим только после остановки всех процессов, которые держат устройство, и только если платформа поддерживает такой сброс. Документация ABI ядра Linux говорит, что файл reset в sysfs существует лишь для устройств с индивидуальным сбросом функции. Запись 1 туда затрагивает реальное устройство. На производственном сервере сначала освободите задачу в планировщике и оцените влияние на соседние функции; самовольный remove или rescan может задеть дочерние устройства.
Изоляция по номеру карты ненадежна
CUDA_VISIBLE_DEVICES=2,3 ограничивает видимость карт для процесса, но это соглашение пользовательского уровня, а не защита от процесса с доступом к /dev/nvidia*. Переменная также перенумеровывает видимые устройства: физическая карта 2 становится cuda:0 внутри процесса. Из-за этого журналы приложения и журналы узла могут говорить о разных «нулевых» картах.
CUDA Programming Guide подтверждает, что CUDA_VISIBLE_DEVICES управляет и видимостью, и порядком перечисления. В производственном планировщике задавайте устройства по UUID, затем сохраняйте соответствие UUID, PCI-адреса и локального номера в метаданных задачи.
export CUDA_DEVICE_ORDER=PCI_BUS_ID
export CUDA_VISIBLE_DEVICES=GPU-2f1...,GPU-a84...
nvidia-smi -q | grep -E 'GPU UUID|Bus Id'
Индексы удобны для ручного теста на неизменном узле. Для автоматического распределения они слабы: порядок может измениться после перезагрузки. UUID переживает такое изменение, хотя замена физической карты, конечно, дает новый UUID.
Изоляция должна происходить на двух уровнях. Планировщик выделяет конкретные ускорители задаче, а контейнерный runtime пропускает внутрь только соответствующие устройства и библиотеки. Права cgroup и device nodes должны подтверждать то же решение. Если пользователь может запустить привилегированный контейнер или самостоятельно подключить все /dev/nvidia*, переменная окружения уже ничего не гарантирует.
MIG меняет единицу распределения: планировщик должен назначать UUID экземпляра MIG, а не только родительской карты. MPS решает другую задачу, совместное выполнение процессов, и сам по себе не создает границу безопасности между недоверенными арендаторами. Эти механизмы часто складывают в одну коробку «изоляции», а потом получают утечку ресурсов или непредсказуемую конкуренцию за память.
Планировщик должен быть единственным источником назначения. Если оператор вручную задает CUDA_VISIBLE_DEVICES, а Kubernetes device plugin или Slurm уже выделил карту, появляются два независимых отображения. Приложение может получить локальный номер, не совпадающий с ожиданием обвязки, а журнал сохранит неверный UUID. Передавайте назначение один раз и формируйте переменные из него автоматически.
Для долгих задач сохраняйте назначение в журнале запуска: идентификатор задания, имя узла, UUID или MIG UUID, PCI-адрес, локальный ordinal и digest контейнера. Тогда сообщение cuda:0 failed можно вернуть к физическому устройству даже через несколько дней. Без этой записи расследование после перезагрузки превращается в догадку.
Изоляция памяти также не равна очистке данных. Перед передачей карты другой доверительной зоне следуйте возможностям и процедурам конкретной платформы, включая сброс экземпляра или устройства, если производитель это поддерживает. Обычное завершение процесса освобождает его контекст, но политика для разных арендаторов должна опираться на документированный механизм, а не на предположение.
После назначения выполните отрицательную проверку. Процесс должен видеть выделенные устройства и не видеть остальные. Такой тест полезнее, чем проверка только положительного пути:
python3 - <<'PY'
import os, torch
print("visible_env=", os.getenv("CUDA_VISIBLE_DEVICES"))
print("device_count=", torch.cuda.device_count())
for i in range(torch.cuda.device_count()):
print(i, torch.cuda.get_device_name(i))
PY
Контейнер не приносит с собой модуль ядра
Контейнер обычно содержит CUDA Runtime, вычислительные библиотеки и приложение, но использует модуль GPU-драйвера хоста. Контейнерный runtime подключает нужные пользовательские части драйвера и устройства. Поэтому исправный образ не компенсирует слишком старый или не загруженный модуль на узле.
Проверяйте один и тот же тест в трех местах: на хосте, в минимальном заведомо согласованном образе и в образе приложения. Если тест падает уже на хосте, контейнер не виноват. Если минимальный образ работает, а образ приложения нет, сравнивайте LD_LIBRARY_PATH, установленные библиотеки и сборку фреймворка. Если оба контейнера падают, хотя хостовая утилита видит карты, проверяйте конфигурацию runtime, права устройств и версию его компонентов.
Особенно опасно копировать libcuda.so в образ «для надежности». Эта библиотека связана с драйвером хоста и обычно должна приходить через механизм контейнерного runtime. Старая копия в /usr/local/lib может получить приоритет и вызвать несовпадение API, хотя системная библиотека исправна.
Диагностический снимок внутри контейнера должен показывать не только версии пакетов:
env | grep -E 'CUDA|NVIDIA|ROCR|HIP|LD_LIBRARY_PATH'
ls -l /dev/nvidia* /dev/kfd /dev/dri/render* 2>/dev/null
ldconfig -p | grep -E 'libcuda|libcudart|libamdhip64'
python3 -c 'import torch; print(torch.__version__); print(torch.cuda.device_count())'
Не монтируйте весь каталог библиотек хоста поверх каталога образа. Такой обходной путь может починить один бинарник и сломать другой. Выберите поддерживаемую пару «ветка драйвера хоста плюс версия runtime образа», зафиксируйте digest образа и повторите короткий вычислительный тест.
Контейнер с флагом привилегированного режима плох для диагностики изоляции. Если он работает, а обычный контейнер нет, вы доказали только недостаток прав. Сравните список подключенных устройств, cgroup и настройки GPU runtime. Затем добавьте точное недостающее разрешение, а не оставляйте полный доступ как постоянное исправление.
Проверьте и узловой компонент, который готовит контейнер. В Kubernetes это обычно device plugin и GPU container runtime, в Slurm это настройки GRES и запуск контейнеров. Их состояние может устареть после замены карты или изменения MIG. Перезапуск компонента оправдан после сверки конфигурации, но сначала сохраните его журнал и фактический список UUID.
Образ лучше проверять по digest, а не по изменяемому тегу. Два узла могут получить разные слои под одним тегом и показать разные версии библиотек. Запись digest рядом с результатом теста устраняет эту неопределенность и позволяет повторить именно тот запуск, который отказал.
Восстановление должно идти от узла к задаче
Правильный порядок восстановления уменьшает число одновременно меняющихся переменных. Сначала остановите прием новых задач и сохраните диагностику, затем возвращайте слои по одному.
- Освободите узел в планировщике, завершите GPU-процессы штатно и запишите UUID, PCI-адреса, версии, журнал ядра и последнюю рабочую конфигурацию.
- Добейтесь, чтобы PCIe видел ожидаемое число устройств. Если не видит, исправляйте платформу, питание или посадку карты до работы с пакетами.
- Восстановите модуль для текущего ядра: точные заголовки, одна схема установки, подпись Secure Boot, успешный DKMS и чистая загрузка.
- Проверьте служебную утилиту, каждую карту отдельно и топологию. На фабричных системах проверьте соответствующую службу управления.
- Согласуйте пользовательские библиотеки и минимальный контейнер с матрицей производителя, затем верните фреймворк и многокарточный тест.
Откат ядра полезен как средство быстрого восстановления, если предыдущее ядро и модуль сохранены и политика безопасности допускает откат. Он одновременно дает сильный диагностический сигнал: на прежнем ядре узел работает, на новом нет. Но оставлять сервер на случайном старом ядре без зарегистрированного исключения и плана исправления нельзя.
Полная переустановка драйвера оправдана, когда пакетная база смешана или повреждена. Перед ней зафиксируйте установленные пакеты и источники файлов. Не удаляйте все, что содержит строку cuda: Toolkit приложения может быть исправен и не связан с отказом модуля. Удаляйте конкретную конфликтующую схему установки, затем ставьте выбранную ветку одним методом.
После ремонта одиночного nvidia-smi недостаточно. Нужны четыре проверки: короткое вычисление на каждой карте, выделение и освобождение памяти, обмен между разрешенными парами и запуск через тот же планировщик с тем же типом контейнера, что использует производство. После этого перезагрузите узел в контролируемое окно и повторите тест. Многие «починенные» конфликты возвращаются только после следующей загрузки.
Фиксируйте результат приемки в машинно читаемом виде, даже если это простой JSON из внутреннего скрипта. Поля должны включать время, ядро, версию модуля, UUID, PCI-адреса, digest образа и результат каждого теста. В следующем инциденте такой файл отвечает, что именно изменилось. Снимок экрана с nvidia-smi не показывает окружение и плохо сравнивается автоматически.
Если многокарточный тест продолжает падать, уменьшайте область: одна задача, одна карта, затем две карты на одном PCIe-коммутаторе, затем пара через другой корневой комплекс. Меняйте только одну ось за запуск. Одновременная смена ядра, драйвера, образа и настроек NCCL дает новый сервер, но не объясняет старый отказ.
Возвращайте нагрузку постепенно. Сначала одна контролируемая задача, затем обычная конкуренция за карты и только после этого полный пул. Следите за журналом ядра и повторным появлением Xid, AER или сбросов. Ошибка, которая проявляется под тепловой или энергетической нагрузкой, может не возникнуть в минутном тесте.
Совместимость нужно хранить как конфигурацию
Список «драйвер достаточно новый» слишком расплывчат для эксплуатации. Для каждого класса узлов храните проверенный набор: модель и ревизия ускорителя, версия BIOS, ядро и заголовки, ветка драйвера, Fabric Manager при наличии, container runtime, базовый образ, CUDA или ROCm, фреймворк и настройки планировщика.
Закрепляйте ветку, а не бесконечно замораживайте один пакет. Обновления безопасности нужны, но они должны проходить через тестовый узел с той же топологией. Тест обязан включать перезагрузку, потому что обновленный пакет на диске и старый модуль в памяти создают обманчиво рабочее состояние.
Минимальная приемка обновления выглядит так:
- после холодной или обычной перезагрузки число UUID совпадает с паспортом узла;
- модуль и пользовательская библиотека принадлежат выбранной ветке;
- каждая карта проходит короткий вычислительный тест;
- разрешенный P2P или коллективный обмен работает на нужных парах;
- две параллельные задачи не видят чужие устройства.
Сохраняйте вывод вместе с версией образа и идентификатором изменения. Тогда фраза «раньше работало» превращается в сравнимый факт. Также настройте предупреждения на провал DKMS, отсутствие ожидаемого UUID, остановку службы фабрики и повторяющиеся аппаратные ошибки. Температура и загрузка полезны, но они не заменяют контроль целостности программного набора.
Популярная рекомендация обновлять драйвер на всех GPU-узлах сразу кажется эффективной из-за одинакового имени пакета. Она ошибочна, если в парке разные поколения карт, ядра или фабрики. Обновляйте по классам совместимости и оставляйте проверяемый путь отката для каждого класса.
Проверенный набор должен иметь владельца и срок пересмотра. Без владельца исключение остается навсегда, а новый базовый образ появляется без проверки на старом классе ускорителей. Изменение матрицы оформляйте так же, как изменение сетевой или хранилищной конфигурации: причина, затронутые классы, тест, окно, критерий отката и собранные результаты.
Запрет автоматических обновлений всех компонентов решает одну проблему ценой другой. Драйвер и ядро нельзя замораживать бессрочно. Разделите получение пакетов и их ввод в эксплуатацию: репозиторий может получать исправления, а производственный класс переходит на них после теста. Так безопасность не спорит с воспроизводимостью.
Хороший контроль обнаруживает расхождение до пользовательской задачи. После загрузки узловой агент может сверить ожидаемые UUID, ветку модуля, состояние фабрики и короткий тест. Если проверка не проходит, планировщик не должен принимать узел. Это дешевле, чем позволить большой задаче занять семь исправных карт и упасть из-за восьмой.
Аппаратный и программный контуры надо разбирать вместе
Когда ошибка повторяется на одном PCIe-слоте после смены карты, программная переустановка уже не главный кандидат. Когда та же карта падает в другом слоте, подозрение переходит на устройство. Перекрестная перестановка в сервисное окно, проверка питания и сравнение AER дают больше информации, чем десятая смена CUDA.
На новом сервере зафиксируйте базовый снимок до передачи в эксплуатацию: все UUID и PCI-адреса, топологию, версии прошивок, результат теста каждой карты, обмен между картами и поведение после перезагрузки. Этот паспорт сокращает расследование, потому что у администратора есть ожидаемое состояние конкретного узла.
GSE проектирует и интегрирует серверную и AI-инфраструктуру, поэтому согласование ускорителей, платформы, программного набора и дальнейшей поддержки можно заложить еще при поставке, а не собирать после первого отказа. Это не отменяет дисциплину эксплуатации: владелец системы все равно должен контролировать матрицу версий, обновления и изоляцию задач.
Не возвращайте сервер в пул, пока проверка не прошла через тот же путь, на котором возник отказ. Если проблема появилась только у двух параллельных контейнеров, одиночный тест на хосте ничего не доказывает. Исправление считается законченным, когда воспроизведен рабочий сценарий, сохранен новый базовый снимок и следующая перезагрузка не меняет результат.
FAQ
Почему nvidia-smi работает, а CUDA-приложение не видит GPU?
`nvidia-smi` проверяет связь служебной утилиты с драйвером, но приложение еще зависит от загруженной `libcuda.so`, CUDA Runtime, фреймворка и прав на устройства. Сравните тест на хосте, в минимальном образе и в образе приложения, затем проверьте фактически загруженные библиотеки.
Что означает CUDA Version в выводе nvidia-smi?
Это максимальная версия CUDA, которую поддерживает загруженный драйвер. Строка не показывает установленную версию Toolkit; ее проверяют отдельно через пакетную базу или `nvcc -V`.
Можно ли поставить CUDA новее, чем драйвер NVIDIA?
Иногда да, в пределах правил minor version compatibility и при соблюдении минимальной версии драйвера. Но новый функционал драйвера, PTX и зависимости библиотек могут нарушить такое сочетание, поэтому сверяйте матрицу для конкретного приложения.
Почему драйвер GPU пропал после обновления ядра Linux?
Обычно DKMS не собрал модуль для нового ядра, не нашел точные заголовки или Secure Boot отклонил подпись. Сопоставьте `uname -r`, `modinfo -F vermagic`, `dkms status` и журнал загрузки.
Нужно ли переустанавливать драйвер, если сервер видит не все GPU?
Сначала сравните `lspci`, служебную утилиту, PCI-адреса и журнал каждой карты. Если PCIe не видит устройство или ошибка привязана к одному слоту, переустановка драйвера почти наверняка отвлечет от платформы или оборудования.
Безопасно ли использовать CUDA_VISIBLE_DEVICES для изоляции задач?
Для выбора карт внутри обычного процесса переменная удобна, но границей безопасности она не служит. Планировщик, container runtime, cgroup и права на device nodes должны пропускать только назначенные UUID.
Почему номера GPU меняются после перезагрузки?
Номера зависят от порядка обнаружения устройств и могут измениться вместе с топологией или прошивкой. Для распределения и журналов используйте UUID, а PCI-адрес сохраняйте как привязку к физическому слоту.
Можно ли исправить конфликт драйвера перезапуском контейнера?
Только если отказ ограничен состоянием приложения или настройкой runtime. Контейнер не заменяет модуль ядра хоста, поэтому несовместимый или незагруженный драйвер требует ремонта узла.
Когда стоит откатить ядро на GPU-сервере?
Откат уместен для быстрого восстановления, если предыдущее сочетание ядра и модуля проверено и допустимо политикой безопасности. После возврата сервиса все равно разберите сбой сборки и подготовьте поддерживаемое обновление.
Какие тесты нужны перед возвратом многоускорительного сервера в работу?
Проверьте вычисление и память на каждой карте, нужные межкарточные обмены, изоляцию двух параллельных задач и запуск через производственный планировщик. Затем перезагрузите узел и повторите тот же набор.