AI 인프라를 구성하는 방법은 워크로드의 성격, 모델 규모, 예산, 사용 기간에 따라 달라집니다. 최신 GPU 서버는 GPU의 연산 성능만으로 결정되지 않습니다. GPU 메모리, NVLink와 NVSwitch, PCIe, NIC(Network Interface Card), 네트워크 패브릭까지 하나의 시스템으로 연결되어 있기 때문에 어느 한 구성 요소가 바뀌면 전체 데이터 경로를 다시 검증해야 합니다.
새로운 GPU 세대가 출시되면 함께 확인해야 할 범위도 넓어집니다. NVIDIA B300에서는 GPU와 NIC뿐 아니라 PCIe 연결 구조까지 이전 세대와 달라졌습니다. 새로운 장비를 실제 클라우드 서비스에 투입하려면 OS, 커널, 드라이버, 펌웨어의 호환성을 검증하고, 물리 장치의 연결 관계인 토폴로지를 가상화 환경에서도 올바르게 재현해야 합니다.
Elice Cloud Infrastructure(ECI)는 엘리스가 자체 설계하고 운영하는 IaaS(Infrastructure as a Service) 서비스입니다. 다양한 GPU와 NPU(Neural Processing Unit) 노드를 대상으로 상면과 전력 설계부터 가상화, 권한 관리, 모니터링까지 AI 인프라 운영에 필요한 계층을 통합해 제공하고 있습니다.
이 글에서는 B300 서버를 ECI에 도입하면서 진행한 과정을 소개합니다. 먼저 B300의 PCIe 토폴로지가 이전 세대와 어떻게 달라졌는지 확인하고, 이 구조를 VM(Virtual Machine) 내부에 재구성하는 과정을 살펴봅니다. 이후 IOMMU(Input-Output Memory Management Unit), ATS(Address Translation Services), ACS(Access Control Services) 등의 PCIe 가상화 기술들에 대해 설명합니다. 마지막으로 동일한 B300 노드에서 호스트와 게스트의 성능을 비교해 실제 가상화 오버헤드를 측정합니다.
ECI 가상화 구조
ECI에서 가상화를 사용하는 이유
ECI는 GPU 서버를 물리 장비 그대로 사용자에게 할당하는 방식만 사용하지 않고, 물리 노드와 사용자 사이에 가상화 계층을 둡니다. 가상화를 사용하는 가장 큰 이유는 물리 서버보다 작은 단위로 자원을 할당하면서도 사용자별 실행 환경과 장치를 독립적으로 구성할 수 있기 때문입니다.
물리 노드와 VM 기반 제공 방식의 특성을 단순화하면 다음과 같습니다.
| 항목 | 물리 노드 | 가상 머신 |
|---|---|---|
| 격리 단위 | 물리 노드 전체 | VM |
| 커널 | 노드 단위로 하나의 실행 환경 제공 | 게스트별 독립 커널 |
| 장치 격리 | 물리적으로 다른 노드 사용 | IOMMU를 통한 DMA 격리 |
| SW 조합 | 노드 전체가 하나의 OS와 드라이버 조합 사용 | 게스트별로 서로 다른 OS와 드라이버 조합 구성 가능 |
| 회수와 배정 | 데이터 초기화와 OS 재설치 등 reprovisioning 필요 | VM 종료와 논리 디스크 재연결로 빠른 재배정 가능 |
| 성능 | 중간 계층이 없어 데이터 경로가 단순함 | VMM과 IOMMU 등 추가 계층의 오버헤드가 발생할 수 있음 |
| 운영 구조 | 구조가 단순하지만 자원 할당 단위가 큼 | 운영 계층은 복잡하지만 자원 배치가 유연함 |
한 사용자가 서버 전체를 장기간 독점한다면 물리 노드 방식이 가장 단순합니다. 가상화 계층이 없기 때문에 하드웨어 성능을 그대로 활용하기 쉽고, 서버 한 대를 하나의 운영 단위로 관리할 수 있습니다. 반면 여러 사용자가 서로 다른 OS, 커널, GPU 드라이버, CUDA 및 통신 라이브러리 조합을 요구하는 환경에서는 물리 노드 단위의 할당이 제약으로 작용합니다. 사용이 끝난 서버를 다른 사용자에게 넘길 때도 기존 데이터 삭제와 OS 재설치, 드라이버와 펌웨어 상태 확인 등 다시 프로비저닝하는 과정이 필요합니다.
ECI는 이러한 물리 노드 방식의 단순성보다 자원 배치의 유연성과 빠른 재프로비저닝을 우선했습니다. 같은 호스트에서도 VM마다 서로 다른 이미지를 사용할 수 있으므로 CUDA와 GPU 드라이버 조합이 다른 워크로드를 독립적으로 실행할 수 있습니다. 또한 장치 패스스루 환경에서는 IOMMU가 VM에 할당된 DMA(Direct Memory Access) 영역을 격리합니다. DMA는 PCIe 장치가 CPU의 지속적인 개입 없이 시스템 메모리를 직접 읽고 쓰는 방식이며, IOMMU는 각 장치가 접근할 수 있는 호스트 메모리 범위를 VM별로 제한합니다.
VM의 상태가 특정 물리 서버가 아니라 논리 디스크에 유지된다는 점도 중요합니다. VM을 종료하면 GPU와 CPU 자원을 반환할 수 있고, 기존 논리 디스크를 다시 연결하면 같은 소프트웨어 환경을 빠르게 복원할 수 있습니다. 이를 기반으로 ECI에서는 물리 서버 한 대보다 작은 단위로 GPU를 제공하고, 사용자와 워크로드에 따라 서로 다른 실행 환경을 구성할 수 있습니다.
대신 가상화에는 추가로 해결해야 하는 문제가 생깁니다. 게스트와 하드웨어 사이에 VMM(Virtual Machine Monitor), IOMMU 등의 계층이 추가되고, PCIe 장치도 물리 서버의 구조가 그대로 노출되는 것이 아니라 호스트가 구성한 가상 토폴로지를 통해 게스트에 전달됩니다. 따라서 단순히 GPU와 NIC를 VM에 정상적으로 연결하는 것만으로는 충분하지 않습니다. DMA 주소 변환에서 발생하는 비용을 줄이고, GPU와 NIC 사이의 물리적 인접 관계까지 게스트에서 올바르게 표현해야 실제 하드웨어 성능에 근접할 수 있습니다.
특히 PCIe 토폴로지는 GPU 워크로드의 통신 경로 선택에 직접적인 영향을 줍니다. 물리 서버에 GPU 8장이 있더라도 일부 GPU만 VM에 할당할 수 있고, 이를 연결하는 가상 PCIe Bridge와 Root Port 역시 물리 구조와 반드시 일대일로 대응할 필요는 없습니다. NCCL(NVIDIA Collective Communications Library)과 CUDA 런타임은 게스트에 노출된 토폴로지를 바탕으로 P2P(Peer-to-Peer) 가능 여부와 통신 경로를 판단합니다. 물리적으로 가까운 GPU와 NIC를 게스트에서 멀리 떨어진 장치처럼 표현하면, 실제로는 빠른 경로가 존재하더라도 소프트웨어가 이를 최적 경로로 인식하지 못할 수 있습니다.
그래서 신규 GPU 서버를 ECI에 도입할 때는 장치가 정상적으로 인식되는지를 확인하는 데서 끝나지 않습니다. 물리 토폴로지를 분석하고, 장치의 역할을 식별한 뒤, 이를 가상화 환경에 재구성하고 실제 성능까지 검증합니다. 과정은 크게 다음 네 단계로 나눌 수 있습니다.
- 토폴로지 재구성: 호스트의 실제 PCIe 구조를 분석하고 게스트에 노출할 토폴로지를 설계합니다.
- 장치 라벨링: GPU, NIC, NVMe, 관리망 NIC 등 각 장치의 역할을 식별합니다.
- 가상화 기술 적용: VFIO, IOMMU, ATS, ACS 등 장치별 가상화 기능을 구성합니다.
- 성능 검증: 동일한 하드웨어에서 호스트와 게스트를 측정해 가상화에 따른 성능 차이를 확인합니다.
B300에서도 이 과정을 동일하게 적용했습니다. 다만 B300에서는 이전 세대와 비교해 GPU와 NIC 사이의 PCIe 구조가 크게 달라졌기 때문에 기존 설정을 그대로 적용하기 전에 물리 토폴로지부터 다시 분석해야 했습니다.
B300 토폴로지
B300은 연산 성능과 메모리뿐 아니라 GPU 주변 I/O 구조에도 변화가 있습니다. 가상화 관점에서 특히 중요한 변화는 ConnectX-8 도입과 GPU-NIC 사이 PCIe Gen 6 경로입니다. 새로운 NIC가 단순히 더 빠른 링크를 제공하는 것이 아니라 GPU와 NIC가 연결되는 PCIe 계층 자체가 변경됐기 때문에 기존 B200 토폴로지 설계를 그대로 사용할 수 없었습니다.
NIC가 ConnectX-8로 바뀌었습니다
B200에서 사용하던 ConnectX-7의 포트 대역폭은 400Gb/s였습니다. B300에서는 ConnectX-8이 도입되면서 최대 포트 대역폭이 800Gb/s로 증가했습니다. RoCE(RDMA over Converged Ethernet) 환경에서는 하나의 800G 포트를 400G 두 개로 분할하고 각각을 서로 다른 네트워크 패브릭에 연결하는 구성이 권장됩니다.[1][2]
RDMA(Remote Direct Memory Access)는 원격 시스템 사이에서 CPU의 개입을 최소화하고 메모리 사이에 직접 데이터를 전송하는 기술입니다. 두 개의 400G 인터페이스를 서로 다른 패브릭에 연결하면 GPU 하나가 두 개의 네트워크 경로를 사용할 수 있고, 패브릭 장애 도메인도 분리할 수 있습니다.
NIC 안에 PCIe Gen 6 스위치가 들어갔습니다
더 큰 변화는 ConnectX-8 내부의 PCIe 구조입니다. ConnectX-8에는 48-lane PCIe Gen 6 스위치가 통합되어 있습니다.[3]

