<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>P2p on lo0 — Blog Técnico</title><link>https://blog.lo0.es/tags/p2p/</link><description>Recent content in P2p on lo0 — Blog Técnico</description><generator>Hugo -- gohugo.io</generator><language>es</language><lastBuildDate>Mon, 08 Jun 2026 06:00:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/tags/p2p/index.xml" rel="self" type="application/rss+xml"/><item><title>Los pasillos y el guardia de seguridad: topología PCIe, GPUDirect P2P y ACS</title><link>https://blog.lo0.es/posts/pcie-topology-gpudirect-p2p-acs/</link><pubDate>Mon, 08 Jun 2026 06:00:00 +0200</pubDate><guid>https://blog.lo0.es/posts/pcie-topology-gpudirect-p2p-acs/</guid><description>&lt;blockquote>
&lt;p>Sigue la serie &lt;em>por debajo del motor&lt;/em>. El &lt;a href="https://blog.lo0.es/posts/nvlink-nvswitch-nccl-tensor-parallel/">post de NVLink y NCCL&lt;/a> explicó la &lt;em>mesa compartida&lt;/em> por la que las GPUs se pasan datos a 450 GB/s. Pero esa mesa solo conecta GPUs entre sí. Todo lo demás —disco, red, el host— viaja por &lt;strong>otro bus&lt;/strong>, el PCIe, y por sus pasillos. El &lt;a href="https://blog.lo0.es/posts/del-disco-a-la-hbm-cold-start-carga-modelo/">cold start&lt;/a> ya rozó esto con GPUDirect Storage; este post abre el plano completo de los pasillos y el guardia que los vigila.&lt;/p>
&lt;/blockquote>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>En un nodo de &lt;strong>4×H100 SXM&lt;/strong>, las GPUs se hablan por &lt;strong>NVLink&lt;/strong> (450 GB/s por sentido, ~7× el PCIe), y para el all-reduce del &lt;a href="https://blog.lo0.es/posts/nvlink-nvswitch-nccl-tensor-parallel/">tensor parallel&lt;/a> ese es el camino. Pero el &lt;strong>PCIe&lt;/strong> no desaparece: es por donde entra todo lo demás. Los pesos suben del &lt;strong>NVMe&lt;/strong> por PCIe (el &lt;a href="https://blog.lo0.es/posts/del-disco-a-la-hbm-cold-start-carga-modelo/">cold start&lt;/a>), los datos de otro nodo llegan por la &lt;strong>NIC&lt;/strong> por PCIe (RDMA), y un KV que se mueve entre nodos viaja por PCIe. &lt;strong>GPUDirect&lt;/strong> es la familia que deja que esos bytes vayan &lt;strong>directos del dispositivo a la HBM&lt;/strong> sin rebotar por la RAM del host: &lt;strong>P2P&lt;/strong> (GPU↔GPU), &lt;strong>RDMA&lt;/strong> (GPU↔NIC) y &lt;strong>Storage&lt;/strong> (GPU↔NVMe). El obstáculo es un guardia llamado &lt;strong>ACS&lt;/strong> (Access Control Services): una feature de seguridad del PCIe que por defecto obliga al tráfico &lt;em>peer-to-peer&lt;/em> a &lt;strong>subir hasta el root complex&lt;/strong> para inspección, lo que destruye el camino directo y mete un rodeo por la CPU. El &lt;strong>IOMMU&lt;/strong> (VT-d) hace algo parecido si no está en modo &lt;em>passthrough&lt;/em>. Desactivarlos da rendimiento; mantenerlos da aislamiento y virtualización —y esa es una decisión real en un entorno &lt;strong>ENS&lt;/strong>—. Este post explica la topología (&lt;code>nvidia-smi topo -m&lt;/code>), GPUDirect, por qué ACS e IOMMU rompen el P2P con números, los 10 knobs y la trampa de quitar el guardia sin saber qué vigilaba. Sobre el cluster genérico 4×H100 SXM.&lt;/p>
&lt;h2 id="dónde-estás-los-pasillos-no-la-mesa">Dónde estás: los pasillos, no la mesa&lt;/h2>
&lt;p>Imagina la cocina como un edificio. Las estaciones de cocción de élite —las GPUs— están en una sala con una &lt;strong>mesa central enorme&lt;/strong> (NVLink/NVSwitch) por la que se pasan ingredientes a toda velocidad sin levantarse. Esa mesa es para ellas y solo ellas.&lt;/p>
&lt;p>Pero el edificio tiene más cosas: la &lt;strong>despensa&lt;/strong> (el almacenamiento NVMe), la &lt;strong>puerta de carga&lt;/strong> (la red, la NIC) y la &lt;strong>recepción&lt;/strong> (la CPU y su RAM). Para llegar a cualquiera de esas, las estaciones no usan la mesa central: usan los &lt;strong>pasillos del edificio&lt;/strong> —el bus PCIe—. Y aquí aparece el personaje del post: en la entrada de cada pasillo hay un &lt;strong>guardia de seguridad&lt;/strong> (ACS) que, por defecto, no deja que dos estaciones se pasen algo directamente por el pasillo: las obliga a &lt;strong>subir el paquete a recepción&lt;/strong> para que lo revisen, y solo entonces baja a destino. Es seguro, pero es un rodeo absurdo cuando las dos estaciones están una al lado de la otra. GPUDirect es el permiso para saltarse ese rodeo; ACS e IOMMU son las razones por las que, a menudo, no puedes.&lt;/p>
&lt;h2 id="la-topología-de-un-nodo-dos-buses-no-uno">La topología de un nodo: dos buses, no uno&lt;/h2>
&lt;p>El error más común es pensar que en un nodo hay &amp;ldquo;un bus&amp;rdquo;. Hay (al menos) dos, y hacen cosas distintas:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>NVLink / NVSwitch&lt;/strong> — la malla de alta velocidad GPU↔GPU. En H100 SXM, &lt;strong>18 enlaces × 50 GB/s = 900 GB/s bidireccionales&lt;/strong> entre dos GPUs cualesquiera, con NVSwitch dando un &lt;em>all-to-all&lt;/em> sin contención (&lt;a href="https://www.nvidia.com/en-us/data-center/h100/">NVLink, NVIDIA&lt;/a>). Es la mesa compartida.&lt;/li>
&lt;li>&lt;strong>PCIe Gen5&lt;/strong> — el bus de I/O general. Un enlace &lt;strong>x16 da 128 GB/s bidireccionales&lt;/strong> (~64 por sentido) (&lt;a href="https://www.nvidia.com/content/dam/en-zz/Solutions/Data-Center/h100/PB-11773-001_v01.pdf">H100 product brief&lt;/a>). Conecta cada GPU con la CPU, la RAM, las NICs y los NVMe. Es el pasillo.&lt;/li>
&lt;/ul>
&lt;p>La diferencia es de &lt;strong>7×&lt;/strong>: NVLink mueve en un segundo lo que el PCIe tarda siete. Por eso el tensor parallel intra-nodo va por NVLink y nadie lo discute. El PCIe importa para lo &lt;em>otro&lt;/em>: subir pesos del disco, recibir de la red, mover KV entre nodos.&lt;/p>
&lt;p>La herramienta para verlo es &lt;code>nvidia-smi topo -m&lt;/code>, que imprime una matriz de cómo está conectado cada par (&lt;a href="https://forums.developer.nvidia.com/t/nvidia-smi-topo-m-revisited/216584">foro NVIDIA&lt;/a>):&lt;/p>
&lt;pre tabindex="0">&lt;code> GPU0 GPU1 GPU2 GPU3 NIC0 CPU Affinity NUMA
GPU0 X NV18 NV18 NV18 PXB 0-47 0
GPU1 NV18 X NV18 NV18 PXB 0-47 0
GPU2 NV18 NV18 X NV18 SYS 48-95 1
GPU3 NV18 NV18 NV18 X SYS 48-95 1
&lt;/code>&lt;/pre>&lt;p>La leyenda es la que importa: &lt;strong>NV18&lt;/strong> = 18 enlaces NVLink (la mesa); &lt;strong>PXB&lt;/strong> = cruza switches PCIe pero no el host; &lt;strong>PHB&lt;/strong> = pasa por el host bridge; &lt;strong>NODE&lt;/strong> = mismo NUMA, cruzando PCIe; &lt;strong>SYS&lt;/strong> = cruza el interconnect entre sockets (el peor caso, atraviesa NUMA). Que &lt;code>GPU0↔NIC0&lt;/code> sea &lt;strong>PXB&lt;/strong> y &lt;code>GPU2↔NIC0&lt;/code> sea &lt;strong>SYS&lt;/strong> te dice exactamente qué GPU debe atender el tráfico de esa NIC —la 0, sin cruzar NUMA—. Esto enlaza directo con el &lt;a href="https://blog.lo0.es/posts/numa-hugepages-aislamiento-cpu-inferencia/">post de NUMA&lt;/a> y el de &lt;a href="https://blog.lo0.es/posts/cilium-ebpf-dranet-numa-de-red-inferencia/">NUMA de red&lt;/a>: la afinidad PCIe &lt;strong>es&lt;/strong> la afinidad NUMA.&lt;/p>
&lt;svg viewBox="0 0 720 280" xmlns="http://www.w3.org/2000/svg" font-family="sans-serif" font-size="12" role="img" aria-label="Topología de un nodo: NVLink arriba, PCIe abajo, ACS como puerta">
&lt;rect x="120" y="20" width="480" height="40" rx="6" fill="none" stroke="#7c3aed" stroke-width="2"/>
&lt;text x="360" y="45" text-anchor="middle" fill="#7c3aed">NVSwitch — malla NVLink 900 GB/s (mesa GPU↔GPU)&lt;/text>
&lt;rect x="120" y="80" width="90" height="36" rx="4" fill="none" stroke="currentColor" stroke-width="1.5"/>&lt;text x="165" y="103" text-anchor="middle" fill="currentColor">GPU0&lt;/text>
&lt;rect x="250" y="80" width="90" height="36" rx="4" fill="none" stroke="currentColor" stroke-width="1.5"/>&lt;text x="295" y="103" text-anchor="middle" fill="currentColor">GPU1&lt;/text>
&lt;rect x="380" y="80" width="90" height="36" rx="4" fill="none" stroke="currentColor" stroke-width="1.5"/>&lt;text x="425" y="103" text-anchor="middle" fill="currentColor">GPU2&lt;/text>
&lt;rect x="510" y="80" width="90" height="36" rx="4" fill="none" stroke="currentColor" stroke-width="1.5"/>&lt;text x="555" y="103" text-anchor="middle" fill="currentColor">GPU3&lt;/text>
&lt;line x1="165" y1="80" x2="165" y2="60" stroke="#7c3aed" stroke-width="1.5"/>&lt;line x1="295" y1="80" x2="295" y2="60" stroke="#7c3aed" stroke-width="1.5"/>&lt;line x1="425" y1="80" x2="425" y2="60" stroke="#7c3aed" stroke-width="1.5"/>&lt;line x1="555" y1="80" x2="555" y2="60" stroke="#7c3aed" stroke-width="1.5"/>
&lt;rect x="250" y="160" width="220" height="34" rx="4" fill="none" stroke="#dc2626" stroke-width="2" stroke-dasharray="5 3"/>&lt;text x="360" y="182" text-anchor="middle" fill="#dc2626">switch PCIe + ACS (el guardia)&lt;/text>
&lt;line x1="165" y1="116" x2="300" y2="160" stroke="#2563eb" stroke-width="1.2"/>&lt;line x1="295" y1="116" x2="330" y2="160" stroke="#2563eb" stroke-width="1.2"/>&lt;line x1="425" y1="116" x2="390" y2="160" stroke="#2563eb" stroke-width="1.2"/>&lt;line x1="555" y1="116" x2="420" y2="160" stroke="#2563eb" stroke-width="1.2"/>
&lt;rect x="120" y="230" width="120" height="34" rx="4" fill="none" stroke="currentColor"/>&lt;text x="180" y="252" text-anchor="middle" fill="currentColor" font-size="11">CPU + RAM (root)&lt;/text>
&lt;rect x="300" y="230" width="120" height="34" rx="4" fill="none" stroke="currentColor"/>&lt;text x="360" y="252" text-anchor="middle" fill="currentColor" font-size="11">NIC (red)&lt;/text>
&lt;rect x="480" y="230" width="120" height="34" rx="4" fill="none" stroke="currentColor"/>&lt;text x="540" y="252" text-anchor="middle" fill="currentColor" font-size="11">NVMe (disco)&lt;/text>
&lt;line x1="180" y1="194" x2="180" y2="230" stroke="#2563eb" stroke-width="1.2"/>&lt;line x1="360" y1="194" x2="360" y2="230" stroke="#2563eb" stroke-width="1.2"/>&lt;line x1="430" y1="194" x2="540" y2="230" stroke="#2563eb" stroke-width="1.2"/>
&lt;text x="610" y="180" fill="#dc2626" font-size="10">ACS on →&lt;/text>
&lt;text x="610" y="195" fill="#dc2626" font-size="10">sube a root&lt;/text>
&lt;/svg>
&lt;h2 id="gpudirect-saltarse-la-recepción">GPUDirect: saltarse la recepción&lt;/h2>
&lt;p>Sin GPUDirect, mover un dato de la NIC (o el NVMe) a la GPU hace un rodeo obligatorio: &lt;strong>dispositivo → RAM del host → GPU&lt;/strong>. Ese rebote por la RAM consume ancho de banda de la CPU, gasta copias y añade latencia. &lt;strong>GPUDirect&lt;/strong> elimina el rebote dejando que el dato vaya &lt;strong>directo del dispositivo a la HBM&lt;/strong>. Tres sabores:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>GPUDirect P2P&lt;/strong> — GPU↔GPU &lt;strong>por PCIe&lt;/strong> (cuando no hay NVLink entre ellas, o para tráfico que no usa la mesa).&lt;/li>
&lt;li>&lt;strong>GPUDirect RDMA&lt;/strong> — GPU↔NIC: la tarjeta de red escribe directa en la HBM. Es lo que hace viable el multi-nodo eficiente (NCCL sobre InfiniBand/RoCE).&lt;/li>
&lt;li>&lt;strong>GPUDirect Storage (GDS)&lt;/strong> — GPU↔NVMe: el disco escribe directo en la HBM, sin buffer de host. Es la palanca del &lt;a href="https://blog.lo0.es/posts/del-disco-a-la-hbm-cold-start-carga-modelo/">cold start&lt;/a>.&lt;/li>
&lt;/ul>
&lt;p>En un nodo SXM, el tráfico GPU↔GPU del &lt;a href="https://blog.lo0.es/posts/nvlink-nvswitch-nccl-tensor-parallel/">tensor parallel&lt;/a> &lt;strong>no usa P2P por PCIe&lt;/strong>: usa NVLink. Por eso GPUDirect importa sobre todo en los &lt;strong>bordes&lt;/strong> del nodo: la red (RDMA, para multi-nodo) y el disco (GDS, para arranque). Ahí es donde ACS hace daño.&lt;/p>
&lt;h2 id="el-guardia-por-qué-acs-e-iommu-rompen-el-p2p">El guardia: por qué ACS e IOMMU rompen el P2P&lt;/h2>
&lt;p>&lt;strong>ACS (Access Control Services)&lt;/strong> es una feature de seguridad del PCIe pensada para virtualización y aislamiento: garantiza que un dispositivo no pueda leer/escribir directamente en otro sin que el &lt;em>root complex&lt;/em> lo medie. Para conseguirlo, &lt;strong>fuerza las transacciones peer-to-peer a subir hasta el root complex&lt;/strong> y volver a bajar (&lt;a href="https://docs.nvidia.com/gpudirect-storage/best-practices-guide/index.html">best practices GDS, NVIDIA&lt;/a>). Es exactamente lo contrario de lo que GPUDirect quiere: el camino directo deja de serlo.&lt;/p>
&lt;p>El &lt;strong>IOMMU&lt;/strong> (VT-d en Intel, equivalente en AMD) traduce direcciones y aísla dispositivos. Si está activo y &lt;strong>no&lt;/strong> en modo passthrough, también &lt;strong>redirige el tráfico P2P por el root complex&lt;/strong>, con el mismo efecto: rendimiento por los suelos o, en casos extremos, &lt;em>hangs&lt;/em> (&lt;a href="https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/troubleshooting.html">troubleshooting NCCL&lt;/a>).&lt;/p>
&lt;p>Resumido sin rodeos (&lt;a href="https://morgangiraud.medium.com/multi-gpu-nvidia-p2p-capabilities-and-debugging-tips-fb7597b4e2b5">Giraud, debugging P2P&lt;/a>): &lt;strong>ACS&lt;/strong> fuerza el paso por el root &lt;em>para comprobaciones de seguridad&lt;/em>; &lt;strong>IOMMU&lt;/strong> lo fuerza &lt;em>para aislamiento y virtualización&lt;/em>. Ambos rompen el objetivo del P2P (comunicación directa sin intermediarios) y añaden overhead. Si no necesitas esa seguridad/virtualización en ese path, desactivarlos recupera el rendimiento. La receta operativa para máximo rendimiento de GPUDirect: &lt;strong>ACS off&lt;/strong> en los switches del camino e &lt;strong>IOMMU en passthrough&lt;/strong> (&lt;code>iommu=pt&lt;/code>) o desactivado.&lt;/p>
&lt;h2 id="las-matemáticas-que-importan-cuánto-cuesta-el-rodeo">Las matemáticas que importan: cuánto cuesta el rodeo&lt;/h2>
&lt;p>Pongamos un &lt;strong>SWAP de KV&lt;/strong> de 5 GB (preemption del &lt;a href="https://blog.lo0.es/posts/scheduler-step-vllm/">scheduler&lt;/a> que manda KV a host, o transferencia entre nodos en &lt;a href="https://blog.lo0.es/posts/disaggregated-serving-prefill-decode/">serving desagregado&lt;/a>):&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Camino&lt;/th>
&lt;th>BW efectivo&lt;/th>
&lt;th>Tiempo de 5 GB&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>NVLink (GPU↔GPU intra-nodo)&lt;/td>
&lt;td>~450 GB/s&lt;/td>
&lt;td>&lt;strong>~11 ms&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>PCIe Gen5 x16 directo (P2P, ACS off)&lt;/td>
&lt;td>~55 GB/s&lt;/td>
&lt;td>&lt;strong>~91 ms&lt;/strong>&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>PCIe vía root complex (ACS on)&lt;/td>
&lt;td>~25-30 GB/s*&lt;/td>
&lt;td>&lt;strong>~170-200 ms&lt;/strong>&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>* El rodeo por el root no solo &amp;ldquo;añade latencia&amp;rdquo;: satura el ancho de banda del host bridge, contiende con otro tráfico y, según la topología, puede caer bastante por debajo del directo. La cifra es de orden, para mostrar la magnitud del problema, no un benchmark.&lt;/p>
&lt;p>La lectura: en el camino que sí usa PCIe (red, disco, swap), tener ACS on puede &lt;strong>duplicar o triplicar&lt;/strong> el tiempo. Y si ese tiempo está en el camino crítico —un cold start, un swap de preemption, un all-reduce inter-nodo— se nota en la latencia que ve el usuario. Lo que &lt;strong>no&lt;/strong> arregla desactivar ACS: el tráfico que ya iba por NVLink (TP intra-nodo). Ahí ACS es irrelevante.&lt;/p>
&lt;h2 id="la-tensión-real-rendimiento-vs-aislamiento-y-ens">La tensión real: rendimiento vs aislamiento (y ENS)&lt;/h2>
&lt;p>Aquí el post se pone serio, porque la receta &amp;ldquo;desactiva ACS e IOMMU&amp;rdquo; tiene un coste que en un entorno regulado no es gratis. ACS e IOMMU &lt;strong>existen por una razón&lt;/strong>: aislar dispositivos. En un nodo &lt;strong>bare-metal dedicado&lt;/strong> a inferencia, sin virtualización ni multi-tenancy, no aíslas nada que importe y desactivarlos es razonable. Pero:&lt;/p>
&lt;ul>
&lt;li>Si haces &lt;strong>passthrough de GPU a VMs&lt;/strong> o usas contenedores con aislamiento fuerte, el IOMMU es &lt;strong>necesario&lt;/strong> —no es opcional—.&lt;/li>
&lt;li>En un escenario &lt;strong>multi-tenant&lt;/strong> donde varias cargas comparten nodo, ACS aporta una garantía de que un dispositivo no fisgonea a otro.&lt;/li>
&lt;li>En &lt;strong>ENS&lt;/strong> (&lt;a href="https://blog.lo0.es/posts/controles-tecnicos-ens-42001-eu-ai-act/">ver controles técnicos&lt;/a>), el aislamiento de cargas y la trazabilidad de accesos pueden ser requisitos; desactivar el aislamiento del bus para ganar 80 ms es una decisión que hay que &lt;strong>justificar y documentar&lt;/strong>, no un tuneo silencioso.&lt;/li>
&lt;/ul>
&lt;p>La salida de diseño, cuando necesitas las dos cosas: &lt;strong>mantén el aislamiento donde lo exige el compliance y diseña para que el camino caliente no dependa del P2P por PCIe&lt;/strong>. Concretamente, en un nodo SXM, el grueso del tráfico crítico (TP) ya va por NVLink y no le afecta ACS. Para la red, dedica una NIC por GPU en su mismo switch PCIe (PXB) y usa GPUDirect RDMA solo en el path que controlas. Para el disco, cachea pesos en NVMe local. Así no pagas la elección entre rendimiento y aislamiento: la evitas en el path que importa.&lt;/p>
&lt;h2 id="los-10-knobs">Los 10 knobs&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>#&lt;/th>
&lt;th>Knob&lt;/th>
&lt;th>Qué controla&lt;/th>
&lt;th>Coste / riesgo&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>ACS off (switches del path)&lt;/td>
&lt;td>rodeo por root del P2P&lt;/td>
&lt;td>pierdes aislamiento de bus&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>2&lt;/td>
&lt;td>&lt;code>iommu=pt&lt;/code> / off&lt;/td>
&lt;td>redirección P2P por root&lt;/td>
&lt;td>rompe passthrough a VM si off&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>3&lt;/td>
&lt;td>&lt;code>nvidia-smi topo -m&lt;/code>&lt;/td>
&lt;td>auditar la topología real&lt;/td>
&lt;td>— (siempre conviene)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>4&lt;/td>
&lt;td>&lt;code>p2pBandwidthLatencyTest&lt;/code>&lt;/td>
&lt;td>medir P2P de verdad&lt;/td>
&lt;td>— (verifica antes de asumir)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>5&lt;/td>
&lt;td>colocación de NIC&lt;/td>
&lt;td>mismo switch PCIe que la GPU&lt;/td>
&lt;td>SYS si cruza NUMA&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>6&lt;/td>
&lt;td>colocación de NVMe&lt;/td>
&lt;td>NUMA-local a la GPU&lt;/td>
&lt;td>H2D cruzando UPI&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>7&lt;/td>
&lt;td>&lt;code>nvidia-peermem&lt;/code> (GDR)&lt;/td>
&lt;td>habilita RDMA a HBM&lt;/td>
&lt;td>driver/kernel correctos&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>8&lt;/td>
&lt;td>PCIe gen/lanes (x16)&lt;/td>
&lt;td>ancho del pasillo&lt;/td>
&lt;td>GPU en x8 silencioso&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>9&lt;/td>
&lt;td>relaxed ordering / ASPM&lt;/td>
&lt;td>latencia y energía PCIe&lt;/td>
&lt;td>jitter si mal configurado&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>10&lt;/td>
&lt;td>persistence mode&lt;/td>
&lt;td>evita reinit del path&lt;/td>
&lt;td>GPU ociosa pagada&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;h2 id="cómo-se-conecta-con-el-resto-del-stack">Cómo se conecta con el resto del stack&lt;/h2>
&lt;p>&lt;strong>Con NVLink y NCCL.&lt;/strong> El &lt;a href="https://blog.lo0.es/posts/nvlink-nvswitch-nccl-tensor-parallel/">post de NVLink&lt;/a> cubre la mesa GPU↔GPU; este cubre el &lt;em>otro&lt;/em> bus, el que conecta con disco, red y host. Son complementarios: ACS afecta al PCIe, no al NVLink.&lt;/p>
&lt;p>&lt;strong>Con el cold start.&lt;/strong> GPUDirect Storage del &lt;a href="https://blog.lo0.es/posts/del-disco-a-la-hbm-cold-start-carga-modelo/">post disco→HBM&lt;/a> es GPUDirect sobre el path de almacenamiento; ACS on lo estrangula igual que estrangula el P2P.&lt;/p>
&lt;p>&lt;strong>Con NUMA.&lt;/strong> La afinidad PCIe de &lt;code>topo -m&lt;/code> &lt;strong>es&lt;/strong> la afinidad NUMA del &lt;a href="https://blog.lo0.es/posts/numa-hugepages-aislamiento-cpu-inferencia/">post del host&lt;/a>; colocar NIC y NVMe en el NUMA correcto evita el camino SYS.&lt;/p>
&lt;p>&lt;strong>Con la red.&lt;/strong> La colocación de NIC y GPUDirect RDMA es el tema del &lt;a href="https://blog.lo0.es/posts/cilium-ebpf-dranet-numa-de-red-inferencia/">post de NUMA de red&lt;/a>; el mismo principio de &amp;ldquo;saca a la CPU del medio&amp;rdquo;.&lt;/p>
&lt;p>&lt;strong>Con PagedAttention y el scheduler.&lt;/strong> El &lt;strong>SWAP&lt;/strong> de preemption (&lt;a href="https://blog.lo0.es/posts/scheduler-step-vllm/">scheduler&lt;/a>) mueve bloques de &lt;a href="https://blog.lo0.es/posts/pagedattention-deep-dive/">KV&lt;/a> por PCIe; por eso V1 prefiere RECOMPUTE y por eso este bus importa.&lt;/p>
&lt;p>&lt;strong>Con el disaggregated serving.&lt;/strong> Transferir KV entre pools en &lt;a href="https://blog.lo0.es/posts/disaggregated-serving-prefill-decode/">serving desagregado&lt;/a> viaja por PCIe→NIC→PCIe; ACS y la colocación deciden si es viable.&lt;/p>
&lt;p>&lt;strong>Con ENS.&lt;/strong> El aislamiento del bus es un control técnico; ver &lt;a href="https://blog.lo0.es/posts/controles-tecnicos-ens-42001-eu-ai-act/">controles ENS/42001/AI Act&lt;/a>.&lt;/p>
&lt;h2 id="trampas-y-cosas-que-no-son-lo-que-parecen">Trampas y cosas que no son lo que parecen&lt;/h2>
&lt;p>&lt;strong>&amp;ldquo;Desactiva ACS en todas partes, va más rápido.&amp;rdquo;&lt;/strong> En un nodo dedicado, vale. En uno con virtualización, multi-tenancy o requisitos de aislamiento (ENS), estás quitando un control de seguridad. La decisión correcta es &lt;em>por path&lt;/em> y documentada, no global y silenciosa.&lt;/p>
&lt;p>&lt;strong>&amp;ldquo;NVLink y PCIe son el mismo bus, más o menos.&amp;rdquo;&lt;/strong> No. Son dos buses con 7× de diferencia y propósitos distintos. El TP va por NVLink; el disco, la red y el host van por PCIe. Confundirlos lleva a &amp;ldquo;optimizar&amp;rdquo; ACS para un tráfico que ni siquiera pasa por PCIe.&lt;/p>
&lt;p>&lt;strong>&amp;ldquo;El P2P funciona solo, no hay que comprobar nada.&amp;rdquo;&lt;/strong> El P2P &lt;strong>se desactiva en silencio&lt;/strong> con ACS/IOMMU activos, y muchas distros los activan por defecto. Comprueba con &lt;code>p2pBandwidthLatencyTest&lt;/code> y &lt;code>nvidia-smi topo -m&lt;/code>; no asumas que tienes el camino directo solo porque las GPUs están en el mismo nodo.&lt;/p>
&lt;p>&lt;strong>&amp;ldquo;IOMMU off siempre, por rendimiento.&amp;rdquo;&lt;/strong> Si haces passthrough de GPU a máquinas virtuales, el IOMMU es &lt;strong>obligatorio&lt;/strong>; desactivarlo rompe el passthrough. El modo correcto suele ser &lt;code>passthrough&lt;/code> (&lt;code>iommu=pt&lt;/code>): mantiene el mapeo necesario sin penalizar el P2P.&lt;/p>
&lt;p>&lt;strong>&amp;ldquo;Más lanes PCIe = GPU más rápida.&amp;rdquo;&lt;/strong> El PCIe es el camino de I/O, no de cómputo. Una GPU en x8 en vez de x16 tarda más en &lt;em>cargar&lt;/em> y en &lt;em>comunicar por PCIe&lt;/em>, pero genera tokens a la misma velocidad una vez los pesos están dentro. El daño de x8 está en el cold start y en el multi-nodo, no en el throughput de decode.&lt;/p>
&lt;p>&lt;strong>&amp;ldquo;GPUDirect arregla cualquier cuello de I/O.&amp;rdquo;&lt;/strong> GPUDirect quita el rebote por la CPU; si tu cuello es el propio dispositivo (NVMe saturado, NIC a tope) o la topología (camino SYS cruzando NUMA), GPUDirect no lo toca. Mide dónde está el cuello antes.&lt;/p>
&lt;h2 id="conclusión">Conclusión&lt;/h2>
&lt;p>Toda esta serie ha bajado pisos buscando dónde se pierde el tiempo, y este llega al cableado del edificio. La intuición trata el nodo como una caja homogénea donde &amp;ldquo;las GPUs hablan con todo&amp;rdquo;; la realidad es que hay dos buses con propósitos opuestos —una mesa de élite para las GPUs (NVLink) y unos pasillos de servicio para todo lo demás (PCIe)— y un guardia de seguridad en los pasillos que, con la mejor intención, obliga a cada paquete a subir a recepción antes de entregarlo. GPUDirect es el permiso para la entrega directa; ACS e IOMMU son las razones legítimas por las que a veces no te lo dan. La lección no es &amp;ldquo;desactiva el guardia&amp;rdquo;: es entender &lt;strong>qué camino es crítico&lt;/strong> (casi nunca el que crees) y &lt;strong>qué vigilaba el guardia&lt;/strong> antes de mandarlo a casa. En un nodo dedicado, el camino directo es casi gratis y conviene tomarlo. En uno que comparte cargas o vive bajo ENS, el aislamiento del bus es un control que se sacrifica con justificación o no se sacrifica. El buen diseño no elige entre rendimiento y aislamiento a ciegas: pone el tráfico crítico en la mesa que no necesita guardia, y deja los pasillos para lo que puede esperar.&lt;/p>
&lt;h2 id="ver-también">Ver también&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://blog.lo0.es/posts/nvlink-nvswitch-nccl-tensor-parallel/">La mesa compartida: NVLink, NVSwitch y NCCL&lt;/a> — el bus GPU↔GPU que ACS no toca; complementario a este post.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/del-disco-a-la-hbm-cold-start-carga-modelo/">Del disco a la HBM: cold start&lt;/a> — GPUDirect Storage sobre el path de NVMe, estrangulado por ACS igual que el P2P.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/numa-hugepages-aislamiento-cpu-inferencia/">NUMA, hugepages y aislamiento de CPU&lt;/a> — la afinidad PCIe es la afinidad NUMA; colocar NIC y NVMe en el socket correcto.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/cilium-ebpf-dranet-numa-de-red-inferencia/">NUMA de red, Cilium eBPF y DRANET&lt;/a> — colocación de NIC y GPUDirect RDMA, el mismo principio de sacar a la CPU del medio.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/pagedattention-deep-dive/">PagedAttention y el block manager&lt;/a> — el KV que viaja por PCIe cuando se hace SWAP.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/scheduler-step-vllm/">El pase: el scheduler step de vLLM&lt;/a> — por qué V1 prefiere RECOMPUTE a SWAP (evita el viaje por PCIe).&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/disaggregated-serving-prefill-decode/">Disaggregated serving: prefill y decode separados&lt;/a> — transferir KV entre nodos pasa por PCIe→NIC→PCIe.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/controles-tecnicos-ens-42001-eu-ai-act/">Controles técnicos ENS / ISO 42001 / EU AI Act&lt;/a> — el aislamiento del bus como control de seguridad a justificar.&lt;/li>
&lt;/ul>
&lt;h2 id="referencias">Referencias&lt;/h2>
&lt;ul>
&lt;li>NVIDIA, &lt;em>GPUDirect Storage Best Practices Guide&lt;/em> (ACS, IOMMU, paths): &lt;a href="https://docs.nvidia.com/gpudirect-storage/best-practices-guide/index.html">https://docs.nvidia.com/gpudirect-storage/best-practices-guide/index.html&lt;/a>.&lt;/li>
&lt;li>NVIDIA, &lt;em>NCCL Troubleshooting&lt;/em> (IOMMU/VT-d y P2P): &lt;a href="https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/troubleshooting.html">https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/troubleshooting.html&lt;/a>.&lt;/li>
&lt;li>M. Giraud, &lt;em>Multi-GPU (NVIDIA) P2P capabilities and debugging tips&lt;/em>: &lt;a href="https://morgangiraud.medium.com/multi-gpu-nvidia-p2p-capabilities-and-debugging-tips-fb7597b4e2b5">https://morgangiraud.medium.com/multi-gpu-nvidia-p2p-capabilities-and-debugging-tips-fb7597b4e2b5&lt;/a>.&lt;/li>
&lt;li>NVIDIA, &lt;em>H100 Product Brief&lt;/em> (PCIe Gen5, NVLink 900 GB/s): &lt;a href="https://www.nvidia.com/content/dam/en-zz/Solutions/Data-Center/h100/PB-11773-001_v01.pdf">https://www.nvidia.com/content/dam/en-zz/Solutions/Data-Center/h100/PB-11773-001_v01.pdf&lt;/a>.&lt;/li>
&lt;li>NVIDIA, &lt;em>GPUDirect RDMA documentation&lt;/em>: &lt;a href="https://docs.nvidia.com/cuda/gpudirect-rdma/index.html">https://docs.nvidia.com/cuda/gpudirect-rdma/index.html&lt;/a>.&lt;/li>
&lt;/ul></description></item></channel></rss>