Skip to content

rig 준비를 상징하는 이미지

radiance 공식 문서에는 맨 하드웨어에서 Qwen3.8-Flash-Next를 서빙하는 상태까지의 전 과정을 단계별로 정리한 PREPARING_YOUR_RIG.md가 있다. 참고 rig는 MSI MPG X670E CARBON WIFI 메인보드, Ryzen 9 7950X3D, RAM 64GB, NVMe 2TB, CPU에 직접 붙은 x16 슬롯 두 개에 Radeon AI PRO R9700을 꽂은 구성이다. 다른 보드라도 같은 설정을 각자의 메뉴 이름으로 찾으면 된다. 이 글은 그 순서를 한국어로 따라가며, 각 단계가 끝날 때마다 확인 명령으로 결과를 검증한다.

참고 머신 ​

전체 과정은 여섯 단계다. 펌웨어 설정 → Arch Linux 설치 → Docker와 AUR → 커널 파라미터 → 카드 확인 → 전력 튜닝, 마지막에 모델 서빙. 문서가 강조하는 하드웨어 조건은 셋이다.

  • Resizable BAR: 호스트가 커널 디스패치 인자를 VRAM에 직접 쓴다. BAR가 VRAM보다 작으면 인자를 고정 호스트 메모리에 두고 매 디스패치마다 링크를 통해 읽게 되어 속도가 준다. P2P(카드 간 직접 접근)도 큰 BAR를 필요로 한다.
  • amdgpu.cwsr_enable=1 (기본값): 컴퓨트 wave save/restore가 꺼져 있으면 드라이버가 강제로 빼내야 하는 큐를 선점하지 못해 카드가 멈추고 리셋된다. radiance는 이 설정이 꺼진 카드에서는 서빙을 거부하고 무엇을 고칠지 알려준다.
  • PCIe 링크: 두 카드가 CPU에 붙은 x16(또는 x8/x8 분할) 슬롯에 있어야 한다.

펌웨어 설정 ​

전원 부팅 시 Del로 펌웨어 설정에 들어가 다음을 바꾼다.

설정값이유
XMP / EXPOprofile 1RAM을 정격 속도로
Above 4G Decoding활성화Resizable BAR의 전제
Re-Size BAR Support활성화디스패치 인자를 VRAM에 기록, P2P도 필요로 함
CSM비활성화Resizable BAR는 순수 UEFI 부팅 필요
Secure Boot비활성화Arch 설치 매체가 서명되지 않음
x16 슬롯 두 개의 PCIe 레인 분할x8/x8두 카드 모두 CPU 레인으로
두 슬롯의 PCIe 링크 속도Gen5슬롯이 낮은 세대로 트레이닝되는 것 방지
내장 Wi-Fi·Bluetooth비활성화유선 사용, 드라이버와 IRQ 하나 줄이기

F10 저장 후 빠져나온다.

운영체제와 Docker ​

문서는 Arch Linux를 기준 예로 든다. archinstall로 최소 구성(systemd-boot, ext4, 스왑 off, Minimal 프로필, NetworkManager, openssh git base-devel)을 설치하고, 콘솔에서 sshd를 켜서 SSH로 작업으로 전환한다.

sh
sudo systemctl enable --now sshd
ip -4 addr show       # rig의 주소 확인

이어서 Docker 계열과 AUR helper를 설치하고 사용자를 그룹에 넣는다.

sh
sudo pacman -Syu --needed docker docker-compose docker-buildx
sudo systemctl enable --now docker
sudo usermod -aG docker,render,video "$USER"     # 로그아웃 후 재로그인
yay -S rocm-bandwidth-test                        # 이후 P2P 확인용

radiance는 ROCm을 호스트에 요구하지 않는다. ROCm이 필요해지지 않게 하려면 호스트에 ROCm을 설치하지 말고 Docker 이미지를 쓰는 편이 낫다.

커널 파라미터 ​

