Ladění jádra Linuxu pro servery s umělou inteligencí: Co vlastně hýbe jehlou

Výchozí jádro Ubuntu na HWE stacku 6.8 nebo 6.11 je dostačující pro zhruba 80 % úloh s umělou inteligencí. Tento článek se týká zbývajících 20 % – vícesocketového EPYC s osmi GPU, serverového serveru vLLM s... vm.max_map_count stěna pod zátěží nebo inferenční server, jehož latence ocasu je spotřebovávána přechody C-stavů CPU.

Většina veřejných rad ohledně „ladění Linuxu pro AI“ je recyklovanými radami z roku 2015 a jejich nezanedbatelný zlomek nenápadně zhoršuje latenci inference. Níže je uvedena menší, ale poctivá sada změn, které skutečně pomáhají na zařízeních třídy Kentino s K-AI (4–8 GPU na Xeonu nebo EPYC, Ubuntu 22.04 / 24.04, jádro 6.x). Předpokládá se, že ovladač a CUDA stack jsou nainstalovány podle... L01 a L02.

Poctivá hierarchie výher

Před jakýmikoli změnami v sysctl se zaměřte na velikost ceny:

Přeměna Typické vítězství v inferenci / trénování
Umístění procesů s ohledem na NUMA 10–30 % na vícezásuvkové krabice
Regulátor CPU performance (Od powersave) 5–15 % na servírovací krabice, nižší TTFT
Zakázání hlubokých C-stavů Mikrosekundy vypnutí P99, +30–50 W v klidu / patice
THP nastaveno na madvise 1–5 % na PyTorch, méně stání s odchodem zákazníků
vm.max_map_count, ulimit -n Zabraňuje převrácení servírování pod zátěží
Afinita IRQ k lokálnímu uzlu NUMA 5–15 % na síťových cestách DataLoader / RDMA
Velikost vyrovnávací paměti TCP (rmem_max, wmem_max) Záleží pouze pro úložiště/streamování >25 GbE
Vše ostatní 0–3 %, často šum

Pokud si z tohoto článku nic dalšího neodnesete: Dvěma velkými výhrami jsou povědomí o NUMA a regulátor CPU. Všechno ostatní je zaokrouhlovací chyba, pokud jste to neměřili.

Regulátor CPU: nejlevnějších 5–15 % na stole

Ubuntu je ve výchozím nastavení powersave (intel_pstate) nebo ondemand (acpi_cpufreq) v závislosti na ovladači. Oba reaktivně nastavují časování, což snižuje náklady na inferenční TTFT a na přípravu na straně CPU kolem dopředného průchodu vLLM – tokenizace, plánování, vzorkování logitů.

Pro servírovací krabici nastavte performance a zapomeňte:

sudo apt install -y cpufrequtils
echo 'GOVERNOR="performance"' | sudo tee /etc/default/cpufrequtils
sudo systemctl restart cpufrequtils

# Verify
for c in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do cat $c; done | sort -u

Na EPYC Genoa / Turin s jádrem 6.5+, amd-pstate řidič nahrazuje acpi-cpufreqStejný nápad, sada scaling_governor na performanceNovější amd-pstate-epp režim udržuje výkon a zároveň umožňuje zvýšení výkonu na jádro; ponechte EPP na performance, Ne balance_performance.

Upozornění: na trénovacím boxu s trvalým využitím GPU ~100% jsou CPU stejně zatíženy a regulátor je méně důležitý. Velkou výhodou jsou inferenční servery, které mezi požadavky nečinně fungují a potřebují okamžitě nastartovat.

NUMA: rozdíl mezi rychlým a průměrným EPYC boxem

Jednosocketové servery Xeon nebo EPYC nemají o čem přemýšlet – jeden uzel NUMA, každý přístup k paměti je lokální. Dvousocketové servery jsou místem, kde žije těch 10–30 %.

Výchozí plánovač s radostí umístí vLLM worker na socket 0 a přesměruje ho do paměti alokované na socketu 1 pomocí page fault – každé načítání je cross-socket UPI / Infinity Fabric hop. Pro model se stovkami GB vah procházených jednou na token je to reálné.

