Тот самый segfault: когда карты AMD не дружат с llama.cpp
Вы собрали сервер с двумя, четырьмя, а может и восемью AMD MI50. 32GB HBM2 на каждой - казалось бы, рай для больших моделей. Скачиваете свежую версию llama.cpp, собираете с поддержкой ROCM, запускаете Qwen3-Next-72B... и получаете холодный, безэмоциональный "Segmentation fault (core dumped)". Ни логов, ни ошибок, ни намёка на причину. Просто тишина.
Знакомо? Если да, вы не одиноки. Эта проблема съела недели моего времени, пока я не докопался до сути. Оказывается, дело не в llama.cpp и не в ROCM по отдельности. А в том, как они взаимодействуют при распределении памяти между несколькими GPU.
Важно: Эта проблема специфична для multi-GPU конфигураций с ROCM. На одной карте или с Vulkan бэкендом её обычно нет. Но если нужна максимальная производительность на AMD - ROCM обязателен.
Почему это происходит? Неочевидная причина segfault
Корень проблемы - в том, как llama.cpp распределяет слои модели по видеокартам. По умолчанию он использует простой round-robin: первый слой на GPU0, второй на GPU1, и так далее. Звучит логично, но на практике...
Когда модель начинает загружаться, llama.cpp пытается аллоцировать память на всех картах одновременно. И вот здесь ROCM 6.3.4 (самая свежая стабильная версия на февраль 2026) иногда даёт сбой. Не потому что памяти не хватает - её обычно достаточно. А потому что драйвер не успевает правильно инициализировать контексты на всех устройствах при параллельной аллокации.
Быстрое решение: флаги, которые спасут ваш день
Прежде чем погружаться в пересборку и патчи, попробуйте это. Часто помогает сразу:
./main -m ./models/qwen3-next-72b-q4_k_m.gguf \
--n-gpu-layers 99 \
--split-mode layer \
-ngl 99 \
-sm layer \
-t 8 \
--rocm-single-alloc \
--no-mmap
Ключевые моменты здесь:
--rocm-single-alloc- заставляет аллоцировать память последовательно, а не параллельно--no-mmap- отключает memory mapping, который иногда конфликтует с ROCM-sm layerи--split-mode layer- явно указываем распределение по слоям
Если это не сработало - не расстраивайтесь. У проблемы есть ещё 3-4 уровня глубины, и мы до них доберёмся.
Полное пошаговое решение: от диагностики до фикса
1 Диагностика: что на самом деле ломается?
Сначала убедимся, что проблема именно в multi-GPU. Запустите с одной картой:
HIP_VISIBLE_DEVICES=0 ./main -m ваша_модель.gguf -ngl 99
Если работает - проблема действительно в распределении между картами. Если нет - возможно, дело в базовой аллокации памяти ROCM.
Проверьте статус ваших карт через rocm-smi:
rocm-smi --showhw
Убедитесь, что все карты видны, имеют драйвер 6.3.4 и не в error state.
2 Пересборка llama.cpp с правильными флагами
Вероятно, вы собирали так:
cmake -B build -DLLAMA_HIPBLAS=ON
make -C build
Этого недостаточно. Нужны дополнительные флаги:
cd llama.cpp
rm -rf build
mkdir build && cd build
cmake .. \
-DLLAMA_HIPBLAS=ON \
-DCMAKE_C_COMPILER=/opt/rocm/bin/hipcc \
-DCMAKE_CXX_COMPILER=/opt/rocm/bin/hipcc \
-DCMAKE_BUILD_TYPE=Release \
-DLLAMA_NATIVE=OFF \
-DLLAMA_AVX=ON \
-DLLAMA_AVX2=ON \
-DLLAMA_F16C=ON
make -j$(nproc)
Особенно важен hipcc как компилятор - он знает специфику AMD и правильно линкует ROCM библиотеки.
3 Настройка переменных окружения ROCM
ROCM чувствителен к переменным окружения. Создайте скрипт запуска:
#!/bin/bash
export HSA_OVERRIDE_GFX_VERSION=9.0.0
export HIP_VISIBLE_DEVICES=0,1,2,3 # ваши карты
export ROCR_VISIBLE_DEVICES=0,1,2,3
export PYTORCH_HIP_ALLOC_CONF=max_split_size_mb:512
# Ограничиваем memory pool для стабильности
export HIP_ENABLE_USERPTR_FOR_PAGED_MEM=0
export ROCM_PATH=/opt/rocm
./main -m models/qwen3-next-72b-q4_k_m.gguf \
-ngl 99 \
-sm layer \
--rocm-single-alloc \
-c 4096 \
-b 512 \
-t 12 \
--no-mmap \
--verbose
HSA_OVERRIDE_GFX_VERSION=9.0.0 критически важен для MI50. Это обманывает ROCM, заставляя думать, что у вас более новая архитектура, что обходит некоторые баги в драйвере.
4 Патч для llama.cpp (если всё ещё падает)
Найдите в коде llama.cpp файл ggml-backend-impl.h. Добавьте после инициализации HIP:
// Добавьте эту задержку после hipInit(0)
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
// Или более агрессивный вариант - инициализируйте устройства последовательно
for (int i = 0; i < device_count; ++i) {
hipSetDevice(i);
hipDeviceSynchronize();
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
Да, костыль. Да, неэлегантно. Но работает. Проблема в том, что hipInit() не гарантирует полной инициализации всех контекстов до возврата управления.
Альтернатива: может, проще использовать Vulkan?
Честно? Иногда - да. Если производительность не критична, Vulkan бэкенд стабильнее. Но вы потеряете 20-40% скорости на MI50.
| Бэкенд | Скорость (tok/s) | Стабильность | Поддержка multi-GPU |
|---|---|---|---|
| ROCM | 25-35 (Qwen3-72B) | Низкая (требует настройки) | Полная |
| Vulkan | 15-22 | Высокая | Ограниченная |
Сборка с Vulkan:
cmake -B build -DLLAMA_VULKAN=ON
make -C build
Но если вы читаете эту статью, вам нужна максимальная производительность. Значит, ROCM неизбежен. Как и его грабли.
Частые ошибки и как их избежать
1. "hipErrorOutOfMemory" при достаточной VRAM
Не ведитесь на сообщение. Это не всегда нехватка памяти. Чаще - фрагментация или неправильная аллокация. Решение:
export PYTORCH_HIP_ALLOC_CONF=max_split_size_mb:512,garbage_collection_threshold:0.8
2. Разные версии ROCM в системе
Убедитесь, что везде одна версия:
# Проверяем всё
dpkg -l | grep rocm # или rpm -qa | grep rocm
/opt/rocm/bin/rocminfo | grep "ROCk version"
ldd ./main | grep rocm
3. Конфликт с NVIDIA драйверами
Если в системе есть NVIDIA карты, они могут мешать. Особенно если вы пробовали гибридную сборку. Решение - blacklist nouveau и явное указание устройств через HIP_VISIBLE_DEVICES.
4. Неправильное квантование модели
MI50 не любит некоторые форматы. Q4_K_M обычно работает. Q8_0 может вызывать проблемы. Попробуйте переквантовать:
./quantize модель.bin модель_квантованная.gguf q4_k_m
Что делать, если ничего не помогает?
Есть ядерное решение. Уменьшите количество слоёв на GPU:
# Вместо -ngl 99 (все слои на GPU)
./main -m модель.gguf -ngl 64 -sm layer --rocm-single-alloc
35 слоёв останутся на CPU. Медленнее, но стабильнее. Или распределите модель вручную:
# Первые 50 слоёв на GPU0, остальные на GPU1
./main -m модель.gguf --tensor-split 0.5,0.5 -ngl 99
Профилактика на будущее
Собирая multi-GPU систему под AI, учитывайте:
- Одинаковые карты - MI50 с MI50, а не MI50 с MI100. Разная архитектура = гарантированные проблемы
- Достаточное питание - каждая MI50 кушает до 300W. Нехватка питания вызывает random crashes
- Охлаждение - thermal throttling на AMD срабатывает агрессивно. При 90°C+ начинаются ошибки памяти
- BIOS сервера - включите Above 4G Decoding и Resizable BAR. Без этого >16GB на устройстве могут не работать
И последнее: ведите лог. Всегда запускайте с --verbose 2> debug.log. Когда (не если) снова упадёт - будет что анализировать.
Итог: почему это всё ещё проблема в 2026 году?
ROCM развивается, но multi-GPU inference - сложная задача. Особенно с legacy картами вроде MI50. AMD сосредоточена на новых ускорителях, а сообщество llama.cpp разрывается между поддержкой всего железа и добавлением новых функций.
Мой прогноз? К середине 2026 года эти проблемы либо исчезнут (с выходом ROCM 7.0 и полным рефакторингом llama.cpp), либо станут настолько нишевыми, что их будут фиксить вручную энтузиасты. Пока что - сохраните этот гайд в закладки. Он сэкономит вам дни отладки.
P.S. Если собираете систему с нуля, посмотрите разбор кейса с 8× RTX 3090. Там другие проблемы, но принципы те же: стабильность требует жертв. Или хотя бы понимания, как всё работает изнутри.