부팅 항목(/boot/loader/entries/*_linux.conf)의 options 줄에 셋을 덧붙인다.

iommu=pt amdgpu.ppfeaturemask=0xfff7ffff amdgpu.ras_enable=0
  • iommu=pt — IOMMU를 패스스루로 두어 카드들이 서로의 메모리에 도달하고 고정 호스트 메모리 매핑도 변환 없이 지나간다.
  • amdgpu.ppfeaturemask=0xfff7ffff — 드라이버 기본 마스크에 OverDrive 비트를 켠 값. 이후 언더볼트를 쓰려면 필요하다.
  • amdgpu.ras_enable=0 — VRAM ECC 해제. ECC가 켜져 있으면 카드마다 VRAM 약 2GB를 예약해 버린다.

P2P(CONFIG_HSA_AMD_P2P)는 Arch 기본 커널이 7.1.2부터 활성화되어 있어 보통 별도 커널 빌드가 필요 없다. 기본 항목으로 지정한 뒤 재부팅한다.

sh
sudo bootctl set-default "$(basename /boot/loader/entries/*_linux.conf)"
sudo reboot

카드 확인 ​

재부팅 후 문서의 확인 목록을 하나씩 돌린다.

sh
cat /proc/cmdline                                     # 세 파라미터가 보여야
zcat /proc/config.gz | grep -E 'HSA_AMD_P2P|PCI_P2PDMA'   # 둘 다 =y
lspci -vv -d 1002:7551 | grep 'Region 0'             # 두 카드 다 size=32G (ReBAR)
sudo journalctl -k -b | grep 'available PCIe bandwidth'   # 카드당 32.0 GT/s PCIe x8
cat /sys/class/drm/card*/device/mem_info_vram_total   # 34208743424 (ECC off 확인)
rocm-bandwidth-test -a

rocm-bandwidth-test -a의 대역행렬에서 카드와 CPU 사이 왕복은 약 28GB/s가 나와야 하고, GPU 간 칸은 전부 값이 있어야 한다. 칸이 비었다면 P2P가 안 되는 것이니 iommu=pt와 BAR 크기를 다시 확인한다. 유휴 링크가 lspci에 2.5 GT/s로 보이는 것은 정상이다. 반대로 부하에서 한 카드가 다른 카드의 절반만 나오면 PCIe 루트 포트 전원 상태가 한 단계 아래에 낀 것이니 재부팅으로 풀린다.

전력 리밋과 언더볼트 ​

R9700 기준 문서의 실측: 210W 리밋은 기본 300W 대비 디코딩 속도를 1% 남짓만 떨어뜨린다. 언더볼트는 -70mV를 권한다(-75mV에서는 가장 무거운 GEMM에서 실행 간 편차가 관찰됨). 두 설정은 재부팅마다, 언더볼트는 카드의 런타임 재개 때마다 사라지므로 부팅 서비스로 적용한다. 문서에는 pp_od_clk_voltage과 power1_cap을 건드리는 gpu-tune.sh와 systemd unit(gpu-tune.service) 전체가 통째로 제공되므로 그대로 복사해 설치하면 된다.

sh
journalctl -u gpu-tune -b --no-pager | tail -2    # 두 카드 모두 -70mV, cap 210 W 확인

시작하지 전에 알아 둘 것 — 카드가 GPU 리셋되면 전력 리밋·팬 커브·전압 오프셋이 펌웨어 기본값으로 돌아간다. 리셋 후 재기동 전에는 반드시 다시 적용해야 한다.

첫 서빙과 확인 ​

준비가 끝났으니 compose로 Flash-Next를 올려본다.

sh
git clone https://codeberg.org/StillDeadcode/radiance.git
cp -r radiance/deploy/compose ~/radiance-compose && cd ~/radiance-compose
mkdir -p ~/models/rad
curl -L -C - -o ~/models/rad/qwen3.8-next-flash-fp8-iq4r-moe.rad \
  https://huggingface.co/StillDeadcode/qwen3.8-next-flash-fp8-iq4r-moe/resolve/main/qwen3.8-next-flash-fp8-iq4r-moe.rad
cp .env.example .env && chmod 600 .env   # RADIANCE_MODELS, RADIANCE_API_KEY, UID/GID, RENDER_GID, VIDEO_GID 채우기
docker compose -f flashnext.yaml up -d
docker compose -f flashnext.yaml logs -f

114GiB짜리 컨테이너 다운로드가 끊기면 같은 -C - 명령으로 이어 받는다. 기동 로그에서 반드시 확인해야 할 한 줄은 이것이다.

device: the 2 cards reach each other's memory directly (peer to peer)

no peer-to-peer access 경고가 뜨면 5단계 확인을 하나도 통과하지 못한 것이다. 마지막으로 실제 요청을 던진다.

sh
KEY=$(grep ^RADIANCE_API_KEY= .env | cut -d= -f2)
curl -s localhost:8000/health
curl -s localhost:8000/v1/chat/completions -H "Authorization: Bearer $KEY" \
  -H 'Content-Type: application/json' \
  -d '{"messages":[{"role":"user","content":"What is 65 * 3?"}]}'

이 컨테이너는 머신과 함께 자동 재기동된다. next 글에서는 이 compose 구조를 더 일반적으로 다룬다 — 이미지 직접 빌드, docker run 옵션의 의미, 모델별 compose 파일 표까지.

오픈소스를 한국어로 읽고 배웁니다.