Kontrolovat:

numactl --hardware                            # node count, sizes, distance matrix
nvidia-smi topo -m                            # GPU↔CPU NUMA affinity
cat /sys/class/net/<iface>/device/numa_node   # NIC NUMA affinity

Vzor, který chcete – a který NCCL detekuje automaticky – je GPU N připnutý k uzlu NUMA, který hostuje jeho kořenový komplex PCIe, nikoli k druhému socketu. Pro ručně spuštěný inferenční proces připněte CPU i paměť k lokálnímu uzlu:

# vLLM on a 2-socket EPYC, GPUs 0–3 on NUMA node 0
numactl --cpunodebind=0 --membind=0 \
  python -m vllm.entrypoints.openai.api_server \
  --model meta-llama/Llama-3.3-70B-Instruct --tensor-parallel-size 4

Dva související knoflíky:

  • kernel.numa_balancing migruje stránky směrem k CPU, které se jich dotýká. Užitečné pro obecné úlohy, občas kontraproduktivní pro AI: předběžné vyplnění jednou projde váhy, jádro migruje stránky a další požadavek je stáhne zpět. Ve výchozím nastavení ponechte zapnuto (1); pokud jitter koreluje s numa_pte_updates in /proc/vmstat, Snaž se sysctl kernel.numa_balancing=0.
  • NCCL na dvouzásuvce — sada NCCL_SOCKET_IFNAME k manažerské síťové kartě a NCCL_IB_HCA k síťové kartě (NIC) na stejném uzlu NUMA jako grafické karty (GPU). Špatná síťová karta tiše snižuje propustnost mezi uzly na polovinu.

Jednosocketový server EPYC 9004/9005: celou tuto část ignorujte.

Průhledné obrovské stránky: madvise, Ne always

THP oportunisticky skládá 4KB stránky do 2MB stránek, čímž snižuje tlak na TLB. PyTorch a ovladač CUDA z toho profitují jen mírně. Past je v tom, že... always režim při chlazení paměti — jádro zastaví vlákno na 50–100 ms, čímž zhutní paměť a torpéduje tak jakékoli SLO s latencí.

Správné nastavení je madvise: aplikace, které vědí, co dělají, volají madvise(MADV_HUGEPAGE) na dlouhodobých alokacích a získává THP; nic jiného to nedělá. Nastaveno pomocí /etc/default/grub:

GRUB_CMDLINE_LINUX_DEFAULT="... transparent_hugepage=madvise"

update-grub && rebootDefragmentace by měla odpovídat — defer+madvise umožňuje zhutnění probíhat na pozadí, nikoli v cestě alokačního vlákna:

echo defer+madvise | sudo tee /sys/kernel/mm/transparent_hugepage/defrag

Pro produkční prostředí vLLM / SGLang / TensorRT-LLM, madvise je správná výchozí hodnota. PyTorch s CUDA Unified Memory (výzkumný kód) někdy těží z always – před otočením změřte.

Explicitní 1 GB obrovské stránky: pouze pokud jste změřili

Explicitní obrovské stránky rezervované při bootování přes hugetlbfs poskytnout malou dodatečnou výhodu pro velmi velké váhy LLM eliminací chyb TLB při skenování vah. Háček: paměť je rezervována předem a není k dispozici zbytku systému, aplikace musí být sestavena tak, aby ji používala, a zisk je 1–3 % pro většinu obslužných úloh.

GRUB_CMDLINE_LINUX_DEFAULT="... default_hugepagesz=1G hugepagesz=1G hugepages=64"

Stojí to za to pro TensorRT-LLM box, kde se engine vejde do zapnuté paměti a vy se honíte za posledními procenty TTFT. Nestojí to za to pro obecný vLLM server, který přepíná modely nebo jakýkoli trénovací box. Přeskočit při prvním sestavení; vraťte se pouze, pokud perf stat -e dTLB-load-misses ukazuje tlak TLB a máte rezervu v RAM.

