Wat ASPM doet
PCIe Active State Power Management (ASPM) laat PCIe-links naar laagvermogenstoestanden gaan als ze niets te doen hebben. De PCIe-specificatie definieert een aantal linktoestanden:
L0 is de volledig actieve toestand. De link staat, beide kanten hebben spanning, data kan er direct door.
L0s is een lichte rusttoestand. De link gaat deels uit. Herstel naar L0 kost ongeveer 1–4 µs, afhankelijk van de hardware. Beide kanten kunnen los van elkaar naar L0s.
L1 is een diepere rusttoestand. Beide kanten van de link gaan samen uit. Herstel naar L0 kost langer — doorgaans 2–32 µs, soms meer. De precieze hersteltijd hangt af van het apparaat, de PCIe-generatie en het platform.
L1.1 en L1.2 zijn subtoestanden van L1, geïntroduceerd in PCIe 3.0. Ze drukken het vermogen verder terug door de PLL-klokreferentie uit te zetten. Herstel uit L1.2 kan 32–100 µs kosten. Voor een opslagapparaat is dat geen afrondingsfout. Dat is ongeveer even lang als de read die je in de eerste plaats wilde doen.
Het idee is rechttoe rechtaan. Ligt een PCIe-link een paar microseconden stil, zet hem dan in een lagere vermogenstoestand. Trekt het verkeer weer aan, maak hem dan wakker. Bespaar er ondertussen een beetje vermogen mee.
Op een laptop of een desktop die het grootste deel van de tijd niets doet, bespaart ASPM echt vermogen. Een paar watt per link, opgeteld over alle PCIe-apparaten in het systeem. Op een server met IO-intensieve workloads liggen de links zelden lang genoeg stil om ASPM zinvol te laten aanslaan.
Waarom het problemen geeft bij passthrough
Op bare metal onderhandelen het besturingssysteem en de apparaatdriver het energiebeheer samen. De NVMe-driver weet wanneer de link stil komt te liggen en wanneer hij nieuwe IO gaat aanbieden. Het PCIe-subsysteem van de kernel stemt de overgangen van linktoestanden af met de driver. Alles loopt in de maat.
Onder VFIO-passthrough valt die afstemming weg.
De hostkernel bestuurt nog steeds de fysieke PCIe-link. De gast-VM bezit het apparaat via VFIO, maar bestuurt de link zelf niet. Het PCIe-subsysteem van de host ziet de link stil komen te liggen — want vanuit de host bekeken gebruikt geen enkele driver aan hostkant hem. Het zet de link in een laagvermogenstoestand. Zodra de gast IO aanbiedt, heeft het apparaat de link terug nodig in L0. De hersteltijd komt naar boven als extra latency op die IO-bewerking.
Het resultaat is wisselvallige latency.
De meeste IO’s ronden op normale snelheid af.
Sommige duren veel langer, omdat ze een link treffen die in L1 of L1.2 staat en eerst wakker moet worden.
Dat komt naar boven als een brede spreiding in je clat-percentielen (completion latency).
Het gemiddelde kan er prima uitzien.
De p99 kan 5–10x hoger liggen.
Dit is moeilijk te zien, omdat de cijfers voor gemiddelde doorvoer er prima uit kunnen zien. Je ziet het probleem pas als je naar de staartlatency kijkt. Veel benchmarks lichten die niet uit tenzij je om percentieluitvoer vraagt.
De VFIO-specifieke haak
Er zit hier een haak aan die verder gaat dan het simpele probleem van “host en gast die vechten over de linktoestand”.
Zodra een apparaat op de host aan vfio-pci is gebonden, weet de hostkernel dat het apparaat in passthroughmodus staat.
Maar het PCIe-ASPM-beleid wordt op linkniveau toegepast, niet op apparaatniveau.
Het ASPM-beleid van de host geldt nog steeds voor de fysieke link, omdat de host nog steeds de PCIe-topologie bezit.
VFIO onderschept of overstemt ASPM-overgangen niet. Het geeft de BAR-ruimte en de interrupts van het apparaat door, maar het energiebeheer van de link blijft onder de host vallen. De gast heeft geen enkel middel om tegen de host te zeggen “houd deze link in L0”.
Sommige nieuwere hardware en kernelversies gaan hier beter mee om dan andere. De veiligste aanpak is dan ook om ASPM helemaal buiten beeld te halen.
Hoe je het uitzet
Zet pcie_aspm=off op de kernelregel van de host:
# Edit /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="quiet pcie_aspm=off"
# Update GRUB and reboot
update-grub
reboot
Dit belet de host om ook maar één PCIe-link in een laagvermogenstoestand te zetten. Het geldt overal. Elk PCIe-apparaat op de host, niet alleen degene die je doorgeeft.
Controleer het na een herstart:
# Should show "ASPM Disabled" for all devices
lspci -vv | grep -i "ASPM"
Wat het aan vermogen kost
ASPM uitzetten verhoogt het stationaire vermogensgebruik wel. Elke PCIe-link die anders in L1 zou staan blijft in L0 en gebruikt een paar honderd milliwatt meer. Over een systeem met tien of vijftien PCIe-apparaten kan dat oplopen tot 2–5 watt in rust.
Voor een server in een datacenter is 2–5 watt een afrondingsfout op de energierekening. Voor een homelab is het een fractie van wat de CPU en het geheugen gebruiken. Voor een laptop maakt het uit. Maar je zou geen VFIO-passthrough doen op een laptopaccu.
De afweging is duidelijk. Een paar watt stationair vermogen tegenover onvoorspelbare latencypieken op je doorgegeven apparaten. Op elk systeem dat passthrough doet, hoort ASPM uit te staan.
Problemen met vermogenstoestanden op apparaatniveau
ASPM bestuurt de vermogenstoestand van de PCIe-link. Apparaten hebben ook hun eigen energiebeheer — de PCIe D-toestanden (D0 tot en met D3).
Staat een apparaat in D3 (volledig uit), dan slaapt niet alleen de link. Het apparaat zelf is gestopt.
Onder VFIO-passthrough kan de vfio-pci-driver van de host het apparaat in D3 zetten als de VM niet draait, of als het energiebeheer van de host besluit dat het apparaat stil ligt.
Sommige NVMe-controllers gaan niet netjes om met de overgang van D3 naar D0. Ze komen niet schoon terug, de gast verliest het apparaat, en de enige uitweg is een herstart van de VM of soms een herstart van de host.
De Samsung 990 EVO Plus is een bekende zondaar.
De oplossing is de module-optie disable_idle_d3 voor vfio-pci:
# /etc/modprobe.d/vfio.conf
options vfio-pci disable_idle_d3=1
Dit belet vfio-pci om een gebonden apparaat in D3 te zetten als het stil ligt.
Net als pcie_aspm=off is het een instelling voor alles. Elk apparaat dat aan vfio-pci is gebonden blijft in D0.
Dat is meestal wat je wil bij passthrough, waar de gast het enige zou moeten zijn dat de vermogenstoestand van het apparaat bepaalt.
De optie disable_idle_d3 staat los van ASPM.
ASPM bestuurt de link.
D3 bestuurt het apparaat.
Beide kunnen los van elkaar problemen geven.
Voor een schone passthroughconfiguratie zet je ze allebei uit.
ASPM per apparaat regelen
Wil je ASPM niet overal uitzetten — misschien heb je andere PCIe-apparaten op de host die wél iets aan energiebesparing hebben — dan kun je ASPM per link regelen via sysfs:
# Find the link's ASPM policy
cat /sys/bus/pci/devices/0000:XX:00.0/link/l1_aspm
# Disable ASPM for a specific link
echo 0 > /sys/bus/pci/devices/0000:XX:00.0/link/l1_aspm
Dit is doelgerichter, maar minder betrouwbaar over herstarts en kernelupdates heen.
Voor de meeste passthroughopstellingen is de kernelvlag pcie_aspm=off voor alles eenvoudiger en voorspelbaarder.
Wanneer ASPM niet het probleem is
Niet elk geval van latencyjitter is ASPM.
Zijn je clat-percentielen structureel hoog (niet alleen de staart), dan is het probleem eerder overhead van IOMMU-vertaling, verkeerde NUMA-uitlijning of een MPS die niet klopt.
ASPM veroorzaakt specifiek een tweetoppig patroon — de meeste IO’s zijn snel, een paar zijn langzaam — omdat het alleen de IO’s raakt die toevallig aankomen terwijl de link in een laagvermogenstoestand staat.
Kijk eerst naar ASPM als je dit ziet:
- p99-latency 5x of meer hoger dan het gemiddelde
- Wisselvallige
fio-uitkomsten tussen runs - Latency die beter wordt onder aanhoudende belasting maar slechter bij hakkelige workloads
Is de latency structureel slecht, wat het belastingspatroon ook is, kijk dan elders. ASPM is het waard om vroeg uit te sluiten, omdat het goedkoop te testen is. Maar het is niet het antwoord op elke langzame link, en het najagen terwijl de cijfers niet bij het patroon passen is een middag die je niet terugkrijgt.
Bronnen
- Linux kernel PCI documentation — ASPM parameters — kernelbron over
pcie_aspm=offen verwante opties - Proxmox Forum — PCI Passthrough NVMe Unable to Change Power State — draadje uit de community over
disable_idle_d3voor NVMe-controllers van Samsung - Proxmox VE Wiki — PCI(e) Passthrough — officiële documentatie over het inrichten van passthrough