▲ 그림 1: 왼쪽은 NIC가 보드의 PCIe 스위치에 연결된 기존 구조이고, 오른쪽은 PCIe Gen 6 스위치가 ConnectX-8에 통합된 구조입니다. 출처: [3]
B200에서는 GPU와 ConnectX-7이 보드 위의 Broadcom PCIe Gen 5 스위치 아래에 위치합니다. B300에서는 ConnectX-8 내부에 PCIe Gen 6 스위치가 추가되고 GPU가 이 스위치에 연결됩니다. 그 결과 GPU와 인접 NIC 사이의 PCIe 경로가 Gen 5에서 Gen 6로 변경되었습니다.
이 구조가 필요한 이유는 대역폭을 비교해 보면 명확합니다. 800Gb/s는 이론적으로 방향당 약 100GB/s의 데이터 전송률에 해당하지만 PCIe Gen 5 x16의 실효 최대 대역폭은 방향당 약 63GB/s 수준입니다. 따라서 800Gb/s NIC의 대역폭을 온전히 활용하려면 GPU-NIC 사이의 PCIe 경로 역시 더 빨라져야 합니다. PCIe Gen 6 x16은 약 118GB/s 수준의 대역폭을 제공하므로 800Gb/s NIC의 데이터 경로를 수용할 수 있습니다.
반면 GPU 사이의 통신은 NVLink와 NVSwitch를 이용하기 때문에 서버 전체의 PCIe 경로를 Gen 6로 변경할 필요는 없습니다. CPU나 메인보드 전체를 Gen 6 플랫폼으로 변경하는 대신, 높은 대역폭이 필요한 GPU-NIC 구간에 ConnectX-8 내부 PCIe Gen 6 스위치를 배치한 구조입니다.