vm.max_map_count a nofile: stěny, které vLLM zasahuje ve velkém měřítku

Automaticky vm.max_map_count v Ubuntu je to 65530 – počet různých mapování paměti, které může proces uchovávat. vLLM obsluhující rozsáhlý model s vysokou souběžností nebo jakýkoli framework využívající mnoho mmapstřepy safetensoru, proletí kolem a umírá Cannot allocate memoryHodnota 262144 odvozená z Elasticsearch je naprosté minimum; pro vLLM obsluhující 70B+ se stovkami souběžných sekvencí je třeba nastavit hodnotu 1048576. Nic to nestojí – jde o měkký limit, ne o rezervaci.

Automaticky ulimit -n na Ubuntu je to 1024. Komicky málo: vLLM, Triton, PyTorch DataLoader workers, NCCL a vrstva gRPC mezi nimi otevírají stovky FD. Dosáhnete limitu a dostanete EMFILE: too many open files a proces, který se tiše zasekává.

# /etc/sysctl.d/99-ai-server.conf
vm.max_map_count = 1048576

# /etc/security/limits.d/99-ai-server.conf
*    soft    nofile  1048576
*    hard    nofile  1048576

# /etc/systemd/system.conf.d/99-limits.conf
[Manager]
DefaultLimitNOFILE=1048576

sudo sysctl --system a systemctl daemon-reexecOvěřte u ulimit -n a cat /proc/<pid>/limits.

Afinita IRQ: připínání přerušení síťové karty k lokálním CPU

Na 100GbE síťové kartě ConnectX-6/7, která podporuje streamování datových sad nebo provoz RDMA s rychlostí přes 10 GB/s, musí přerušení přistát na procesorech (a) na stejném uzlu NUMA jako síťová karta a (b) ne na stejných jádrech, na kterých běží workery DataLoader. Výchozí nastavení irqbalance odvádí přijatelnou práci; při velké zátěži ne.

Nejčistší řešení je od Mellanoxu. set_irq_affinity.sh od mlnx-tools:

sudo systemctl disable --now irqbalance
sudo /usr/sbin/set_irq_affinity.sh enp1s0f0                  # all NIC-local cores
sudo /usr/sbin/set_irq_affinity_cpulist.sh 4-11 enp1s0f0     # pin to specific cores

Špatným krokem je odejít irqbalance běží na krabici, kterou jste také ručně připnuli – bojují. Vyberte si jednu. Obsluhující krabice s jednou nebo dvěma RDMA síťovými kartami: ručně připnout, zakázat irqbalanceUniverzální krabice s mnoha rozhraními: nechte irqbalance na s --banirq vyloučit kritickou síťovou kartu.

Vyrovnávací paměti síťového jádra: pouze pro rychlé úložiště / streamovací cesty

Pro inferenční server s jedním uzlem, který komunikuje s klienty přes prostý TCP s nízkou rychlostí, je výchozí net.core.rmem_max / wmem_max 208 KB je v pořádku. Pro uzel stahující trénovací data ze 100GbE NFS nebo úložiště objektů, nebo pro frontend vLLM za vyrovnávačem zátěže s vysokým RPS jsou výchozí hodnoty maximální hodnotou pro váš produkt s ohledem na zpoždění šířky pásma. Výchozí sada pro zařízení připojené ke 100GbE:

# /etc/sysctl.d/99-ai-network.conf
net.core.rmem_max = 268435456
net.core.wmem_max = 268435456
net.ipv4.tcp_rmem = 4096 87380 268435456
net.ipv4.tcp_wmem = 4096 65536 268435456
net.core.netdev_max_backlog = 250000
net.core.somaxconn = 65535

Maximálně 256 MB je pro rackový 100 GbE (BDP je ~1.25 MB) přehnané, ale neškodné – automatické ladění TCP zvětšuje vyrovnávací paměti pouze podle potřeby až do limitu. U RDMA (RoCE / IB) pro datovou cestu tyto knoflíky nehrají roli – RDMA obchází kernelový TCP stack. Stále hrají roli pro rovinu správy, NFS a stahování modelů.

