Ga naar de hoofdinhoud

MI300X FP8 data-parallelle benchmarks (8 tot 64 GPU's): H200 achter zich, B200 binnen bereik

Door: ElioVP
31 juli 2025
Alle
MI300X FP8 data-parallelle benchmarks (8 tot 64 GPU's): H200 achter zich, B200 binnen bereik

Bij ElioVP willen we AI-inferentie tot het uiterste drijven en elke prestatie in een plug-and-play-runtime verpakken.

In ons vorige artikel toonde Paiton's FP8-pipeline op AMD's MI300X duidelijk betere resultaten dan NVIDIA's H200. Daarna gingen we opnieuw aan de slag.

Deze keer draaien we Llama-3.1-8B-Instruct-FP8-KV, een lichtere FP8-gekwantiseerde Llama-variant, niet op 8 GPU's maar op 64 virtuele GPU's die uit één MI300X-server zijn gepartitioneerd.

Met vLLM en Paiton's kerneloptimalisaties verwachtten we een bescheiden winst bij het opschalen van multi-tenancy. Het resultaat was veel sterker dan verwacht en kwam dicht bij een gelijkspel met NVIDIA's B200.

Waarom hebben we dit gedaan?

  • Maximale benutting: Partitioneer de hardware zodat elke tenant alleen betaalt voor precies het VRAM en de rekenkracht die nodig zijn.
  • Elastische multi-tenancy: Start geïsoleerde vGPU's in enkele seconden en vermijd vertraging door noisy neighbours en concurrentie om resources.
  • Granulaire SLA's: Pas de QoS per slice aan, ultralage latentie voor chatbots, bulkdoorvoer voor batchtaken, zonder te jongleren met hardware.
  • Kostenefficiënt schalen: Stem uw computeomgeving en budget nauwkeurig af door kleinere GPU-partities te huren in plaats van de volledige GPU.
  • Snelle CI/CD-provisioning: Integreer GPU-slices in uw pipeline voor directe A/B-tests, blue-green deployments en regressiebenchmarks.
  • Foutisolatie: Beperk OOM-fouten en driverproblemen tot één slice, zodat één problematische taak niet de volledige server stillegt.
  • Toekomstbestendige flexibiliteit: Herpartitioneer wanneer nodig om nieuwe modelgroottes of kwantisatieformaten te ondersteunen, zonder ingrijpende hardware-upgrade.

Met die bouwstenen op hun plaats onderzochten we hoe ver Paiton inferentie op een gepartitioneerde MI300X kon opschalen. De resultaten spreken voor zich.

Doelen

  • Evalueer de schaalbaarheid van Paiton op MI300X bij gebruik van GPU-partitionering.
  • Meet de latentie en doorvoer van Llama 3.1 8B in FP8-formaat met behulp van vLLM.
  • Valideer de geheugenefficiëntie en kernelfusievoordelen van plug-and-play Paiton-modellen.

Benchmarkopstelling en methodologie

Onze benchmarkingmethode volgt een duidelijke reeks regels en stappen. Dit zorgt ervoor dat onze tests open en reproduceerbaar zijn.

  • Hardwareconfiguratie:
    • 8x AMD MI300x
    • 8 x Nvidia H200
    • 8 x Nvidia B200
  • Inferentiebibliotheek:
    • AMD MI300x (Paiton): vLLM v0.9.0
    • AMD MI300x (AITER): v0.9.2
    • NVIDIA H200: v0.10.0 (V1-modus)
    • NVIDIA B200: v0.10.1 (V1-modus, vanuit de broncode gebouwd voor ondersteuning van de B200-architectuur)
  • Taalmodel: Llama-3.1-8B-Instruct-FP8-KV
  • Driverstapel:
    • AMD MI300x: ROCm 6.4.2
    • NVIDIA H200: CUDA 12.8.1
    • NVIDIA B200: CUDA 12.8.1
  • Framework:
    • AMD MI300x: Torch 2.7.1+rocm6.3
    • NVIDIA H200: Torch 2.7.1+cu128
    • NVIDIA B200: Torch 2.9.0.dev+cu128
  • Batchgrootte: 1024
  • Meetprotocol: elke benchmark werd 10 keer uitgevoerd en de cijfers die we rapporteren zijn algemene gemiddelden. Dit helpt het effect van tijdelijke systeemwijzigingen te verminderen. Onze zorgvuldige meetstappen omvatten:
    • Opstarttijden: belangrijk om te controleren hoe lang het duurt om het model te laden en het systeem gereed te maken.
    • Cold-Start TTFT (Time to First Token): meet hoe lang het duurt vanaf een nieuw verzoek totdat het eerste gegenereerde token verschijnt. Dit is van cruciaal belang voor hoe snel interactieve toepassingen reageren.
    • Steady-State TTFT: Controleert de TTFT nadat het systeem stabiel heeft gedraaid, waarbij typische prestaties bij constant gebruik worden weergegeven.
    • End-to-end-latencymetrics: geven een volledig beeld van de tijd voor een compleet inferentieverzoek, vanaf het verzenden van de input tot de uiteindelijke output.

Deze gedetailleerde methode biedt een goede manier om de specifieke prestatiegegevens van Paiton te controleren in drukke, gepartitioneerde GPU-omgevingen.

Gegevensparallellisme zonder partitionering

Eerst probeerden we vLLM's ingebouwde optie “–data-parallel-size” te gebruiken. Al snel bleek dat die niet meteen werkte en ingrijpende aanpassingen zou vereisen. Daarom kozen we een andere aanpak.

Om de benchmarks uit te voeren over 8 containers met behulp van vLLM, hebben we eerst de officiële NGINX-loadbalancing-gids gevolgd (https://docs.vllm.ai/en/stable/deployment/nginx.html)

  1. NGINX-configuratie

Dit is de load-balancingconfiguratie die we gebruikten in /etc/nginx/nginx.conf:

upstream backend {
    least_conn;
    server vllm0:8000 max_fails=3 fail_timeout=10000s;
    server vllm1:8000 max_fails=3 fail_timeout=10000s;
    server vllm2:8000 max_fails=3 fail_timeout=10000s;
    server vllm3:8000 max_fails=3 fail_timeout=10000s;
    server vllm4:8000 max_fails=3 fail_timeout=10000s;
    server vllm5:8000 max_fails=3 fail_timeout=10000s;
    server vllm6:8000 max_fails=3 fail_timeout=10000s;
    server vllm7:8000 max_fails=3 fail_timeout=10000s;
}

server {
    listen 80;
    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
  1. De Docker-containers lanceren

We hebben het volgende script gebruikt om 8 containers te starten met behulp van incrementele apparaat- en poortnummers:

#!/bin/bash

echo "Starting vLLM containers with incremental configuration…"

for i in {0..7}; do
    device_num=$((128 + (i * 8)))
    device_path="/dev/dri/renderD${device_num}"
    port=$((8080 + i))
    container_name="vllm${i}"

    echo "Starting container ${container_name} on port ${port} with device ${device_path}…"

    docker run -itd \
        –ipc host \
        -v /data:/data \
        –network vllm_nginx \
        -e VLLM_ROCM_USE_AITER=True \
        -e HF_HOME=root/.cache/huggingface \
        -e HF_HUB_CACHE=/root/.cache/huggingface/hub \
        –device=/dev/kfd \
        –device=${device_path} \
        –group-add video \
        -p ${port}:8000 \
        –name ${container_name} \
        rocm/vllm:latest \
        vllm serve \
        amd/Llama-3.1-8B-Instruct-FP8-KV \
        –num-scheduler-steps 10 \
        –kv-cache-dtype fp8 \
        –max-model-len 4096

    if [ $? -eq 0 ]; then
        echo "✓ Container ${container_name} started successfully"
    else
        echo "✗ Failed to start container ${container_name}"
    fi

    echo "—"
done

echo "All containers started. Summary:"
echo "Containers: vllm0 through vllm7"
echo "Ports: 8081 through 8088"
echo "Devices: renderD128 through renderD184 (in steps of 8)"

De regel device_num=$((128 + (i * 8))) was nodig door achtergebleven renderdevicevermeldingen in /dev/dri/ na eerdere GPU-partitionering. Ook na het resetten van de partities keerden de device-ID's niet terug naar hun oorspronkelijke waarden. Daarom moesten we elk devicepad verschuiven om naar de beschikbare rendernodes te verwijzen.

  1. Benchmarking

Ten slotte hebben we de volgende opdracht uitgevoerd om alle containers te benchmarken:

for i in {1..10}; do
    echo "=== Running benchmark iteration $i/10 ==="
    python3 ~/vllm/benchmarks/benchmark_serving.py \
      –backend vllm \
      –model amd/Llama-3.1-8B-Instruct-FP8-KV \
      –dataset-name sharegpt \
      –dataset-path ~/vllm/ShareGPT_V3_unfiltered_cleaned_split.json \
      –num-prompts 1024 \
      –random-range-ratio 1.0 \
      –percentile-metrics ttft,tpot,itl,e2el \
      –sharegpt-output-len 256
    echo "=== Completed iteration $i/10 ==="
    echo
done

Gegevensparallellisme met partitionering

De eerste cruciale stap was het partitioneren van onze GPU's.

Dit was heel eenvoudig en gemakkelijk te doen volgens de officiële documentatie van AMD.

Stappen:

  1. Stel de rekenpartities in.
sudo amd-smi set –gpu all –compute-partition CPX
  1. Stel de geheugenpartities in.
sudo amd-smi set –memory-partition NPS4

Wacht een paar seconden en klaar!

Resultaat:

Klaar voor gebruik!

Zoals vermeld in de vorige sectie hebben we, om de benchmarks uit te voeren over meerdere containers met behulp van vLLM, eerst de officiële NGINX load-balancing-handleiding gevolgd (https://docs.vllm.ai/en/stable/deployment/nginx.html)

  1. NGINX-configuratie

Hier is de taakverdelingsconfiguratie die we gebruikten in /etc/nginx/nginx.conf:

upstream backend {
    least_conn;
    server vllm0:8000 max_fails=3 fail_timeout=10000s;
    .
    .
    .
    server vllm63:8000 max_fails=3 fail_timeout=10000s;
}

server {
    listen 80;
    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}
  1. De Docker-containers lanceren

We hebben het volgende script gebruikt om 64 containers te starten met behulp van incrementele apparaat- en poortnummers:

#!/bin/bash

# Script to run vLLM containers with incremental device, port, and name changes
# Runs 64 containers with device=/dev/dri/renderD128 increasing in steps of 64
# Port starting at 8081 and increasing by 1 each time
# Container name starting at vllm0 and increasing by 1 each time

echo "Starting vLLM containers with incremental configuration…"

for i in {0..63}; do
    # Calculate device number (renderD128, renderD192, renderD256, etc.)
    device_num=$((128 + i))
    device_path="/dev/dri/renderD${device_num}"

    # Calculate port (8081, 8082, 8083, etc.)
    port=$((8081 + i))

    # Calculate container name (vllm0, vllm1, vllm2, etc.)
    container_name="vllm${i}"

    echo "Starting container ${container_name} on port ${port} with device ${device_path}…"
    docker run -itd \
        –ipc host \
        -v /data:/data \
        –network vllm_nginx \
        -e VLLM_ROCM_USE_AITER=True \
        -e HF_HOME=root/.cache/huggingface \
        -e HF_HUB_CACHE=/root/.cache/huggingface/hub \
        –device=/dev/kfd \
        –device=${device_path} \
        –group-add video \
        -p ${port}:8000 \
        –name ${container_name} \
        rocm/vllm:latest \
        vllm serve \
        /data/.cache/huggingface/hub/models–amd–Llama-3.1-8B-Instruct-FP8-KV/snapshots/fa42f9a9105c545755fea25cf69f49ac8c8b40e1/ \
        –num-scheduler-steps 10 \
        –kv-cache-dtype fp8 \
        –max-model-len 4096

    # Check if container started successfully
    if [ $? -eq 0 ]; then
        echo "✓ Container ${container_name} started successfully"
    else
        echo "✗ Failed to start container ${container_name}"
    fi

    echo "—"
done

echo "All containers started. Summary:"
echo "Containers: vllm0 through vllm63"
echo "Ports: 8081 through 8144"
echo "Devices: renderD128 through renderD4160 (in steps of 64)"
echo ""
echo "To check container status: docker ps"
echo "To view logs: docker logs <container_name>"
  1. Benchmarking

Hetzelfde script als in de vorige sectie.

De opstelling in actie:

Paiton MI300X

Standaard MI300X

Benchmarkresultaten

Zonder partities, 8 GPU's

MetricPaiton ∆Standaard∆ versus standaardH200∆ versus H200B200∆ versus B200
Benchmarkduur(en) ↓4.81211.029+129,20%11.84+146,05%4,59-4,61%
Verzoekdoorvoer (req/s) ↑213,5594.308+126,44%83,22+156,61%225,99–5,50%
Uitvoertokendoorvoer (tok/s) ↑53851.63923809.63+126,18%20940.86+157,16%56989.26-5,52%
Totale tokendoorvoer (tok/s) ↑101941.66745047.076+126,30%39674.51+156,94%107827.34-5,46%
Gemiddelde TTFT (ms) ↓543.7994252.513+682,47%3027.49+456,96%1245,55+129,05%
Gemiddelde TPOT (ms) ↓15.07516.872+11,92%26,70+77,02%10.27-31,87%
Gemiddelde ITL (ms) ↓15.02516.509+9,88%71.11+373,37%32,62+117,10%
Gemiddelde E2EL (ms) ↓4317.438403.948+94,65%9705.94+124,79%3818,69-11,51%

Met partities, 64 vGPU's

MetricPaiton ∆*Standaard∆ versus standaard (ratio)H200∆ versus H200
Benchmarkduur(en)7.87517.2942,20
Verzoekdoorvoer (req/s)130.23459.7272.18
Uitvoertokendoorvoer (tok/s)33339.93115047.1152,22
Totale tokendoorvoer (tok/s)62667.91428497,622,20
Gemiddelde TTFT (ms)1082.8856255.8795,78
Gemiddelde TPOT (ms)20,9931.2891,49
Gemiddelde ITL (ms)20,9931.131,48
Gemiddelde E2EL (ms)6435.47714067.7242.19

*Opmerking: we werken eraan om deze cijfers verder te verbeteren.

**Opmerking 2: dit is niet mogelijk met NVIDIA, of is op zijn minst erg moeilijk (meer informatie).

Laten we dit nu eens bekijken vanuit een ROI-gedreven perspectief.

Als de resultaten tot nu toe nog geen indruk op u hebben gemaakt, zal deze vergelijking dat vermoedelijk wel doen. We gebruiken de MI300X-server als referentie om kosten en doorvoer te vergelijken met de H200 en B200.

ArchitectuurKostenfactor versus PaitonKostenefficiëntie throughput*Kostenefficiëntie latency
MI300X+PaitonReferentieReferentieReferentie
Standaard MI300X1x+126,31%+94,57%
H2001.375x+253,30%+209,07%
B2002x+89,18%+77,02%
*Kostenefficiëntie van throughput: het percentage extra totale tokenthroughput per dollar ten opzichte van elk platform.**Kostenefficiëntie van latency: het percentage betere end-to-end-latency per dollar ten opzichte van elk platform.

Wat dit u vertelt

  • Paiton levert 2,5× de throughput per dollar ten opzichte van een H200 en 126% meer dan de standaardconfiguratie.
  • Latency per dollar is 3,1× beter dan bij de H200 en 94% beter dan bij de standaardconfiguratie. Elke bespaarde milliseconde draagt bij aan het rendement.
  • Het B200-gat is reëel, maar onthoud dat het tweemaal zoveel kost. Paiton wint over de hele linie nog steeds op het gebied van kostenefficiëntie.

Kosten per miljoen tokens

Als we de beschikbare huurprijzen voor de verschillende systemen gebruiken, kunnen we de relatieve kosten per 1 miljoen tokens berekenen:

ArchitectuurDoorvoer (tok/s)GPU-aantalOng. uurkostenInferentiekosten / 1M-tokensRelatieve kosten
MI300X+Paiton101941.667~8$ 20,50$ 0,06REF
Standaard MI300X45047.076~8$ 20,50$ 0,132,26× ↑
H20039674.51~8$ 28,20$ 0,203,54× ↑
B200107827.34~8$ 48,60$ 0,132,24× ↑

Inzichten:

  • Paiton levert 2,26× kostenbesparingen op vergeleken met de niet-geoptimaliseerde MI300X.
  • H200 kost 3,54× meer dan MI300X+Paiton per 1 miljoen tokens.
  • B200 is de duurste en kost meer dan 2,24× meer dan de geoptimaliseerde MI300X-installatie.

Grote overwinning voor AMD

Uitzoeken hoe MIG met vLLM op NVIDIA werkte, bleek bijzonder vermoeiend. Uiteindelijk liepen we vast op een NCCL-fout die onoplosbaar leek.

Hoewel MIG virtuele partities op ondersteunde NVIDIA GPU's toestaat, kwamen we, zoals eerder vermeld, aanzienlijke beperkingen tegen bij het proberen het te gebruiken in combinatie met vLLM voor data-parallelle workloads. Meer specifiek was vLLM niet in staat om MIG-plakken op de juiste manier te gebruiken voor gedistribueerde inferentie.

De AMD-architectuur maakte daarentegen een eenvoudige partitionering en gecontaineriseerde deployment van vLLM-instances mogelijk. Deze gestroomlijnde opstelling en ROCm-compatibiliteit maakten AMD direct veel geschikter voor echte multi-tenancy.

Dit vertegenwoordigt een grote overwinning voor AMD, vooral voor bedrijven die geïsoleerde inferentieworkloads op gedeelde hardware willen implementeren zonder al te veel wrijving of compromissen.

AMD heeft Intel methodisch voorbijgestreefd op het vlak van prestaties en is nu strategisch klaar om NVIDIA's leiderschap uit te dagen. We zijn er trots op die evolutie mee te ondersteunen.***Kian MohadjerinHoofd AI, Eliovp BV*

Belangrijkste resultaten

  • De throughput schaalde vrijwel lineair tot 64 partities, dankzij Paiton's minimale geheugenoverhead en snelle kerneldispatch.
  • De latency bleef stabiel tijdens parallelle sessies. Dat toont de kracht van Paiton's planning per GPU en optimalisaties voor gedeeld geheugen.
  • Het geheugengebruik per partitie lag aanzienlijk lager dan bij standaard vLLM of andere runtimes, waardoor deployments met hoge dichtheid mogelijk werden.
  • De kosten per miljoen tokens zijn met meer dan 2× verlaagd vergeleken met geavanceerde systemen zoals de B200, wat het vermogen van Paiton aantoont om toonaangevende efficiëntie te leveren, zelfs op meer betaalbare AMD-hardware.

Conclusie

Dit experiment toont hoe Paiton met geavanceerde packaging- en optimalisatietechnieken het volledige potentieel van moderne hardware zoals de MI300X ontsluit. Llama 3.1 8B FP8 uitvoeren over 64 GPU-partities laat zien dat inferentieworkloads op grote schaal parallel kunnen draaien zonder veel prestaties of bruikbaarheid op te offeren.

Stel u het potentieel voor van Paiton in combinatie met AMD's aankomende MI355X. Met nog meer geheugenbandbreedte, rekenkracht en architecturale verbeteringen kan de combinatie van next-generation hardware en de Paiton-runtime high-performance AI-serving opnieuw definiëren.

Blijf op de hoogte van toekomstige updates terwijl we de mogelijkheden van Paiton uitbreiden.

Wilt u onze resultaten zelf verifiëren? Test Paiton en vraag een evaluatiemodel aan.

Prijzen

Bent u benieuwd naar de prijzen van Paiton, dan is onze formule vrij eenvoudig:

50% van x% kosten bespaard per 1 miljoen tokens

We meten de kostenbesparing door de huidige throughput van de klant te vergelijken met de throughput na inschakeling van Paiton.

Neem contact op en laten we praten :)

Referenties

  1. Supermicro GPU-systeem AS-8125GS-TNMR2
  2. AMD Instinct MI300X
  3. Paiton FP8 verslaat Nvidia's H200 op AMD's MI300X
  4. ROCm/vllm GitHub
  5. vllm-project/vllm GitHub
  6. Hugging Face AMD Llama-3.1-8B-Instruct-FP8-KV
  7. vLLM Nginx-implementatie
  8. AMD GPU-partitioneringsdocumentatie
  9. ROCm Compute Memory-modi
  10. vLLM GitHub nummer 6551