▲ 그림 2: 경로별 PCIe 세대. GPU-NIC 경로는 Gen 6, GPU-CPU 상위 경로는 Gen 5. 출처: [4]
토폴로지 실측
실제 서버에서도 이 구조를 확인할 수 있습니다. lspci -t에서 GPU 한 장 주변의 PCIe 트리만 추출하면 B200과 B300의 차이가 그대로 나타납니다.
B200
| \-01.0-[98-9d]----00.0-[99-9d]--+-00.0-[9a]----00.0 NVIDIA Corporation GB100 [B200] [10de:2901]
| +-01.0-[9b]----00.0 Mellanox Technologies MT2910 Family [ConnectX-7] [15b3:1021]
| +-02.0-[9c]----00.0 Samsung Electronics Co Ltd NVMe SSD Controller PM9A1/PM9A3/980PRO [144d:a80a]
| \-1f.0-[9d]----00.0 Broadcom / LSI PCIe Switch management endpoint [1000:00b2]
#98:00.0 = broadcom switch
B300
| \-02.0-[eb-f4]----00.0-[ec-f4]--+-00.0-[ed-f2]----00.0-[ee-f2]--+-00.0-[ef]--+-00.0 Mellanox Technologies CX8 Family [ConnectX-8] [15b3:1023]
| | | \-00.1 Mellanox Technologies CX8 Family [ConnectX-8] [15b3:1023]
| | \-02.0-[f0-f2]----00.0-[f1-f2]----00.0-[f2]----00.0 NVIDIA Corporation GB110 [B300 SXM6 AC] [10de:3182]
| +-01.0-[f3]----00.0 Broadcom / LSI Virtual PCIe Placeholder Endpoint [1000:02b2]
| \-02.0-[f4]----00.0 Samsung Electronics Co Ltd NVMe SSD Controller PM9A1/PM9A3/980PRO [144d:a80a]
#eb:00.0 = broadcom switch
#ec:00.0 = mellanox virtual port
#ed:00.0 = mellanox PCIe Bridge
Mellanox Technologies로 표시되는 장치가 ConnectX-8이고 NVIDIA Corporation으로 표시되는 장치가 B300 GPU입니다. B300에서는 하나의 ConnectX-8에서 ef:00.0과 ef:00.1 두 개의 네트워크 인터페이스가 노출됩니다. 또 GPU와 NIC가 다른 장치보다 더 깊은 PCIe Bridge 계층 아래에 위치하는 것도 확인할 수 있습니다.
부모 Bridge의 세부 정보를 보면 B200에서는 Broadcom PEX890xx PCIe Gen 5 Switch가 사용되는 반면, B300의 GPU 바로 위에서는 Mellanox mlx5Gen PCIe Bridge가 확인됩니다.
# B200 부모 스위치
PCI bridge [0604]: Broadcom / LSI PEX890xx PCIe Gen 5 Switch [1000:c030] (rev b0) (prog-if 00 [Normal decode])
# B300 부모 스위치
PCI bridge [0604]: Mellanox Technologies ConnectX/BlueField Family mlx5Gen PCIe Bridge [PCIe Bridge] [15b3:197c] (prog-if 00 [Normal decode])
링크 속도에서도 차이가 나타납니다.
# B300 GPU <-> NIC 경로
LnkSta: Speed 64GT/s, Width x16
TrErr- Train- SlotClk- DLActive+ BWMgmt- ABWMgmt-
# B300 GPU <-> CPU 상위 경로
LnkSta: Speed 32GT/s, Width x16
TrErr- Train- SlotClk- DLActive+ BWMgmt- ABWMgmt-
GPU-NIC 구간은 64GT/s, 즉 PCIe Gen 6 x16으로 동작하고 GPU-CPU 방향의 상위 경로는 32GT/s, 즉 PCIe Gen 5 x16으로 동작합니다. 실제 PCIe 트리와 링크 상태를 종합하면 B300에서는 GPU와 인접 ConnectX-8 사이에 별도의 Gen 6 계층이 추가됐다는 것을 확인할 수 있습니다.
정리하면
- ConnectX-8 도입으로 NIC 포트 대역폭이 400Gb/s에서 800Gb/s로 증가했습니다.
- GPU와 인접 ConnectX-8 사이의 PCIe 경로가 Gen 6 x16으로 변경되었습니다.
- ConnectX-8 내부 PCIe 스위치가 추가되면서 GPU와 NIC의 PCIe 계층 구조도 이전 세대와 달라졌습니다.
- 따라서 게스트에서도 B300의 GPU-NIC 인접 관계를 반영하도록 PCIe 토폴로지를 다시 구성해야 합니다.
토폴로지 재구성
VM에서 보이는 PCIe 토폴로지는 물리 서버의 토폴로지와 반드시 동일할 필요가 없습니다. 실제 PCIe 장치를 패스스루하면서도 게스트에는 별도의 가상 Root Port와 PCIe Bridge를 구성할 수 있고, 게스트 OS와 NCCL은 이 가상 토폴로지를 기준으로 장치 사이의 거리를 판단합니다.[5]
따라서 물리적으로 GPU와 NIC가 PCIe Gen 6로 가까이 연결되어 있더라도 게스트에서 두 장치를 멀리 떨어진 것으로 표현하면 최적의 통신 경로를 선택하지 못할 수 있습니다. B300에서 우선적으로 보존해야 하는 관계는 GPU 사이의 NVLink 경로와 GPU에서 인접 ConnectX-8로 이어지는 PCIe Gen 6 경로입니다.
구체적으로는 다음 두 경로를 우선적으로 보존합니다.
- GPU-GPU: NVSwitch를 경유하는 18개의 NVLink 연결인 NV18 경로
- GPU-인접 NIC: 해당 GPU와 PCIe Gen 6로 연결된 ConnectX-8 인터페이스
호스트가 초기화될 때 PCIe 트리를 순회하면서 Device ID, Subsystem ID, PCI Class와 상위 Bridge 관계를 수집합니다. 각 GPU는 동일한 물리적 PCIe 계층에 있는 NIC와 NVMe 등의 장치와 하나의 토폴로지 단위로 기록되고, VM을 만들 때 이 정보를 바탕으로 게스트의 PCIe 계층을 구성합니다. 특정 GPU를 VM에 넘길 때 해당 GPU와 인접한 NIC를 동일한 가상 PCIe 스위치 아래에 배치하는 방식입니다.
nvidia-smi topo -m은 NVIDIA 장치 사이의 상대적인 연결 관계를 몇 가지 등급으로 표현합니다. 동일한 서버를 호스트와 게스트에서 확인한 결과는 다음과 같습니다.
| 경로 | 호스트 | 게스트 |
|---|---|---|
| GPU ↔ GPU | NV18 | NV18 |
| GPU ↔ 인접 NIC | PXB | PIX |
| 인접 NIC ↔ 인접 NIC | PIX | PIX |
| NIC 수 | 18개, 인접 16개와 관리망 2개 | 16개, 인접 NIC만 |
각 표기의 의미는 다음과 같습니다.
NV18: NVSwitch를 경유해 18개의 NVLink가 연결된 경로PIX: 최대 하나의 PCIe Bridge를 통과하는 경로PXB: 여러 PCIe Bridge를 통과하지만 CPU의 Host Bridge는 통과하지 않는 경로PHB: CPU의 Host Bridge를 통과하는 경로NODE: 동일한 NUMA(Non-Uniform Memory Access) 노드 안에서 서로 다른 Host Bridge를 경유하는 경로SYS: 서로 다른 NUMA 노드를 거치는 경로
GPU-GPU 관계는 호스트와 게스트 모두 NV18로 유지됩니다. GPU와 인접 NIC는 실제 B300 호스트에서는 ConnectX-8 내부 PCIe 계층 때문에 PXB로 표시되지만, 게스트에서는 가상 PCIe 계층을 단순화하면서 PIX로 표현했습니다. 여기서 중요한 것은 물리 서버의 Bridge 개수를 그대로 복제하는 것이 아니라 통신 라이브러리가 경로를 선택하는 데 필요한 장치 사이의 상대적 거리와 인접성을 보존하는 것입니다.[6]
게스트에서는 인접 NIC를 GPU와 같은 가상 PCIe 스위치 아래에 두고, 비인접 NIC는 Host Bridge를 경유하는 PHB 관계로 표현했습니다. 이렇게 하면 실제 Bridge 계층은 호스트보다 단순해지더라도 어떤 NIC가 해당 GPU에 가장 가까운지는 그대로 유지됩니다.
정리하면
- 게스트의 PCIe 토폴로지는 VM 생성 시 호스트에서 구성할 수 있습니다.
- B300에서는 GPU-GPU NVLink 관계와 GPU-ConnectX-8의 PCIe Gen 6 인접 관계를 우선적으로 보존합니다.
- 물리 Bridge 구조를 그대로 복제하기보다 NCCL과 CUDA가 올바른 경로를 선택하도록 상대적인 장치 거리를 보존하는 것이 핵심입니다.
이 토폴로지를 구성하려면 먼저 호스트의 각 PCIe 장치가 어떤 역할을 하는지 정확하게 식별해야 합니다.
장치 라벨링
ECI에서는 호스트의 PCIe 장치를 읽어 들인 뒤 GPU, 데이터 네트워크 NIC, NVMe, 관리망 NIC, NVSwitch 관리 인터페이스 등 역할별로 라벨을 부여합니다. 이 라벨에 따라 장치를 VM에 노출할지, 어느 VM에 할당할지, 어떤 드라이버에 바인딩할지, 게스트의 어느 PCIe 위치에 배치할지가 결정됩니다.
새로운 서버가 들어오면 기존 장비에는 없던 Device ID나 Subsystem ID가 등장할 수 있기 때문에 장치 식별 규칙 역시 업데이트해야 합니다. 동일한 PCI Device ID를 가진 장치라도 서버 내부에서의 물리적 위치나 용도가 다를 수 있으므로 PCI ID 하나만으로 역할을 판단하지 않습니다. PCI Class, Subsystem ID와 함께 상위 PCIe Bridge 관계와 주변 장치까지 확인해 실제 역할을 분류합니다.
B300 한 대에는 GPU 8장, GPU에 인접한 NIC 16개, 관리용 NIC 2개, GPU별 NVMe, NVSwitch 관리 인터페이스 4개가 있습니다. 구조를 단순화하면 다음과 같습니다.
--------------------
*호스트
├─ HB ─ switch ─┬─ GPU0
│ └─ CX-8 ─┬ NIC0
│ └ NIC1
├─ HB ─ switch ─┬─ GPU1
│ └─ CX-8 ─┬ NIC2
│ └ NIC3
├─ HB ──────────── NIC4 ← 관리망
├─ HB ─ switch ─┬─ GPU2
│ └─ CX-8 ─┬ NIC5
│ └ NIC6
├─ HB ─ switch ─┬─ GPU3
... └─ CX-8 ─┬ NIC7
└ NIC8
--------------------
*가상 머신
└─ Host Bridge
├─ switch ─┬─ GPU0
│ ├─ NIC0 ┐ 상호 PIX
│ └─ NIC1 ┘
├─ switch ─┬─ GPU1
... ├─ NIC2 ┐ 상호 PIX
└─ NIC3 ┘
게스트에는 워크로드 실행에 필요한 GPU 8장과 인접 NIC 16개만 노출합니다. 관리망 NIC 2개와 NVSwitch 관리 인터페이스 4개는 호스트의 관리 영역에 남기고 게스트에서는 숨깁니다. 이렇게 장치의 역할과 물리적 위치를 먼저 식별해 두면 이후 VM을 생성할 때 GPU와 대응하는 NIC를 일관된 규칙으로 배치할 수 있습니다.
정리하면
- 호스트의 PCIe 장치 전체에 역할별 라벨을 부여합니다.
- PCI ID뿐 아니라 Subsystem ID, PCI Class와 물리 토폴로지를 함께 사용해 장치를 식별합니다.
- B300에서는 GPU 8장과 인접 NIC 16개를 게스트에 노출하고, 관리용 장치는 호스트에 남깁니다.
- 이 라벨 정보가 이후 패스스루, 드라이버 바인딩, 게스트 PCIe 토폴로지 구성의 기준이 됩니다.
가상화 기술
장치 식별과 토폴로지 구성이 끝나면 실제 디바이스 패스스루와 DMA 격리 기능을 적용합니다. GPU와 NIC처럼 대량의 DMA가 발생하는 PCIe 장치를 VM에 직접 할당하려면 성능뿐 아니라 각 장치가 어느 메모리 영역까지 접근할 수 있는지도 함께 통제해야 합니다.
이때 적용하는 기술들은 다음 두 가지의 근본적인 문제에서 출발합니다.
- 게스트와 호스트가 서로 다른 주소를 본다. 게스트는 자신의 물리 주소를 사용하지만 실제 메모리는 호스트의 물리 주소로 관리됩니다. PCIe 장치는 이 차이를 알지 못한 채 DMA를 시작합니다.
- 주소 변환에는 비용이 든다. 매 DMA마다 페이지 테이블을 처음부터 탐색하면 고속 NIC처럼 변환 횟수가 많은 장치에서 비용이 누적됩니다.
메모리 주소 공간의 차이를 보완하기 위한 번역 오버헤드를 최소화함과 동시에 보안성을 지키는 것이 가상화의 핵심 기술이며, 이를 어떻게 적용하느냐에 따라 가상머신의 오버헤드가 나뉩니다.
적용 기술