C-stavy: latence vs. klidový výkon

U obslužného zařízení citlivého na latenci je nejlevnějším zlepšením latence ocasu po regulátoru CPU zakázání hlubokých C-stavů. Vstup/výstup C6 je v desítkách mikrosekund; u požadavku, který by měl odpovědět do 30 ms, přidává CPU vycházející z C6 pro zpracování vzorkování po tokenu znatelný jitter.

GRUB_CMDLINE_LINUX_DEFAULT="... intel_idle.max_cstate=1 processor.max_cstate=1"

update-grub && rebootOvěřte u cpupower idle-info — k dispozici by měly být pouze C0 a C1. Cena: 30–50 W klidového výkonu na zásuvku protože jádra nikdy nepřecházejí do hlubokého spánku. Na dvoupaticovém serveru s 8 GPU je to 60–100 W trvalé režie – nepatrné oproti 3.5–4.5 kW trvalé spotřeby GPU při zátěži.

Použijte pro inferenční servery citlivé na latenci a robotické cesty v reálném čase. Přeskočte trénovací boxy (latence nehraje roli, spotřeba energie v nečinnosti se sčítá za měsíce) a dávkové úlohy.

Ladění jádra související se souborovým systémem (náhled na L04)

Několik fs.* sysctls záleží:

fs.aio-max-nr = 1048576              # default 65536 too low for vLLM weight loaders
fs.inotify.max_user_watches = 524288 # tooling that watches checkpoint dirs

fs.aio-max-nr je ten, co kouše – frameworky provádějící asynchronní I/O s mnoha shardy (DALI, zavaděče hmotnosti vLLM) u velkých modelů propalují výchozí hodnotu 65536. Samotná volba souborového systému (XFS vs ZFS vs ext4), možnosti připojení a O_DIRECT sémantika žije v L04.

Zakázání nepotřebných modulů jádra

Bezhlavý server nemá žádné moduly pro načítání bluetooth, zvuku, webkamery, bezdrátového připojení, joysticku ani tiskového serveru. Každý z nich představuje více kódu v útočné ploše a malé zpoždění při spouštění. Jednotlivě triviální; kolektivně je o čistším serveru snazší uvažovat.

# /etc/modprobe.d/blacklist-ai-server.conf
blacklist bluetooth
blacklist btusb
blacklist snd_hda_intel
blacklist uvcvideo
blacklist joydev

# Plus
sudo systemctl disable --now bluetooth.service cups.service avahi-daemon.service \
                              ModemManager.service whoopsie.service apport.service

Bootování se u typické sestavy EPYC sníží z ~30 s na ~10 s. lsmod stává se čitelným. Nulový dopad na výkon inference, mírné snížení plochy útoku.

Dva profily: inference vs. trénování

Tvar ladění je skutečně odlišný. Náčrty pro zasunutí:

Inference (/etc/sysctl.d/99-ai-inference.conf)

vm.max_map_count = 1048576
vm.swappiness = 1
vm.overcommit_memory = 1
kernel.numa_balancing = 1
fs.aio-max-nr = 1048576
net.core.rmem_max = 268435456
net.core.wmem_max = 268435456
net.ipv4.tcp_rmem = 4096 87380 268435456
net.ipv4.tcp_wmem = 4096 65536 268435456
net.core.netdev_max_backlog = 250000
net.core.somaxconn = 65535

Navíc na příkazovém řádku jádra: transparent_hugepage=madvise intel_idle.max_cstate=1 processor.max_cstate=1Guvernér: performance. IRQ síťových karet připnuté k lokálním jádrům NUMA, irqbalance vypnuto.

Školení (/etc/sysctl.d/99-ai-training.conf)

vm.max_map_count = 1048576
vm.swappiness = 1
vm.overcommit_memory = 1
kernel.numa_balancing = 0       # page migration mid-epoch is just churn
fs.aio-max-nr = 1048576
fs.inotify.max_user_watches = 524288
net.core.rmem_max = 536870912
net.core.wmem_max = 536870912
net.ipv4.tcp_rmem = 4096 131072 536870912
net.ipv4.tcp_wmem = 4096 131072 536870912

Příkazový řádek jádra: transparent_hugepage=madvise (přeskočit pinning C-state – trénink je omezen propustností, spotřeba v klidu se v průběhu týdnů sčítá). Regulátor: performance pokud máte dostatečný rozpočet. NCCL je připnutý k místní NUMA přes NCCL_IB_HCA.

Past „Všechno jsem naladil a ono se to zpomalilo“

Nejčastějším způsobem selhání je výpis z cargo-cultu: zkopírovat sto sysctlů z blogového příspěvku, restartovat, pozorovat horší výkon a netušit, kterým knoflíkem uvolnit. Metoda, která funguje:

  1. Stanovení základní linie – nccl-tests all_reduce_perf, vLLM benchmark_throughput.py, čas tréninkového kroku. Zapište si čísla.
  2. Změň jednu věc.
  3. Znovu spusťte stejný benchmark třikrát pro měření šumu.
  4. Pokud je medián významně lepší, ponechte jej. Pokud ne, vraťte jej zpět.
  5. Změnu a důvod zdokumentujte ve správě verzí vedle souboru sysctl.

Viděli jsme produkční boxy se 40 řádky ladění sysctl, které byly dohromady o 2 % pomalejší než výchozí nastavení Ubuntu – každá jednotlivá změna byla neutrální nebo horší, ale operátor si byl jistý, že „ladění pomohlo“.

Červený klobouk tuned 2.27 lodí explicitně ai-inference a ai-training profily a je to důvěryhodná zkratka na RHEL / Rocky. Ubuntu ji nedodává; apt install tuned funguje, ale je méně propracované. V Ubuntu ručně vkládané drop-iny v /etc/sysctl.d/ a čistý příkazový řádek GRUBu se snáze audituje a přesně víte, co je nastaveno.

Co dělat dál

Rozumná sekvence ladění jádra pro novou sestavu Kentino K-AI, seřazená podle priority:

  1. Nastavte regulátor CPU na performance. Ověřte u cpupower frequency-infoNejvětší výhra bez jakýchkoli nákladů.
  2. Běh numactl --hardware a nvidia-smi topo -m. Před jakýmkoli připojením si promyslete topologii. U dvoupaticových boxů si naplánujte, které grafické karty budou patřit kterému uzlu NUMA.
  3. sada vm.max_map_count a nofile omezení. Tyto metody zabraňují selháním, nikoli zpomalení. Proveďte je před prvním spuštěním výroby.
  4. sada transparent_hugepage=madvise na příkazovém řádku jádra.
  5. Pin NIC IRQ k lokálnímu uzlu NUMA síťové karty s set_irq_affinity.sh. Zakázat irqbalance pokud jste tak učinili.
  6. Pouze pro inferenční rámečky: zakázat hluboké C-stavy pomocí intel_idle.max_cstate=1 processor.max_cstate=1.
  7. Ladění síťových vyrovnávacích pamětí pouze pokud jste naměřili úzké hrdlo na úložné nebo streamovací trase 25/100 GbE.
  8. Přeskočit 1 GB explicitních obrovských stránek pokud nemáte benchmark ukazující tlak TLB.
  9. Benchmark před a po každé změně. Jedna věc po druhé. Dokument.

Křížové odkazy: L01 pro připínání ovladačů a jádra, L02 pro CUDA / kontejnerový stack, L04 pro vrstvu souborového systému, L05 pro sledování.

Ladění jádra v moderním Linuxu je většinou jednorázová konfigurace, nikoli průběžná optimalizační hra. Správně nastavte governor, umístění NUMA a limity. Zbytek přeskočte, pokud váš benchmark neříká jinak.


Toto je součást Kentino Wiki, referenční série o výpočetní technologii s využitím umělé inteligence, robotice a systémech, které je propojují. Komentáře a opravy jsou vítány na adrese info@kentino.com.