▲ 그림 3: 게스트 VM, 게스트 메모리, 게스트 디바이스의 관계
IOMMU
가상 머신에서는 게스트가 인식하는 메모리 주소와 실제 호스트의 물리 메모리 주소가 다릅니다. CPU가 게스트 메모리에 접근할 때 게스트의 가상 주소는 먼저 GPA(Guest Physical Address)로 변환되고, GPA는 EPT(Extended Page Tables) 또는 NPT(Nested Page Tables)를 통해 HPA(Host Physical Address)로 다시 변환됩니다.
하지만 PCIe 장치가 DMA를 시작할 때는 CPU의 EPT 또는 NPT 데이터 경로가 직접 개입하지 않습니다. 디바이스가 사용하는 DMA 주소는 IOVA(I/O Virtual Address)이고, 일반적인 패스스루 구성에서는 게스트의 GPA와 같은 값으로 매핑되는 경우가 많습니다. IOMMU는 PCIe 장치의 BDF(Bus, Device, Function)를 특정 IOMMU Domain에 연결하고, 해당 Domain의 페이지 테이블을 이용해 IOVA를 HPA로 변환합니다. 이를 통해 VM에 할당된 디바이스가 자신에게 매핑되지 않은 다른 VM이나 호스트의 메모리를 임의로 접근하지 못하도록 제한할 수 있습니다.
매 DMA 요청마다 페이지 테이블을 처음부터 탐색하면 비용이 크기 때문에 IOMMU에는 IOTLB(I/O Translation Lookaside Buffer)라는 주소 변환 캐시가 있습니다. 이전에 변환한 주소라면 IOTLB에서 결과를 바로 가져오고, 캐시에 없는 주소만 페이지 테이블 워크를 수행합니다. 고속 NIC처럼 매우 많은 DMA 주소를 사용하는 장치에서는 이러한 주소 변환 과정도 성능에 영향을 줄 수 있습니다.
ECI 적용 방식
게스트에 노출할 GPU, NIC, NVMe를 원래 드라이버에서 분리해vfio-pci에 바인딩합니다. VFIO는 Linux가 제공하는 패스스루 프레임워크로, 장치의 설정 공간과 MMIO 영역은 VMM이 직접 다루고 DMA는 IOMMU Domain을 거치도록 연결합니다. 호스트가 계속 사용하는 관리망 NIC와 NVSwitch 관리 인터페이스는 기존 드라이버에 그대로 두고, 패스스루 대상만 분리합니다.IOMMU가 없으면 VM에 할당된 장치가 호스트나 다른 VM의 메모리에 임의로 쓸 수 있습니다.게스트 드라이버가 지시하는 DMA는 CPU의 EPT나 NPT를 거치지 않기 때문에 별도의 통제가 필요합니다. 여러 사용자의 VM이 한 노드를 공유하는 환경에서는 이 경계가 곧 테넌트 사이의 격리 경계가 됩니다.
ATS
ATS(Address Translation Services)는 IOMMU의 주소 변환 결과를 PCIe Endpoint 쪽에서도 캐시할 수 있게 하는 기능입니다. ATS를 지원하는 디바이스는 실제 DMA를 보내기 전에 IOMMU에 Translation Request를 보내고, 반환받은 주소 변환 결과를 자신의 ATC(Address Translation Cache)에 저장합니다.
이후 같은 메모리 영역에 DMA를 수행할 때는 ATC에 저장된 변환 결과를 사용하고, PCIe TLP(Transaction Layer Packet)의 AT(Address Type) 필드에 이미 변환된 주소라는 정보를 표시해 전송합니다. 결과적으로 동일한 주소에 대해 IOMMU가 반복해서 주소 변환을 수행해야 하는 빈도를 줄일 수 있습니다.
즉 ATS는 IOMMU를 제거하는 기능이 아니라 IOMMU가 승인한 주소 변환 결과를 디바이스 쪽에도 캐싱해 반복적인 translation 비용을 줄이는 기능입니다. 특히 RDMA처럼 DMA 작업량이 크고 지연 시간에 민감한 환경에서는 이러한 차이가 중요해집니다.
ECI 적용 방식
ConnectX-8 에 ATS를 활성화합니다. ATS는 펌웨어 설정에서의 활성화가 필요하고, 실제로 적용됐는지는lspci -vvv의ATSCtl에서Enable+로 확인할 수 있습니다.ATS의 효과는 장치의 DMA 패턴에 따라 달라집니다. 같은 메모리 영역을 반복해서 사용하면 ATC 적중률이 높아 변환 비용이 크게 줄지만, 매번 다른 주소를 쓰면 Translation Request 자체가 추가 왕복이 됩니다. RDMA처럼 등록된 메모리 영역을 반복 사용하는 워크로드에서 이득이 큰 이유입니다.
ATS는 다음에 설명할 ACS 설정과 함께 동작합니다. PCIe TLP에 이미 변환된 주소라는 표시가 있어야 스위치가 그 요청을 Root Complex로 우회시키지 않고 바로 전달할 수 있기 때문입니다.
ACS
ACS(Access Control Services)는 PCIe 장치 사이의 P2P 트랜잭션 라우팅과 접근 제어를 담당합니다. 일반적으로 IOMMU가 DMA를 격리하려면 트랜잭션이 IOMMU가 위치한 Root Complex 방향으로 전달되어야 하지만, 같은 PCIe 스위치 아래의 두 장치가 P2P로 통신하면 요청이 스위치 내부에서 직접 전달될 수 있습니다.
멀티테넌트 환경에서는 서로 다른 VM에 할당된 장치가 동일한 PCIe 스위치를 공유할 수 있기 때문에 이 P2P 경로 역시 통제해야 합니다. ACS의 P2P Request Redirect와 같은 기능을 활성화하면 하위 장치 사이의 요청을 Root Complex 방향으로 리다이렉트할 수 있습니다. Linux가 여러 PCIe 장치를 독립적인 IOMMU Group으로 분리할 수 있는지 판단할 때도 이러한 PCIe isolation capability가 중요합니다.
반대로 모든 P2P 트래픽을 항상 Root Complex까지 올리면 B300에서 GPU와 NIC를 같은 PCIe Gen 6 스위치 아래 배치한 구조의 장점을 충분히 활용하기 어렵습니다. 이를 보완하기 위해 ATS로 이미 변환된 요청은 ACS Direct Translated P2P를 통해 스위치 내부에서 직접 전달할 수 있도록 구성합니다.[7] 이렇게 하면 DMA isolation을 유지하면서도 인접한 GPU와 NIC 사이에서는 짧은 PCIe 경로를 사용할 수 있습니다.
ECI 적용 방식
GPU와 ConnectX-8 상위 Bridge의 ACS 설정을 조정해 격리와 성능을 함께 확보합니다. 변환되지 않은 요청은 Root Complex 방향으로 리다이렉트해 IOMMU를 반드시 거치게 하고, ATS로 이미 변환된 요청만 Direct Translated P2P를 통해 스위치 내부에서 직접 전달합니다. 현재 설정은lspci -vvv의ACSCtl에서 확인할 수 있습니다.이 구성의 핵심은 두 경로를 구분한다는 점입니다. 변환을 거치지 않은 요청에는 짧은 경로를 허용하지 않으므로 격리 경계는 그대로 유지되고, IOMMU가 이미 승인한 요청은 Root Complex까지 올라갈 이유가 없으므로 인접한 GPU와 NIC 사이에서 PCIe Gen 6 경로를 그대로 사용할 수 있습니다.
반대로 ACS를 전부 켜서 모든 P2P를 Root Complex로 올리면 격리는 단순해지지만, B300에서 GPU와 NIC를 같은 Gen 6 스위치 아래 배치한 구조의 이점을 활용하기 어렵습니다. 어느 쪽을 택하든 IOMMU Group 분리 결과가 함께 달라지므로, 앞서 설계한 게스트 토폴로지와 맞는지 확인해야 합니다.
정리하면
- 게스트와 호스트는 다른 메모리 주소 공간을 사용하기 때문에, DMA에는 게스트 주소를 번역하는 계층이 필요합니다. 이 때 IOMMU 가 그 역할을 맡으며, 게스트 메모리 주소(IOVA)를 호스트 메모리 주소로 번역합니다.
- ATS는 게스트 메모리 주소(IOVA) 의 번역 결과를 디바이스의 번역 테이블에 캐싱해 반복 비용을 줄입니다.
- ACS는 IOMMU를 우회하는 P2P를 통제하되, 변환된 요청은 Direct Translated P2P로 직접 전달합니다.
성능 검증
기능 검증이 끝난 뒤 동일한 B300 노드에서 호스트와 게스트의 성능을 비교했습니다. 두 환경에서 GPU 드라이버, Fabric Manager, CUDA, NCCL, nccl-tests 버전을 동일하게 맞추고 같은 테스트 스크립트를 사용했습니다.
테스트 환경
| 호스트 | 게스트 | |
|---|---|---|
| Driver / Fabric Manager | 595.71.05 | 595.71.05 |
| CUDA | 13.3.73 | 13.3.73 |
| NCCL | 2.31.2 | 2.31.2 |
| NCCL-tests | 2.20.0 (b4d5bee) | 2.20.0 (b4d5bee) |
NCCL 테스트는 다음과 같이 실행했습니다.
mpirun -np 8 --bind-to none -x UCX_TLS=sm,self \
<collective>_perf -b 8 -e 8G -f 4 -g 1 -n 20 -w 5 -c 0
각 rank에 GPU 한 장을 할당해 총 8개의 프로세스로 실행했습니다. 메시지 크기는 8B부터 8GiB까지 4배씩 증가시키며 측정했고, 각 크기마다 5회의 warm-up 이후 20회를 측정했습니다. 5종의 collective benchmark를 한 세트로 총 3회 반복하고 각 결과의 중앙값을 사용했습니다.
NCCL 결과
다음 표는 가장 큰 메시지 크기에서 측정한 busbw의 3회 중앙값입니다. busbw는 NCCL이 collective 연산의 데이터 이동 특성을 반영해 계산하는 버스 대역폭 지표입니다. 단위는 GB/s이고, 차이는 (게스트 - 호스트) / 호스트로 계산했습니다. 음수이면 게스트의 성능이 낮아진 것이고, 양수이면 게스트가 더 높은 값을 기록한 것입니다.
alltoall과 sendrecv는 테스트 과정의 메모리 사용량 때문에 최대 1GiB까지 측정했습니다.
| collective | 호스트 | 게스트 | 차이 |
|---|---|---|---|
| all_reduce (8GiB) | 833.70 | 834.21 | +0.06% |
| all_gather (8GiB) | 666.50 | 666.51 | +0.00% |
| reduce_scatter (8GiB) | 688.78 | 688.42 | −0.05% |
| alltoall (1GiB) | 571.20 | 570.72 | −0.08% |
| sendrecv (1GiB) | 635.59 | 636.08 | +0.08% |
최대 메시지 크기에서 관찰된 가장 큰 성능 저하는 alltoall의 0.08%였습니다. 나머지 collective는 0.05% 이하의 저하를 보이거나 게스트가 호스트와 같거나 조금 더 높은 값을 기록했습니다.
각 collective의 구체적인 동작 방식은 이전 글인 InfiniBand vs RoCEv2 벤치마크 - 벤치마크 방법에서 설명하고 있습니다.
메시지 크기별 비교
최대 메시지 크기 하나만으로는 가상화 오버헤드의 특성을 충분히 확인할 수 없습니다. 작은 메시지에서는 고정 지연 시간이 상대적으로 크게 반영되고, 큰 메시지에서는 데이터 전송 대역폭이 성능을 더 크게 좌우하기 때문입니다. 따라서 32KiB 이상의 측정 지점을 작은 메시지와 대형 메시지 구간으로 나눠 비교했습니다.
| collective | 32 KiB - 2 MiB | 8 MiB 이상 |
|---|---|---|
| all_reduce | −0.6% - +0.2% | −0.3% - +0.5% |
| all_gather | −1.1% - +1.2% | 0.0% - +1.6% |
| reduce_scatter | −1.1% - +1.3% | 0.0% - +0.3% |
| alltoall | −8.6% - +3.5% | −0.5% - +1.5% |
가상화 오버헤드 관점에서 8MiB 이상의 대형 메시지 구간만 보면 가장 큰 성능 저하는 0.5%였습니다. all_gather와 reduce_scatter에서는 이 구간에서 게스트가 호스트보다 느린 측정값이 나타나지 않았고, all_reduce와 alltoall의 최대 저하도 각각 0.3%, 0.5%였습니다.
작은 메시지 구간에서는 변동 폭이 더 컸습니다. 특히 alltoall 128KiB에서 8.6%의 성능 저하가 한 차례 관찰됐습니다. 다만 인접한 메시지 크기에서는 같은 수준의 저하가 반복되지 않았기 때문에, 현재 결과만으로 지속적인 가상화 오버헤드라고 판단하기보다는 단일 측정 지점의 아웃라이어로 보고 있습니다.
nvbandwidth
앞의 NCCL 테스트는 단일 B300 서버 안에서 실행되므로 GPU 간 통신의 대부분이 NVLink와 NVSwitch를 통해 이루어집니다. 따라서 IOMMU가 포함된 PCIe DMA 경로의 오버헤드를 직접 확인하기 위해 NVIDIA의 nvbandwidth를 이용해 GPU 메모리와 CPU 시스템 메모리 사이의 전송 성능도 별도로 측정했습니다.
nvbandwidth에서는 다음 두 방향의 전송을 측정했습니다.
- H2D(Host-to-Device): CPU 측 시스템 메모리에서 GPU의 디바이스 메모리로 데이터를 전송하는 방향
- D2H(Device-to-Host): GPU의 디바이스 메모리에서 CPU 측 시스템 메모리로 데이터를 전송하는 방향
여기서 Host는 CPU가 사용하는 시스템 메모리, Device는 GPU의 메모리를 의미합니다.
| 항목 | 값 |
|---|---|
| 버전 | nvbandwidth v0.10.0 (git v0.10) |
| 빌드 | -DCMAKE_CUDA_ARCHITECTURES=103 |
| GPU Architecture | sm_103 |
| 경로 | 호스트 | 게스트 |
|---|---|---|
| H2D(Host-to-Device) 단방향 | 55.0 GB/s | 54.9 GB/s |
| D2H(Device-to-Host) 단방향 | 58.1 GB/s | 57.3 GB/s |
H2D에서는 약 0.2%, D2H에서는 약 1.4%의 성능 저하가 관찰됐습니다. 따라서 IOMMU가 실제 데이터 경로에 포함되는 GPU-CPU PCIe 전송에서도 측정된 최대 성능 저하는 약 1.4%였습니다.
이번 측정에는 GPU-NIC 사이의 PCIe Gen 6 및 RDMA 경로가 포함되지 않았습니다. 이 경로는 실제 네트워크 패브릭과 원격 GPU 노드가 구성된 뒤 별도로 측정할 예정입니다.
정리하면
- 단일 노드 NCCL 5종의 최대 메시지 크기에서 측정된 최대 성능 저하는 0.08%였습니다.
- 8MiB 이상 대형 메시지 구간에서 측정된 최대 성능 저하는 0.5%였습니다.
- 작은 메시지에서는 변동 폭이 커졌으며,
alltoall128KiB에서 8.6% 저하가 한 차례 관찰됐지만 인접 지점에서는 반복되지 않았습니다. - IOMMU가 데이터 경로에 포함되는 GPU-CPU PCIe 전송에서는 최대 1.4%의 성능 저하가 측정됐습니다.
- GPU-NIC PCIe Gen 6와 RDMA 경로는 네트워크 패브릭 구축 이후 별도의 테스트에서 검증할 예정입니다
마무리
B300을 ECI에 도입하면서 가장 중요하게 확인한 변화는 GPU와 NIC 사이의 PCIe 구조였습니다. ConnectX-8 내부에 PCIe Gen 6 스위치가 추가되면서 GPU와 NIC의 물리적 인접 관계가 이전 세대와 달라졌고, 가상화 환경에서도 이를 반영하도록 게스트의 PCIe 토폴로지를 다시 구성해야 했습니다.
이를 위해 호스트의 PCIe 계층을 분석하고 각 장치를 역할별로 라벨링한 뒤, GPU와 인접 NIC가 게스트에서도 가까운 장치로 인식되도록 토폴로지를 구성했습니다. 동시에 IOMMU와 ACS를 이용해 DMA와 P2P 경로를 격리하고, ATS와 Direct Translated P2P를 적용해 고속 데이터 경로에서 발생할 수 있는 불필요한 주소 변환과 우회 비용을 줄였습니다.
성능 검증에서는 단일 노드 NCCL의 최대 메시지 크기에서 가상화로 인한 최대 성능 저하가 0.08%, 8MiB 이상의 대형 메시지 구간에서는 최대 0.5%로 측정됐습니다. IOMMU가 실제 데이터 경로에 포함되는 GPU-CPU PCIe 전송에서는 최대 1.4%의 성능 저하가 관찰됐습니다. GPU-NIC PCIe Gen 6와 RDMA 경로는 네트워크 패브릭 구축 이후 별도로 검증할 예정입니다.
새로운 GPU 플랫폼을 클라우드 환경에 도입하는 작업은 서버를 설치하고 드라이버를 올리는 것만으로 끝나지 않습니다. PCIe 토폴로지, DMA isolation, IOMMU, NIC 펌웨어, 커널과 드라이버의 상호작용까지 전체 데이터 경로를 확인해야 하고, 가상화 환경에서는 물리적인 인접 관계를 게스트에 어떻게 표현할지도 직접 설계해야 합니다. 복잡한 데이터 경로를 직접 파고들어 해결하는 경험은 엔지니어로서 가치 있는 성장의 기회가 됩니다.
다음 글에서는 ConnectX-8 에 ATS를 적용하며 마주했던 이슈와 디버깅 과정, 그렇게 적용한 RDMA 루트에 대한 벤치마크 결과에 대해 소개하겠습니다.
참고
[1] https://networking-docs.nvidia.com/connectx8hw/port-configurations#PortConfigurations-C8180Port-SplittingConfigurations
[2] https://docs.nvidia.com/enterprise-reference-architectures/hgx-ai-factory/latest/networking-physical-topologies.html#multi-plane-topology-approach
[3] https://developer.nvidia.com/blog/nvidia-connectx-8-supernics-advance-ai-platform-architecture-with-pcie-gen6-connectivity/
[4] https://docs.nvidia.com/enterprise-reference-architectures/hgx-ai-factory/latest/components.html#nvidia-hgx-b300-systems
[5] https://docs.nvidia.com/ai-enterprise/planning-resource/optimizing-vm-configuration-ai-inference/latest/appendix.html#nccl - NCCL routing algorithm description
[6] https://docs.nvidia.com/deeplearning/nccl/archives/nccl_2162/user-guide/docs/env.html#nccl-p2p-level
[7] https://docs.nvidia.com/ai-enterprise/planning-resource/optimizing-vm-configuration-ai-inference/latest/appendix.html#configuring-acs - ACS config
[8] https://elixir.bootlin.com/linux/v6.8/source/drivers/iommu/intel/iommu.c#L1323
부록
용어 정리
| 용어 | 설명 |
|---|---|
| VM | 물리 컴퓨터 위에서 독립된 컴퓨터처럼 동작하는 실행 환경. 자체 커널과 드라이버를 가짐 |
| 하이퍼바이저 / VMM | VM을 생성·스케줄링하고 하드웨어 자원을 중재하는 계층 |
| 게스트 / 호스트 | VM 내부가 게스트, VM을 돌리는 물리 머신이 호스트 |
| MMU | CPU가 접근하는 가상 주소를 물리 주소로 변환하는 하드웨어 |
| EPT / NPT | 게스트 물리 주소(GPA)를 호스트 물리 주소(HPA)로 변환하는 2단계 페이지 테이블. CPU가 개시한 접근에만 적용됨 |
| IOMMU | 디바이스가 개시한 DMA의 주소를 변환·격리하는 하드웨어. Intel VT-d, AMD-Vi |
| IOTLB | IOMMU가 들고 있는 주소 변환 캐시 |
| ATS | 디바이스가 IOMMU에 변환을 미리 요청해 받아 두고, 이후 DMA를 이미 변환된 주소로 보내는 PCIe 기능 |
| ATC | ATS로 받아 온 변환 결과를 디바이스가 자기 안에 캐싱하는 저장소 |
| ACS | 같은 스위치 아래 장치 간 P2P 트랜잭션을 루트 컴플렉스로 올려 IOMMU를 거치게 하는 PCIe 기능. 장치를 개별 IOMMU 그룹으로 나눌 수 있게 함 |
| SR-IOV / PF / VF | 하나의 물리 PCIe 장치(PF)를 여러 개의 경량 가상 함수(VF)로 노출하는 기능. VF를 각 VM에 나눠 붙임 |
| VFIO | 리눅스가 제공하는 디바이스 패스스루 프레임워크 |
