<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Mlperf on lo0 — Blog Técnico</title><link>https://blog.lo0.es/tags/mlperf/</link><description>Recent content in Mlperf on lo0 — Blog Técnico</description><generator>Hugo -- gohugo.io</generator><language>es</language><lastBuildDate>Mon, 22 Jun 2026 11:00:00 +0200</lastBuildDate><atom:link href="https://blog.lo0.es/tags/mlperf/index.xml" rel="self" type="application/rss+xml"/><item><title>Almacenamiento en la era de la IA (2/4): rendimiento</title><link>https://blog.lo0.es/posts/almacenamiento-ia-rendimiento/</link><pubDate>Mon, 22 Jun 2026 11:00:00 +0200</pubDate><guid>https://blog.lo0.es/posts/almacenamiento-ia-rendimiento/</guid><description>&lt;p>En el &lt;a href="https://blog.lo0.es/posts/almacenamiento-ia-estado-del-arte/">primer artículo&lt;/a> dibujamos el mapa: la jerarquía memoria-almacenamiento, las tecnologías de medio y la pila de software que domina los clústeres GPU. Este segundo artículo entra en la propiedad que justifica toda esa complejidad: el rendimiento. La pregunta que debe responder un arquitecto no es &amp;ldquo;¿cuántos GB/s da mi cabina?&amp;rdquo;, sino &amp;ldquo;¿consigo que mis GPU trabajen al 95 % en lugar de al 40 %?&amp;rdquo;. Esa diferencia es, literalmente, la mitad de la factura de cómputo.&lt;/p>
&lt;h2 id="la-métrica-que-de-verdad-importa-utilización-del-acelerador">La métrica que de verdad importa: utilización del acelerador&lt;/h2>
&lt;p>Es tentador medir el almacenamiento de IA con las métricas clásicas —&lt;em>throughput&lt;/em> secuencial, IOPS aleatorias, latencia—, y las necesitamos. Pero ninguna de ellas captura lo que paga el negocio. La métrica integradora es la &lt;strong>utilización del acelerador&lt;/strong>: qué fracción del tiempo la GPU está calculando en lugar de esperando datos.&lt;/p>
&lt;p>La mayoría de los &lt;em>pipelines&lt;/em> de ML reales corren entre el 30 % y el 60 % de utilización de GPU. Las encuestas del sector son demoledoras: solo en torno al 7 % de los equipos de IA/ML logra superar el 85 % en picos, y una mala previsión o un autoescalado deficiente pueden dejar GPUs ociosas el 70-85 % del tiempo. Un &lt;em>job&lt;/em> que corre al 30 % de utilización está pagando el 70 % de su capacidad de cómputo para nada.&lt;/p>
&lt;p>Podemos formalizarlo. Si \( t_{\text{cmp}} \) es el tiempo de cómputo por &lt;em>batch&lt;/em> y \( t_{\text{io}} \) el tiempo que la GPU pasa bloqueada esperando I/O que no logra solaparse con el cómputo, la utilización efectiva es:&lt;/p>
$$U = \frac{t_{\text{cmp}}}{t_{\text{cmp}} + t_{\text{io}}}$$
&lt;p>El objetivo de toda la ingeniería de almacenamiento para IA es llevar \( t_{\text{io}} \) hacia cero, ya sea aumentando el ancho de banda, reduciendo la latencia o solapando la I/O con el cómputo mediante &lt;em>prefetching&lt;/em> y &lt;em>pipelining&lt;/em>. Y hay un agravante: cuanto más rápida es la GPU, más difícil es alimentarla. El paso de V100 a H100 redujo el tiempo de cómputo por &lt;em>batch&lt;/em> del modelo 3D U-Net en un 76 %, convirtiendo una carga que era sensible al ancho de banda en una sensible a la latencia. Cada generación de acelerador sube el listón para el almacenamiento.&lt;/p>
&lt;p>Este cambio de régimen —de limitado por ancho de banda a limitado por latencia— tiene una consecuencia de diseño que conviene interiorizar. Cuando una carga está limitada por ancho de banda, la solución es añadir capacidad de transferencia: más NVMe, más &lt;em>lanes&lt;/em>, más nodos. Cuando pasa a estar limitada por latencia, esa receta deja de funcionar; lo que importa entonces es el tiempo de respuesta por operación, que se ataca con caché, con &lt;em>prefetching&lt;/em> inteligente y con rutas de datos que eliminan saltos (como GPUDirect). Diagnosticar correctamente en cuál de los dos regímenes está cada carga es la primera tarea de cualquier optimización: invertir en ancho de banda una carga limitada por latencia es gastar dinero sin mover la utilización.&lt;/p>
&lt;h2 id="mlperf-storage-el-banco-de-pruebas-que-sí-mide-lo-correcto">MLPerf Storage: el banco de pruebas que sí mide lo correcto&lt;/h2>
&lt;p>Durante años faltó una forma neutral de comparar plataformas de almacenamiento para IA. MLPerf Storage, de MLCommons, la ha proporcionado. Su acierto de diseño es no medir GB/s en abstracto, sino simular el &amp;ldquo;&lt;em>think time&lt;/em>&amp;rdquo; de los aceleradores para generar un patrón de I/O realista, y exigir que esos aceleradores simulados mantengan un nivel mínimo de utilización. Es decir, mide exactamente lo que importa: cuántos aceleradores puede mantener alimentados una plataforma sin que su utilización caiga por debajo del umbral.&lt;/p>
&lt;p>La &lt;strong>v1.0&lt;/strong> (septiembre de 2024) usaba los modelos 3D U-Net, ResNet-50 y CosmoFlow, simulando A100 y H100, con umbrales de utilización del 90 % para los dos primeros y del 70 % para CosmoFlow. La &lt;strong>v2.0&lt;/strong> (agosto de 2025) marcó un salto: más de 200 resultados de 26 organizaciones —Alluxio, DDN, Hammerspace, HPE, IBM, KIOXIA, Micron, Oracle, Samsung, WDC, entre otras—, sistemas capaces de sostener aproximadamente el doble de aceleradores que en v1.0, y, sobre todo, una nueva carga de &lt;em>checkpointing&lt;/em> (a la que volveremos).&lt;/p>
&lt;p>Algunos resultados de v2.0 sirven para calibrar el estado del arte:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Sistema&lt;/th>
&lt;th>Throughput&lt;/th>
&lt;th>Aceleradores&lt;/th>
&lt;th>Utilización GPU&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Volumez&lt;/td>
&lt;td>1,079 TB/s&lt;/td>
&lt;td>—&lt;/td>
&lt;td>92,21 %&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Hammerspace (5 nodos)&lt;/td>
&lt;td>420,8 GB/s&lt;/td>
&lt;td>140&lt;/td>
&lt;td>&amp;gt;94,7 %&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Hammerspace (3 nodos)&lt;/td>
&lt;td>253,1 GB/s&lt;/td>
&lt;td>84&lt;/td>
&lt;td>&amp;gt;94,7 %&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Hammerspace (1 nodo)&lt;/td>
&lt;td>85,6 GB/s&lt;/td>
&lt;td>28&lt;/td>
&lt;td>&amp;gt;94,7 %&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Alluxio&lt;/td>
&lt;td>24,14 GiB/s&lt;/td>
&lt;td>128&lt;/td>
&lt;td>99,57 %&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>El dato de Hammerspace ilustra una propiedad que un arquitecto debe exigir: &lt;strong>escalado lineal&lt;/strong>. De 1 a 5 nodos el &lt;em>throughput&lt;/em> crece de 85,6 a 420,8 GB/s manteniendo la utilización por encima del 94,7 % con un coeficiente de variación ínfimo (0,08-0,14 %). El escalado lineal es lo que separa una plataforma de IA de un NAS rápido.&lt;/p>
&lt;h2 id="las-cifras-de-las-plataformas-comerciales">Las cifras de las plataformas comerciales&lt;/h2>
&lt;p>Fuera del banco de pruebas, las plataformas certificadas para DGX SuperPOD publican cifras agregadas que conviene tener como referencia de orden de magnitud:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>WEKA WEKApod Nitro&lt;/strong>: 720 GB/s de lectura y 186 GB/s de escritura por configuración, 18 millones de IOPS, con NIC ConnectX-8 a 800 Gb/s. Por nodo, 70 GB/s de lectura y 40 GB/s de escritura; la configuración mínima de 8 nodos entrega 560 GB/s de lectura. Un único equipo de entrada cubre la demanda de I/O de una &amp;ldquo;&lt;em>scalable unit&lt;/em>&amp;rdquo; GB200 de 1.152 GPUs.&lt;/li>
&lt;li>&lt;strong>DDN AI400X2&lt;/strong>: más de 90 GB/s y 3 millones de IOPS por &lt;em>appliance&lt;/em>; la variante Turbo satura cerca de 100 GB/s (800 Gbps) por DGX B200. La nueva plataforma de DDN declara más de 1 TB/s de lectura por &lt;em>appliance&lt;/em> con escalado por rack, y ha alimentado al supercomputador Eos de NVIDIA con 4 TB/s.&lt;/li>
&lt;li>&lt;strong>VAST Data&lt;/strong>: múltiples TB/s desde un único &lt;em>mount point&lt;/em> vía &lt;em>multipathing&lt;/em> NFS, RDMA sobre NFS y GPUDirect, gestionando exabytes en un único espacio de nombres multiprotocolo.&lt;/li>
&lt;li>&lt;strong>Pure Storage&lt;/strong>: certificado para DGX SuperPOD con GB200 y GB300.&lt;/li>
&lt;/ul>
&lt;p>Estas cifras solo significan algo en relación con el cluster que alimentan. Un GB200 NVL72 mueve 130 TB/s de comunicación interna entre GPU; el almacenamiento no compite con eso, pero sí debe sostener el &lt;em>data loading&lt;/em> y el &lt;em>checkpointing&lt;/em> sin estrangular a 72 GPU que se comportan como una sola.&lt;/p>
&lt;h2 id="el-patrón-de-io-del-entrenamiento-y-gpudirect-storage">El patrón de I/O del entrenamiento y GPUDirect Storage&lt;/h2>
&lt;p>Entender el patrón de I/O es la clave para no sobredimensionar ni infradimensionar. El entrenamiento combina varios patrones: lecturas grandes y secuenciales del dataset, lecturas pequeñas y aleatorias en el &lt;em>shuffling&lt;/em> entre épocas, y escrituras masivas y periódicas en el &lt;em>checkpointing&lt;/em>. Cada uno estresa el almacenamiento de forma distinta.&lt;/p>
&lt;p>El camino tradicional de datos atraviesa la CPU: del almacenamiento a un &lt;em>bounce buffer&lt;/em> en memoria del host y de ahí a la memoria de la GPU. Cada byte de cada &lt;em>checkpoint&lt;/em> y de cada carga de pesos paga la latencia y el &lt;em>overhead&lt;/em> de CPU de ese doble salto. &lt;strong>GPUDirect Storage (GDS)&lt;/strong> lo corta: habilita DMA directo entre la memoria de la GPU y el NVMe mediante la librería de espacio de usuario cuFile y el módulo de kernel nvidia-fs, que intercepta las llamadas POSIX y las redirige por el motor DMA. El resultado es &lt;em>zero-copy&lt;/em>, con transferencias directas que superan los 40 GB/s y, sobre todo, sin robar ciclos a la CPU.&lt;/p>
&lt;p>Hay un matiz que los despliegues ingenuos pasan por alto: &lt;strong>GDS está optimizado para transferencias grandes, alineadas y secuenciales&lt;/strong>. Para cargas dominadas por archivos pequeños o acceso muy aleatorio, el camino tradicional con caché en la CPU puede ser más eficiente. GDS no es un interruptor mágico de &amp;ldquo;más rendimiento&amp;rdquo;; es una herramienta para un patrón concreto. Diseñar el &lt;em>data pipeline&lt;/em> —formato de dataset, tamaño de &lt;em>shard&lt;/em>, número de &lt;em>workers&lt;/em> del &lt;em>DataLoader&lt;/em>— importa tanto como elegir la cabina.&lt;/p>
&lt;p>Merece la pena detenerse en el &lt;em>data pipeline&lt;/em>, porque es donde se pierde rendimiento de forma más silenciosa. El entrenamiento no lee el dataset de cualquier manera: lo recorre en &lt;em>batches&lt;/em>, lo baraja entre épocas para evitar sesgos de orden, y a menudo aplica transformaciones (decodificación de imágenes, &lt;em>tokenización&lt;/em>, &lt;em>augmentation&lt;/em>) en CPU antes de entregar el tensor a la GPU. Cada uno de esos pasos puede convertirse en el cuello de botella. Un número insuficiente de &lt;em>workers&lt;/em> del &lt;em>DataLoader&lt;/em> deja a la GPU esperando; un formato de dataset que obliga a abrir millones de ficheros pequeños hunde el rendimiento de metadatos; un &lt;em>shuffle&lt;/em> mal diseñado convierte lecturas secuenciales eficientes en accesos aleatorios costosos. La práctica habitual en cargas serias es empaquetar el dataset en &lt;em>shards&lt;/em> grandes (formatos como WebDataset, TFRecord o Parquet) precisamente para que el patrón de lectura sea secuencial y grande, el terreno donde GDS y los sistemas de archivos paralelos rinden mejor. La regla mental: el almacenamiento más rápido del mundo no salva a un &lt;em>pipeline&lt;/em> de datos mal diseñado.&lt;/p>
&lt;h2 id="el-coste-real-del-checkpointing-cuando-hay-entrenamiento">El coste real del checkpointing (cuando hay entrenamiento)&lt;/h2>
&lt;p>El &lt;em>checkpointing&lt;/em> es la carga de escritura más exigente del mundo de la IA, pero conviene situarla: es un problema de &lt;strong>entrenamiento&lt;/strong>. Una factoría de inferencia pura apenas lo sufre —sus escrituras pesadas son otras: KV-cache, índices vectoriales, telemetría—. Lo tratamos aquí porque muchas instalaciones combinan algo de &lt;em>fine-tuning&lt;/em> o entrenamiento ocasional con el servicio, y porque ilustra mejor que ningún otro caso cómo la asincronía vence a la fuerza bruta. Si tu plataforma es de inferencia, puedes leer esta sección como contexto y saltar a la siguiente, que es la que de verdad te concierne.&lt;/p>
&lt;p>Dicho esto, la intuición de la mayoría sobre el &lt;em>checkpointing&lt;/em> es errónea en dos puntos: el tamaño y la frecuencia.&lt;/p>
&lt;p>&lt;strong>El tamaño.&lt;/strong> Un &lt;em>checkpoint&lt;/em> no son solo los pesos. La regla práctica es de unos 16 bytes por parámetro, porque el grueso es el estado del optimizador. Las cifras de la carga de &lt;em>checkpointing&lt;/em> de MLPerf Storage v2.0, basadas en el &lt;em>Llama 3 Herd&lt;/em> de Meta, lo dejan claro:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Modelo&lt;/th>
&lt;th>Procesos&lt;/th>
&lt;th>Tamaño del checkpoint&lt;/th>
&lt;th>Del cual, estado del optimizador&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>8B&lt;/td>
&lt;td>8&lt;/td>
&lt;td>105 GB&lt;/td>
&lt;td>90 GB&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>70B&lt;/td>
&lt;td>64&lt;/td>
&lt;td>912 GB&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>405B&lt;/td>
&lt;td>512&lt;/td>
&lt;td>5,29 TB&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>1T&lt;/td>
&lt;td>1024&lt;/td>
&lt;td>15 TB&lt;/td>
&lt;td>13,2 TB&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>&lt;strong>La frecuencia.&lt;/strong> A escala, los fallos de hardware son constantes (lo desarrollamos en el &lt;a href="https://blog.lo0.es/posts/almacenamiento-ia-disponibilidad/">artículo sobre disponibilidad&lt;/a>). El modelo de Meta para un cluster de 16.000 aceleradores predice un fallo cada pocas horas. Para perder menos del 5 % del progreso entre fallos hay que hacer del orden de 20 &lt;em>checkpoints&lt;/em> en ese intervalo. Eso se traduce en cadencias agresivas:&lt;/p>
&lt;ul>
&lt;li>16.000 aceleradores: unos 155 &lt;em>checkpoints&lt;/em> al día, uno cada 9,3 minutos.&lt;/li>
&lt;li>100.000 aceleradores: unos 967 &lt;em>checkpoints&lt;/em> al día, uno cada 1,5 minutos.&lt;/li>
&lt;/ul>
&lt;p>Y aquí aparece el problema de ancho de banda. El &lt;em>checkpoint&lt;/em> síncrono detiene el entrenamiento mientras escribe. Si \( S_{\text{ckpt}} \) es el tamaño del &lt;em>checkpoint&lt;/em> y \( t_{\text{win}} \) la ventana de tiempo aceptable para escribirlo manteniendo el &lt;em>overhead&lt;/em> por debajo del 5 %, el ancho de banda requerido es:&lt;/p>
$$B_{\text{req}} = \frac{S_{\text{ckpt}}}{t_{\text{win}}}$$
&lt;p>Para un modelo de 1T en 100.000 aceleradores, la ventana cae a unos 4,4 segundos. Escribir 15 TB en ese tiempo exige del orden de 3,6 TB/s a través del cluster, o unos 200 GB/s sostenidos a lo largo de todo el &lt;em>job&lt;/em>. Solo en &lt;em>checkpoints&lt;/em>, ese escenario genera más de 14 PB de escrituras al día. No es una carga marginal: es una de las cargas de escritura más exigentes que existen.&lt;/p>
&lt;p>Conviene ver el cálculo desplegado, porque revela dónde está la palanca. Tomemos el modelo de 405B, cuyo &lt;em>checkpoint&lt;/em> pesa 5,29 TB. Si la política exige escribirlo manteniendo el &lt;em>overhead&lt;/em> por debajo del 5 % en una cadencia donde la ventana aceptable es, digamos, de 30 segundos, el ancho de banda síncrono necesario es de unos 176 GB/s sostenidos —al alcance de una cabina de gama alta, pero solo dedicada a esa tarea—. Si en lugar de 30 segundos la ventana se contrae a 5 (clúster más grande, fallos más frecuentes), el requisito salta por encima de 1 TB/s. La sensibilidad a la ventana es brutal: la diferencia entre un diseño viable y uno imposible está en cómo se gestiona el tiempo, no en cuántos discos se compran. Ahí es donde la asincronía cambia las reglas.&lt;/p>
&lt;p>&lt;strong>La solución no es solo más ancho de banda; es asincronía.&lt;/strong> El &lt;em>checkpointing asíncrono&lt;/em> desacopla el &lt;em>snapshot&lt;/em> (copia GPU→CPU, rápida) de la persistencia (escritura en segundo plano, solapada con el cómputo). El &lt;em>Distributed Async Checkpointing&lt;/em> de PyTorch reduce el tiempo efectivo de &lt;em>checkpoint&lt;/em> entre 10 y 20 veces; en un ejemplo de IBM, un modelo de 7B bajó su &lt;em>down time&lt;/em> de 148,8 a 6,3 segundos, una mejora de 23,6 veces. Técnicas como CheckFreq pipelinean el &lt;em>snapshot&lt;/em> y la persistencia con el entrenamiento, permitiendo &lt;em>checkpointear&lt;/em> cada 14-19 iteraciones. Por eso proveedores como VAST sostienen que la métrica relevante no es GB/s sino el &lt;em>checkpoint overlap&lt;/em>: qué fracción del &lt;em>checkpoint&lt;/em> se solapa con el cómputo. Un 10 % de solapamiento suele bastar.&lt;/p>
&lt;p>La lección de diseño es clara: dimensionar el almacenamiento de entrenamiento por el pico de escritura del &lt;em>checkpointing&lt;/em> síncrono es caro y, a menudo, innecesario si la pila de software hace bien la asincronía. Pero confiar en la asincronía sin medir el &lt;em>overlap&lt;/em> es jugar a la ruleta con semanas de cómputo.&lt;/p>
&lt;h2 id="el-rendimiento-de-una-factoría-de-inferencia">El rendimiento de una factoría de inferencia&lt;/h2>
&lt;p>Aquí está el corazón del asunto para quien explota una factoría de inferencia. En una factoría de inferencia el almacenamiento no se mide en épocas ni en GPU-horas, sino en la experiencia que percibe el cliente, y esa experiencia se condensa en dos métricas: el &lt;strong>TTFT&lt;/strong> (&lt;em>time to first token&lt;/em>, el tiempo hasta el primer token de respuesta) y la &lt;strong>latencia inter-token&lt;/strong> (la velocidad a la que llegan los tokens siguientes). A escala de flota, la métrica que paga las facturas es el &lt;strong>throughput en tokens por segundo&lt;/strong> por GPU, porque determina cuántas peticiones atiende cada acelerador. El almacenamiento toca las tres, y de formas que un diseño centrado solo en entrenamiento no anticipa.&lt;/p>
&lt;h3 id="prefill-decode-y-su-desagregación">Prefill, decode y su desagregación&lt;/h3>
&lt;p>La inferencia tiene dos fases con perfiles opuestos. El &lt;strong>prefill&lt;/strong> procesa todo el &lt;em>prompt&lt;/em> de entrada de una vez, genera los pares clave-valor del KV-cache y es una fase intensiva en cómputo; domina el TTFT. El &lt;strong>decode&lt;/strong> genera los tokens uno a uno reutilizando ese caché, es intensivo en ancho de banda de memoria y domina la latencia inter-token. Como sus cuellos de botella son distintos, la tendencia de 2025-2026 es &lt;strong>desagregarlas&lt;/strong>: ejecutar el &lt;em>prefill&lt;/em> y el &lt;em>decode&lt;/em> en &lt;em>pools&lt;/em> de GPU separados y transferir el KV-cache entre ellos. Esa transferencia —que puede ir por NVLink, por red o a través de una capa de almacenamiento compartida— convierte el movimiento del KV-cache en una operación de rendimiento crítico. Una factoría que desagrega prefill y decode necesita una vía de KV-cache de altísimo ancho de banda y baja latencia entre ambos &lt;em>pools&lt;/em>; el almacenamiento (o la DPU que lo gobierna) deja de ser un actor pasivo y entra en el camino crítico de cada petición.&lt;/p>
&lt;h3 id="el-kv-cache-como-capa-de-rendimiento">El KV-cache como capa de rendimiento&lt;/h3>
&lt;p>El problema central es el tamaño del KV-cache con contextos largos: desborda la HBM, que es escasa y cara. Las opciones son recomputarlo en cada petición —carísimo en cómputo y letal para el TTFT— o descargarlo a una capa más lenta y reutilizarlo. Aquí compiten dos enfoques. El &lt;em>offload&lt;/em> a memoria &lt;strong>CXL&lt;/strong> ofrece mejoras de más de 5 veces frente al &lt;em>caching&lt;/em> basado en SSD o RDMA, según los proveedores de la cadena CXL, y permite manejar &lt;em>batches&lt;/em> hasta un 30 % más grandes manteniendo los objetivos de latencia, lo que sube el &lt;em>throughput&lt;/em> y la utilización de GPU. El &lt;em>offload&lt;/em> a &lt;strong>NVMe&lt;/strong>, estandarizado por NVIDIA en 2026 con su plataforma ICMS sobre BlueField-4, es más lento pero mucho más barato y capaz, idóneo para KV-cache a escala de &lt;em>pod&lt;/em>.&lt;/p>
&lt;p>La gran palanca de rendimiento aquí es la &lt;strong>reutilización de KV-cache&lt;/strong> (&lt;em>prefix caching&lt;/em>). Muchas peticiones comparten prefijos: el mismo &lt;em>system prompt&lt;/em>, el mismo documento de contexto, la misma conversación previa. Si el KV-cache de esos prefijos se conserva en una capa de almacenamiento rápida y se reutiliza en lugar de recomputarse, el &lt;em>prefill&lt;/em> se acorta drásticamente y el TTFT se desploma. Esto convierte una capa de almacenamiento de baja latencia en un multiplicador directo del throughput de la factoría: cuanto más caché útil quepa y más rápido se sirva, menos cómputo se desperdicia recalculando lo ya calculado. Dimensionar bien esta capa —capacidad, ancho de banda, latencia, política de expulsión— es una de las decisiones de rendimiento más rentables de toda la factoría.&lt;/p>
&lt;h3 id="el-tiempo-de-carga-de-modelos-y-el-cold-start">El tiempo de carga de modelos y el cold start&lt;/h3>
&lt;p>Hay un coste de almacenamiento específico de la inferencia que el entrenamiento ignora: &lt;strong>arrancar una réplica&lt;/strong>. Cuando el autoescalado decide levantar una instancia nueva de un modelo —porque sube la demanda, porque falla una réplica o porque se rota una versión—, hay que leer los pesos del repositorio y cargarlos en la HBM. Para un modelo de decenas o cientos de GB, ese &lt;em>cold start&lt;/em> puede ir de segundos a minutos según el ancho de banda del repositorio y la ruta de carga. Y durante ese tiempo, la GPU nueva no atiende peticiones mientras el sistema, quizá, está saturado. Un repositorio de modelos lento se traduce directamente en SLA incumplidos en los picos. Las mitigaciones —mantener los pesos en flash local caliente, usar formatos de carga rápida, &lt;em>streaming&lt;/em> de pesos a medida que se necesitan, o GPUDirect Storage para cargar directamente a la HBM— son decisiones de almacenamiento que determinan la elasticidad real de la factoría.&lt;/p>
&lt;h3 id="el-rendimiento-de-rag-y-la-búsqueda-vectorial">El rendimiento de RAG y la búsqueda vectorial&lt;/h3>
&lt;p>Si la factoría sirve RAG, hay un eslabón más en el camino crítico de cada petición: la recuperación. Antes de que el modelo genere nada, el sistema busca en una base de datos vectorial los fragmentos relevantes, y esa búsqueda de similitud —sobre índices que pueden ocupar TB— se suma al TTFT. El rendimiento de la búsqueda vectorial depende de mantener los índices en flash de baja latencia y de un patrón de lectura aleatoria eficiente; un índice que no cabe en memoria y se sirve desde almacenamiento lento añade latencia a cada petición. Además, los KV-cache precomputados de los documentos recuperados aceleran el &lt;em>prefill&lt;/em>, porque el modelo reutiliza claves y valores ya calculados y solo codifica la consulta del usuario. La factoría de inferencia con RAG, por tanto, tiene dos cargas de lectura sensibles a latencia conviviendo —el índice vectorial y el KV-cache— que compiten por el mismo flash rápido y que hay que dimensionar juntas.&lt;/p>
&lt;p>Para un arquitecto de inferencia, todo esto introduce un plano de almacenamiento con un perfil propio: lecturas aleatorias sensibles a latencia (índices, prefijos de KV-cache reutilizables), escrituras efímeras de alta rotación (KV-cache nuevo), lecturas grandes y esporádicas pero urgentes (carga de modelos) y un flujo append-only de telemetría. No se dimensiona, en absoluto, como el almacenamiento de un clúster de entrenamiento.&lt;/p>
&lt;h2 id="cómo-medir-lo-propio-más-allá-de-la-hoja-de-especificaciones">Cómo medir lo propio: más allá de la hoja de especificaciones&lt;/h2>
&lt;p>Las cifras de los fabricantes y de MLPerf son útiles como referencia, pero el rendimiento real depende de la carga concreta, y un arquitecto debe medir, no asumir. La metodología que funciona parte de tres principios.&lt;/p>
&lt;p>El primero es &lt;strong>medir la utilización del acelerador, no el almacenamiento en abstracto&lt;/strong>. Una cabina puede entregar 500 GB/s en una prueba sintética y, sin embargo, dejar las GPU al 50 % porque el patrón real es de archivos pequeños y aleatorios que la prueba secuencial no reproduce. La pregunta correcta siempre es: ¿qué fracción del tiempo está calculando mi GPU con esta carga, este formato de dataset y este &lt;em>pipeline&lt;/em>?&lt;/p>
&lt;p>El segundo es &lt;strong>reproducir el patrón de I/O real&lt;/strong>, no uno cómodo. Esto implica probar con el mismo formato de dataset, el mismo tamaño de &lt;em>shard&lt;/em>, el mismo número de &lt;em>workers&lt;/em> y la misma cadencia de &lt;em>checkpointing&lt;/em> que se usarán en producción. El acierto de MLPerf Storage fue precisamente simular el &lt;em>think time&lt;/em> del acelerador para generar un patrón realista; replicar ese rigor a escala propia es lo que separa una medición útil de un número de &lt;em>marketing&lt;/em>.&lt;/p>
&lt;p>El tercero es &lt;strong>buscar el escalado, no el pico&lt;/strong>. Una plataforma que entrega un pico altísimo en una configuración pequeña pero se aplana al añadir nodos no sirve para crecer. Las pruebas deben hacerse a varias escalas para verificar que el &lt;em>throughput&lt;/em> crece de forma aproximadamente lineal y que la utilización del acelerador se mantiene, como mostraba el ejemplo de Hammerspace en MLPerf v2.0. Un coeficiente de variación bajo entre configuraciones es tan importante como el pico.&lt;/p>
&lt;h2 id="el-coste-de-equivocarse">El coste de equivocarse&lt;/h2>
&lt;p>Conviene poner número al problema. El precio de una H100 en la nube a mediados de 2026 se mueve en un rango amplio según proveedor, con una mediana de mercado en torno a 2,3-3,1 USD por hora y GPU. Multiplíquese por miles de GPU y por las semanas que dura un entrenamiento, y un 40 % de utilización en lugar de un 90 % se traduce en millones de euros de cómputo desperdiciado. Por eso más del 50 % de las organizaciones reportan en 2026 cuellos de botella de datos o almacenamiento que limitan su IA, y por eso el ancho de banda de almacenamiento ha emergido como un techo duro al escalado, comparable a la energía y la refrigeración: cuando hay &lt;em>data starvation&lt;/em>, añadir cómputo da rendimientos decrecientes.&lt;/p>
&lt;p>La recomendación operativa que se repite es dimensionar el &lt;em>pipeline&lt;/em> de I/O para 300 Gbps o más en cargas serias, y medir —no asumir— la utilización del acelerador como indicador de salud. Un almacenamiento optimizado puede entregar hasta 5 veces el &lt;em>throughput&lt;/em> de un acceso S3 estándar sobre HTTP: más de 100 GB/s agregados frente a unos 20 GB/s.&lt;/p>
&lt;h2 id="la-capa-física-redes-y-pcie-gen6">La capa física: redes y PCIe Gen6&lt;/h2>
&lt;p>Todo lo anterior se apoya en una capa física que también ha avanzado. La NIC ConnectX-8 de NVIDIA combina PCIe Gen6 con 800 GbE u 800 Gb de InfiniBand XDR, diseñada para los sistemas Blackwell. InfiniBand XDR ofrece 800 Gbps por dirección (el doble que NDR, que sigue siendo el &lt;em>storage fabric&lt;/em> habitual), y el &lt;em>switch&lt;/em> Quantum-X800 añade cómputo en red que acelera las operaciones colectivas. La transición a XDR se acelera con los despliegues Blackwell de 2025-2026. La regla mental es sencilla: el almacenamiento debe estar a la altura de la red, y la red, a la altura de la GPU. Un eslabón lento define el rendimiento de toda la cadena.&lt;/p>
&lt;p>Merece la pena traducir esto a números concretos. Una NIC de 800 Gb/s entrega, en el mejor caso, unos 100 GB/s a un nodo. Si la cabina puede servir más de lo que la NIC absorbe, la red es el cuello de botella; si la cabina sirve menos, lo es el almacenamiento. El equilibrio se busca dimensionando cada capa para que ninguna estrangule a la siguiente, y verificándolo con medidas de extremo a extremo, no con las especificaciones aisladas de cada componente. Es habitual encontrar instalaciones con una cabina excelente y una &lt;em>fabric&lt;/em> infradimensionada —o al revés— que rinden muy por debajo de la suma de sus partes. La capa física también impone su geografía: la &lt;em>topología&lt;/em> de la red (cuántos saltos hay entre el nodo de cómputo y la cabina, si comparten conmutador o atraviesan la columna vertebral del clúster) afecta a la latencia tanto como la propia cabina, y un diseño de almacenamiento para IA que ignore la topología de red está incompleto.&lt;/p>
&lt;h2 id="tres-preguntas-antes-de-dimensionar">Tres preguntas antes de dimensionar&lt;/h2>
&lt;p>Toda esta complejidad se puede ordenar en tres preguntas que un arquitecto debería responder antes de comprar nada. ¿Cuál es el patrón de I/O dominante de mi carga —secuencial grande, aleatorio pequeño, escritura en ráfagas— y, por tanto, qué métrica me limita? ¿Está mi carga limitada por ancho de banda o por latencia, y en consecuencia dónde invierto? ¿Y cuál es mi presupuesto de &lt;em>checkpointing&lt;/em> —tamaño, cadencia y, sobre todo, qué fracción puedo solapar con el cómputo? Quien responde estas tres con datos medidos, y no con intuiciones, dimensiona bien; quien las salta acaba con GPU ociosas o con una cabina sobredimensionada y carísima que nunca se aprovecha. El rendimiento del almacenamiento de IA es, en el fondo, un ejercicio de adecuación: poner la capacidad correcta donde la carga la necesita, ni más ni menos.&lt;/p>
&lt;h2 id="para-llevarse-a-casa">Para llevarse a casa&lt;/h2>
&lt;p>El rendimiento del almacenamiento para IA no se mide en GB/s sino en utilización del acelerador, y esa utilización depende de tres cosas: ancho de banda suficiente, latencia baja y, sobre todo, solapamiento de la I/O con el cómputo. MLPerf Storage v2.0 ha dado por fin un lenguaje común para comparar plataformas con esa óptica. El &lt;em>checkpointing&lt;/em> es la carga de escritura más exigente y se domina con asincronía, no solo con hardware. La inferencia de contexto largo añade una capa de almacenamiento nueva alrededor del KV-cache. Y el coste de equivocarse se mide en GPU ociosas, que es la partida más cara del presupuesto.&lt;/p>
&lt;p>El rendimiento, sin embargo, no sirve de nada si los datos no están protegidos ni disponibles. El &lt;a href="https://blog.lo0.es/posts/almacenamiento-ia-seguridad/">tercer artículo&lt;/a> aborda la seguridad de esta nueva capa de almacenamiento.&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/almacenamiento-ia-estado-del-arte/">Almacenamiento en la era de la IA (1/4): el estado del arte&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/almacenamiento-ia-seguridad/">Almacenamiento en la era de la IA (3/4): seguridad&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/almacenamiento-ia-disponibilidad/">Almacenamiento en la era de la IA (4/4): disponibilidad&lt;/a>&lt;/li>
&lt;/ul>
&lt;h2 id="fuentes">Fuentes&lt;/h2>
&lt;ul>
&lt;li>MLCommons, &lt;em>MLPerf Storage v2.0 Results&lt;/em> — &lt;a href="https://mlcommons.org/2025/08/mlperf-storage-v2-0-results/">https://mlcommons.org/2025/08/mlperf-storage-v2-0-results/&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>Announcing the MLPerf Storage v2.0 Checkpointing Workload&lt;/em> — &lt;a href="https://mlcommons.org/2025/08/storage-2-checkpointing/">https://mlcommons.org/2025/08/storage-2-checkpointing/&lt;/a>&lt;/li>
&lt;li>MLCommons, &lt;em>MLPerf Storage v1.0 Benchmark Results&lt;/em> — &lt;a href="https://mlcommons.org/2024/09/mlperf-storage-v1-0-benchmark-results/">https://mlcommons.org/2024/09/mlperf-storage-v1-0-benchmark-results/&lt;/a>&lt;/li>
&lt;li>Hammerspace, &lt;em>MLPerf Storage v2.0 Benchmark Results&lt;/em> — &lt;a href="https://hammerspace.com/hammerspace-mlperf-storage-v2-0-benchmark-results/">https://hammerspace.com/hammerspace-mlperf-storage-v2-0-benchmark-results/&lt;/a>&lt;/li>
&lt;li>Alluxio, &lt;em>Strong Performance in MLPerf Storage v2.0&lt;/em> — &lt;a href="https://www.alluxio.io/blog/alluxio-demonstrates-strong-performance-in-mlperf-storage-v2-0-benchmarks">https://www.alluxio.io/blog/alluxio-demonstrates-strong-performance-in-mlperf-storage-v2-0-benchmarks&lt;/a>&lt;/li>
&lt;li>NVIDIA, &lt;em>GPUDirect Storage Overview Guide&lt;/em> — &lt;a href="https://docs.nvidia.com/gpudirect-storage/overview-guide/index.html">https://docs.nvidia.com/gpudirect-storage/overview-guide/index.html&lt;/a>&lt;/li>
&lt;li>Spheron, &lt;em>GPU Direct Storage Guide 2026&lt;/em> — &lt;a href="https://www.spheron.network/blog/gpu-direct-storage-nvme-ai-training-inference-guide/">https://www.spheron.network/blog/gpu-direct-storage-nvme-ai-training-inference-guide/&lt;/a>&lt;/li>
&lt;li>PyTorch, &lt;em>Reducing Checkpointing Times with Async Checkpointing&lt;/em> — &lt;a href="https://pytorch.org/blog/reducing-checkpointing-times/">https://pytorch.org/blog/reducing-checkpointing-times/&lt;/a>&lt;/li>
&lt;li>VAST Data, &lt;em>Optimizing Checkpoint Bandwidth for LLM Training&lt;/em> — &lt;a href="https://www.vastdata.com/blog/optimizing-checkpoint-bandwidth-for-llm-training">https://www.vastdata.com/blog/optimizing-checkpoint-bandwidth-for-llm-training&lt;/a>&lt;/li>
&lt;li>Astera Labs, &lt;em>How CXL Transforms RAG and KV Cache Performance&lt;/em> — &lt;a href="https://www.asteralabs.com/breaking-through-the-memory-wall-how-cxl-transforms-rag-and-kv-cache-performance/">https://www.asteralabs.com/breaking-through-the-memory-wall-how-cxl-transforms-rag-and-kv-cache-performance/&lt;/a>&lt;/li>
&lt;li>MinIO, &lt;em>AI Storage Architecture: Overcoming the Bottleneck in 2026&lt;/em> — &lt;a href="https://www.min.io/blog/ai-storage-architecture-bottleneck-2026">https://www.min.io/blog/ai-storage-architecture-bottleneck-2026&lt;/a>&lt;/li>
&lt;li>WEKA, &lt;em>WEKApod Nitro reference architecture&lt;/em> — &lt;a href="https://www.weka.io/resources/reference-architecture/nvidia-gb200-nvl72-systems-reference-architecture-for-cloud-partners/">https://www.weka.io/resources/reference-architecture/nvidia-gb200-nvl72-systems-reference-architecture-for-cloud-partners/&lt;/a>&lt;/li>
&lt;li>Blocks &amp;amp; Files, &lt;em>Storage vendors rally behind Nvidia at GTC 2025&lt;/em> — &lt;a href="https://blocksandfiles.com/2025/03/18/nvidia-storage-announcements/">https://blocksandfiles.com/2025/03/18/nvidia-storage-announcements/&lt;/a>&lt;/li>
&lt;li>ServeTheHome, &lt;em>NVIDIA ConnectX-8 SuperNIC PCIe Gen6 800G&lt;/em> — &lt;a href="https://www.servethehome.com/nvidia-connectx-8-supernic-pcie-gen6-800g-nic-detailed/">https://www.servethehome.com/nvidia-connectx-8-supernic-pcie-gen6-800g-nic-detailed/&lt;/a>&lt;/li>
&lt;li>SpendArk, &lt;em>GPU Cloud Pricing 2026&lt;/em> — &lt;a href="https://spendark.com/blog/machine-learning-cloud-cost/">https://spendark.com/blog/machine-learning-cloud-cost/&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Catálogo de herramientas de benchmark LLM: ficha práctica a fondo</title><link>https://blog.lo0.es/posts/herramientas-benchmark-llm-ficha-a-ficha/</link><pubDate>Sun, 14 Jun 2026 02:00:00 +0200</pubDate><guid>https://blog.lo0.es/posts/herramientas-benchmark-llm-ficha-a-ficha/</guid><description>&lt;blockquote>
&lt;p>Notación: importes en &lt;strong>euros (N €)&lt;/strong>, decimales con coma. No se usa el símbolo de dólar
(en este sitio es delimitador de fórmula).&lt;/p>
&lt;/blockquote>
&lt;h2 id="qué-cubre-este-artículo">Qué cubre este artículo&lt;/h2>
&lt;p>Segundo artículo del track de &lt;strong>benchmarking&lt;/strong> (B2). La &lt;a href="https://blog.lo0.es/posts/benchmarking-llm-frameworks-estado-del-arte/">introducción B1&lt;/a>
fijó las métricas y la metodología; este artículo es el &lt;strong>manual práctico&lt;/strong>: para cada
herramienta, qué mide, &lt;strong>cómo se invoca de verdad&lt;/strong> (con el comando), qué formato de salida da
y cuándo elegirla. El objetivo es que, tras leerlo, sepas qué ejecutar para medir tu motor y
puedas reproducir el número. Sin recomendaciones universales; solo la mecánica de cada
herramienta y el criterio para escoger.&lt;/p>
&lt;hr>
&lt;h2 id="cómo-elegir-el-mapa-de-herramientas">Cómo elegir: el mapa de herramientas&lt;/h2>
&lt;p>Recordando la división de B1, las herramientas se ordenan en dos ejes: &lt;strong>micro-bench&lt;/strong>
(mono-proceso, para tunear un motor) vs &lt;strong>generador de carga&lt;/strong> (multi-proceso, para medir
capacidad real), y &lt;strong>propias del motor&lt;/strong> vs &lt;strong>agnósticas del endpoint&lt;/strong>.&lt;/p>
&lt;div class="diagram" style="max-width:780px;margin:1rem auto;">
&lt;svg viewBox="0 0 780 250" role="img" aria-label="Mapa de herramientas de benchmark por dos ejes: micro-bench mono-proceso vs generador de carga multi-proceso, y propio del motor vs agnostico del endpoint" xmlns="http://www.w3.org/2000/svg">
&lt;style>.ax{fill:none;stroke:currentColor;stroke-width:1}.bx{fill:none;stroke:currentColor;stroke-width:1.2}.tl{font:600 12px sans-serif;fill:currentColor}.ts{font:11px sans-serif;fill:currentColor}&lt;/style>
&lt;line class="ax" x1="60" y1="200" x2="720" y2="200"/>
&lt;line class="ax" x1="390" y1="40" x2="390" y2="200"/>
&lt;text x="70" y="216" class="ts">micro-bench (mono-proceso)&lt;/text>
&lt;text x="560" y="216" class="ts">generador de carga (multi-proceso)&lt;/text>
&lt;text x="400" y="52" class="ts">↑ agnóstico del endpoint&lt;/text>
&lt;text x="400" y="195" class="ts">↓ propio del motor&lt;/text>
&lt;rect class="bx" x="150" y="150" width="150" height="34" rx="5"/>&lt;text x="225" y="171" text-anchor="middle" class="ts">vLLM bench / SGLang bench&lt;/text>
&lt;rect class="bx" x="470" y="70" width="120" height="34" rx="5"/>&lt;text x="530" y="91" text-anchor="middle" class="ts">AIPerf&lt;/text>
&lt;rect class="bx" x="470" y="115" width="120" height="34" rx="5"/>&lt;text x="530" y="136" text-anchor="middle" class="ts">GuideLLM&lt;/text>
&lt;rect class="bx" x="610" y="93" width="110" height="34" rx="5"/>&lt;text x="665" y="114" text-anchor="middle" class="ts">LLMPerf&lt;/text>
&lt;rect class="bx" x="150" y="60" width="150" height="34" rx="5"/>&lt;text x="225" y="81" text-anchor="middle" class="ts">MLPerf (suite estándar)&lt;/text>
&lt;text x="60" y="240" class="ts">Para tunear un motor concreto: micro-bench. Para medir capacidad bajo SLO: generador de carga. Para comparar fabricantes: MLPerf.&lt;/text>
&lt;/svg>
&lt;/div>
&lt;hr>
&lt;h2 id="datasets-la-carga-sintética-importa-tanto-como-la-herramienta">Datasets: la carga sintética importa tanto como la herramienta&lt;/h2>
&lt;p>Antes de las fichas, un punto que cambia los resultados sin que se note: &lt;strong>qué carga le metes&lt;/strong>.
Las herramientas aceptan distintos tipos de dataset, y cada uno mide algo distinto:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Dataset&lt;/th>
&lt;th>Qué simula&lt;/th>
&lt;th>Sesgo que introduce&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>random&lt;/strong> (longitudes fijas)&lt;/td>
&lt;td>carga uniforme controlada&lt;/td>
&lt;td>irreal: el tráfico no es de longitud fija&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>sharegpt&lt;/strong> (conversaciones reales)&lt;/td>
&lt;td>distribución realista de prompts&lt;/td>
&lt;td>el estándar de facto para comparar&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>trazas propias&lt;/strong>&lt;/td>
&lt;td>tu tráfico real&lt;/td>
&lt;td>el más fiel, pero específico de tu caso&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>La trampa: un benchmark con prompts cortos de longitud fija da un throughput altísimo que &lt;strong>no
se parece a producción&lt;/strong>, donde las longitudes varían y los prompts largos dominan el coste de
prefill. Para una cifra defendible, usa &lt;strong>sharegpt&lt;/strong> (comparabilidad) o, mejor, &lt;strong>trazas de tu
propio tráfico&lt;/strong> (fidelidad). Y declara siempre la distribución de longitudes (prompt/salida)
junto al número, porque dos benchmarks con datasets distintos &lt;strong>no son comparables&lt;/strong> aunque
usen la misma herramienta.&lt;/p>
&lt;hr>
&lt;h2 id="vllm-bench-serve">vLLM bench serve&lt;/h2>
&lt;p>Qué mide: TTFT, TPOT, throughput y latencias del &lt;strong>servidor vLLM&lt;/strong> bajo una carga sintética.
Clase: micro-bench (mono-proceso). Es la herramienta para &lt;strong>tunear vLLM&lt;/strong> y ver el efecto de
sus optimizaciones (&lt;a href="https://blog.lo0.es/posts/decode-optimizaciones-vllm/">decode&lt;/a>, &lt;a href="https://blog.lo0.es/posts/prefill-optimizaciones-vllm/">prefill&lt;/a>).&lt;/p>
&lt;p>Invocación típica (&lt;a href="https://docs.vllm.ai/en/latest/cli/bench/serve/">vLLM · CLI de benchmark&lt;/a>):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">vllm bench serve &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --backend vllm &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --model meta-llama/Llama-3.1-8B-Instruct &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --endpoint /v1/completions &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --dataset-name sharegpt &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --dataset-path ShareGPT_V3_unfiltered_cleaned_split.json &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --num-prompts &lt;span class="m">1000&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Parámetros clave: &lt;code>--num-prompts&lt;/code> (carga), &lt;code>--dataset-name&lt;/code> (sharegpt, random, etc.),
&lt;code>--request-rate&lt;/code> (peticiones/s). La salida es un &lt;strong>resumen por consola&lt;/strong> con TTFT, TPOT,
throughput y percentiles, y puede volcarse a JSON. Para barrer concurrencias existe &lt;strong>&lt;code>vllm bench sweep serve&lt;/code>&lt;/strong>, que automatiza el sweep (&lt;a href="https://docs.vllm.ai/en/latest/cli/bench/sweep/serve/">vLLM · sweep&lt;/a>).&lt;/p>
&lt;p>Límite: mono-proceso, se satura en el cliente a alta concurrencia; menos flexible que GuideLLM
en datasets y patrones de carga. Úsalo para iterar rápido sobre la config de vLLM, no para
medir la capacidad máxima a escala.&lt;/p>
&lt;hr>
&lt;h2 id="sglang-bench">SGLang bench&lt;/h2>
&lt;p>Qué mide: el equivalente para el motor &lt;strong>SGLang&lt;/strong> (TTFT, TPOT, throughput). Clase: micro-bench.
Uso: tunear SGLang y compararlo consigo mismo entre configuraciones. La mecánica es análoga a
&lt;code>vllm bench serve&lt;/code>: una carga sintética, salida por consola/JSON con las mismas métricas. Si
evalúas SGLang vs vLLM, &lt;strong>no&lt;/strong> los compares con sus micro-benchs respectivos (clases iguales
pero implementaciones distintas): usa un generador de carga agnóstico (GuideLLM/AIPerf) contra
ambos endpoints, para que la herramienta no sea la variable.&lt;/p>
&lt;hr>
&lt;h2 id="aiperf-nvidia-ex-genai-perf">AIPerf (NVIDIA, ex genai-perf)&lt;/h2>
&lt;p>Qué mide: TTFT, ITL, throughput y latencia sobre &lt;strong>cualquier endpoint compatible&lt;/strong> (vLLM, NIM,
TGI, SGLang). Clase: generador de carga &lt;strong>multi-proceso&lt;/strong>. Es el sucesor de genai-perf
(jubilado el 15-abr-2026). Su rasgo distintivo: durante el sweep &lt;strong>detecta la saturación de la
GPU&lt;/strong> y devuelve la iteración anterior como &lt;code>estimatedCapacity&lt;/code>; por eso hay que extender el
sweep &lt;strong>más allá del codo&lt;/strong> (&lt;a href="https://lucaberton.com/blog/nvidia-aiperf-llm-inference-benchmarking-guide/">AIPerf&lt;/a>).&lt;/p>
&lt;p>Salida: métricas estructuradas (JSON) con distribuciones de TTFT/ITL y el &lt;code>estimatedCapacity&lt;/code>.
Úsalo cuando quieras la &lt;strong>capacidad real&lt;/strong> de un endpoint, sea cual sea el motor, con la
detección automática del punto de saturación.&lt;/p>
&lt;hr>
&lt;h2 id="guidellm-proyecto-vllm">GuideLLM (proyecto vLLM)&lt;/h2>
&lt;p>Qué mide: distribuciones completas de TTFT, ITL y comportamiento de extremo a extremo, para
evaluación &lt;strong>dirigida por SLO&lt;/strong>. Clase: generador de carga multi-proceso. Es la herramienta
recomendada para benchmarkear servidores vLLM en producción: más flexible que &lt;code>vllm bench serve&lt;/code> en carga de datasets, formato de peticiones y patrones de tráfico, con &lt;strong>progreso en
vivo y generación automática de informe&lt;/strong> (&lt;a href="https://developers.redhat.com/articles/2025/12/24/how-deploy-and-benchmark-vllm-guidellm-kubernetes">Red Hat&lt;/a>).&lt;/p>
&lt;p>Invocación típica:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">guidellm benchmark &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --target &lt;span class="s2">&amp;#34;http://localhost:8000&amp;#34;&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --rate-type throughput &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --max-requests &lt;span class="m">1000&lt;/span> &lt;span class="se">\
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="se">&lt;/span> --data &lt;span class="s2">&amp;#34;samples=1000,prompt_tokens=1024,output_tokens=256&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Parámetros clave: &lt;code>--rate-type&lt;/code> (&lt;code>synchronous&lt;/code>, &lt;code>concurrent&lt;/code>, &lt;code>throughput&lt;/code>, o por tasa),
&lt;code>--data&lt;/code> (especificación de la carga: nº de muestras y longitudes de prompt/salida), &lt;code>--target&lt;/code>
(el endpoint). Genera &lt;strong>sweeps reproducibles&lt;/strong> para hallar el rango de operación seguro bajo
SLO, con distribuciones completas (no solo medias). Salida: informe con percentiles y, a
menudo, exportable a JSON/HTML. Es la opción por defecto para responder &amp;ldquo;¿hasta dónde cargo
este motor sin romper el SLO?&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="llmperf-anyscaleray">LLMPerf (Anyscale/Ray)&lt;/h2>
&lt;p>Qué mide: throughput y latencia a nivel de inferencia. Clase: generador de carga. Uso:
validación de endpoints, históricamente muy extendido en el ecosistema Ray/Anyscale. Es una
opción sólida y conocida, aunque menos centrada en distribuciones y sweeps que GuideLLM/AIPerf.
Encaja si ya operas en Ray o quieres una herramienta simple para validar un endpoint.&lt;/p>
&lt;hr>
&lt;h2 id="inference-benchmarker-hugging-face">inference-benchmarker (Hugging Face)&lt;/h2>
&lt;p>Qué mide: latencia y throughput de endpoints de inferencia, con orientación a generar informes
comparables. Clase: generador de carga. Uso: alternativa OSS dentro del ecosistema Hugging
Face, útil si ya trabajas con TGI o el stack de HF. Como las demás de su clase, su valor está
en medir capacidad real con carga distribuida; la elección entre ésta, GuideLLM y AIPerf
suele venir por el ecosistema en el que ya operas más que por diferencias de fondo en lo que
miden.&lt;/p>
&lt;hr>
&lt;h2 id="guidellm-vs-aiperf-cuál-de-los-dos-generadores-de-carga">GuideLLM vs AIPerf: cuál de los dos generadores de carga&lt;/h2>
&lt;p>Son las dos opciones serias de carga multi-proceso, y se solapan mucho. Las diferencias
prácticas que inclinan la elección:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Criterio&lt;/th>
&lt;th>GuideLLM&lt;/th>
&lt;th>AIPerf&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Origen&lt;/td>
&lt;td>proyecto vLLM (Red Hat)&lt;/td>
&lt;td>NVIDIA (sucesor de genai-perf)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Foco&lt;/td>
&lt;td>evaluación dirigida por &lt;strong>SLO&lt;/strong>, sweeps reproducibles&lt;/td>
&lt;td>capacidad real, &lt;strong>estimatedCapacity&lt;/strong> automático&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Patrones de carga&lt;/td>
&lt;td>síncrono, concurrente, por tasa&lt;/td>
&lt;td>sweep con detección de saturación&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Informe&lt;/td>
&lt;td>progreso en vivo + informe automático&lt;/td>
&lt;td>métricas estructuradas (JSON)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Ecosistema&lt;/td>
&lt;td>vLLM / OpenShift AI&lt;/td>
&lt;td>NVIDIA NIM / Triton / vLLM&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>En la práctica: si tu pregunta es &amp;ldquo;¿hasta dónde cargo sin romper el SLO?&amp;rdquo;, &lt;strong>GuideLLM&lt;/strong> la
responde de forma más directa con sus sweeps dirigidos por SLO; si tu pregunta es &amp;ldquo;¿cuál es la
capacidad máxima de este endpoint?&amp;rdquo;, &lt;strong>AIPerf&lt;/strong> la da con su detección automática del codo. Muchos
equipos usan los dos: GuideLLM para el SLO operativo, AIPerf para la capacidad de referencia. Lo
que &lt;strong>no&lt;/strong> debes hacer es comparar un resultado de GuideLLM con uno de AIPerf como si fueran la
misma medida: aunque ambos sean multi-proceso, su metodología de sweep difiere; elige uno para
una comparación dada y mantenlo.&lt;/p>
&lt;hr>
&lt;h2 id="mlperf-inference-mlcommons">MLPerf Inference (MLCommons)&lt;/h2>
&lt;p>Qué mide: rendimiento bajo &lt;strong>escenarios normalizados&lt;/strong> (Offline, Server, Interactive) con
reglas estrictas. A diferencia de las anteriores, &lt;strong>MLPerf no se &amp;ldquo;ejecuta&amp;rdquo; para tu caso del
día a día&lt;/strong>: es una suite de comparación entre fabricantes cuyos resultados se &lt;strong>leen&lt;/strong>
(publicados por NVIDIA, AMD, Intel, etc.). Úsalo para comparar hardware/motores entre sí con
reglas idénticas, no para dimensionar tu carga concreta —para eso, GuideLLM/AIPerf sobre tu
endpoint—.&lt;/p>
&lt;hr>
&lt;h2 id="tabla-comparativa-práctica">Tabla comparativa práctica&lt;/h2>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Herramienta&lt;/th>
&lt;th>Clase&lt;/th>
&lt;th>Comando base&lt;/th>
&lt;th>Salida&lt;/th>
&lt;th>Cuándo&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>vllm bench serve&lt;/strong>&lt;/td>
&lt;td>micro&lt;/td>
&lt;td>&lt;code>vllm bench serve&lt;/code>&lt;/td>
&lt;td>consola/JSON&lt;/td>
&lt;td>tunear vLLM&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>vllm bench sweep&lt;/strong>&lt;/td>
&lt;td>micro (sweep)&lt;/td>
&lt;td>&lt;code>vllm bench sweep serve&lt;/code>&lt;/td>
&lt;td>consola/JSON&lt;/td>
&lt;td>barrer concurrencia en vLLM&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>SGLang bench&lt;/strong>&lt;/td>
&lt;td>micro&lt;/td>
&lt;td>bench del repo SGLang&lt;/td>
&lt;td>consola/JSON&lt;/td>
&lt;td>tunear SGLang&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>AIPerf&lt;/strong>&lt;/td>
&lt;td>carga&lt;/td>
&lt;td>&lt;code>aiperf profile …&lt;/code>&lt;/td>
&lt;td>JSON + estimatedCapacity&lt;/td>
&lt;td>capacidad real, multi-endpoint&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>GuideLLM&lt;/strong>&lt;/td>
&lt;td>carga&lt;/td>
&lt;td>&lt;code>guidellm benchmark …&lt;/code>&lt;/td>
&lt;td>informe + JSON/HTML&lt;/td>
&lt;td>SLO, sweep reproducible&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>LLMPerf&lt;/strong>&lt;/td>
&lt;td>carga&lt;/td>
&lt;td>script Ray/LLMPerf&lt;/td>
&lt;td>JSON&lt;/td>
&lt;td>validar endpoint (Ray)&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>MLPerf&lt;/strong>&lt;/td>
&lt;td>suite&lt;/td>
&lt;td>(se leen resultados)&lt;/td>
&lt;td>resultados oficiales&lt;/td>
&lt;td>comparar fabricantes&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="resumen-qué-ejecutas-para-cada-pregunta">Resumen: qué ejecutas para cada pregunta&lt;/h2>
&lt;p>Para no perderse en el catálogo, el mapeo directo de pregunta a herramienta:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Tu pregunta&lt;/th>
&lt;th>Herramienta&lt;/th>
&lt;th>Por qué&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&amp;ldquo;¿Mejora mi cambio de config en vLLM?&amp;rdquo;&lt;/td>
&lt;td>&lt;code>vllm bench serve&lt;/code> (+ sweep)&lt;/td>
&lt;td>rápido, propio del motor&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&amp;ldquo;¿Hasta dónde cargo sin romper el SLO?&amp;rdquo;&lt;/td>
&lt;td>GuideLLM&lt;/td>
&lt;td>sweeps dirigidos por SLO&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&amp;ldquo;¿Cuál es la capacidad máxima del endpoint?&amp;rdquo;&lt;/td>
&lt;td>AIPerf&lt;/td>
&lt;td>detección automática del codo&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&amp;ldquo;¿vLLM o SGLang para mi carga?&amp;rdquo;&lt;/td>
&lt;td>GuideLLM/AIPerf contra ambos&lt;/td>
&lt;td>misma herramienta, motor variable&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&amp;ldquo;¿Qué hardware/motor es mejor en abstracto?&amp;rdquo;&lt;/td>
&lt;td>leer MLPerf&lt;/td>
&lt;td>comparabilidad cross-vendor&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&amp;ldquo;¿Hay regresión en este release?&amp;rdquo;&lt;/td>
&lt;td>sweep corto en CI vs línea base&lt;/td>
&lt;td>detección continua&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>La regla que subyace a toda la tabla: &lt;strong>micro-bench para iterar sobre un motor, generador de
carga para medir capacidad y decidir, MLPerf para comparar fabricantes&lt;/strong>. Y, para cualquier
comparación entre sistemas, la misma herramienta para todos los candidatos. Si tienes claras
estas tres categorías, la elección concreta es secundaria.&lt;/p>
&lt;hr>
&lt;h2 id="metodología-paso-a-paso-de-un-benchmark">Metodología paso a paso de un benchmark&lt;/h2>
&lt;p>Una corrida fiable no es &amp;ldquo;lanzar el comando&amp;rdquo;: es un procedimiento. Los pasos, con la herramienta
de carga (GuideLLM/AIPerf) contra tu endpoint:&lt;/p>
&lt;div class="diagram" style="max-width:780px;margin:1rem auto;">
&lt;svg viewBox="0 0 780 170" role="img" aria-label="Flujo de un benchmark: desplegar el motor, calentar, barrer concurrencia, recoger métricas y comparar" xmlns="http://www.w3.org/2000/svg">
&lt;style>.bx{fill:none;stroke:currentColor;stroke-width:1.3}.tl{font:600 12px sans-serif;fill:currentColor}.ts{font:11px sans-serif;fill:currentColor}.ar{fill:none;stroke:currentColor;stroke-width:1.3;marker-end:url(#wm)}&lt;/style>
&lt;defs>&lt;marker id="wm" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">&lt;path d="M0,0 L10,5 L0,10 z" fill="currentColor"/>&lt;/marker>&lt;/defs>
&lt;rect class="bx" x="20" y="50" width="120" height="44" rx="6"/>&lt;text x="80" y="69" text-anchor="middle" class="tl">1 · Desplegar&lt;/text>&lt;text x="80" y="85" text-anchor="middle" class="ts">motor + config&lt;/text>
&lt;path class="ar" d="M140,72 L165,72"/>
&lt;rect class="bx" x="165" y="50" width="120" height="44" rx="6"/>&lt;text x="225" y="69" text-anchor="middle" class="tl">2 · Calentar&lt;/text>&lt;text x="225" y="85" text-anchor="middle" class="ts">descartar warm-up&lt;/text>
&lt;path class="ar" d="M285,72 L310,72"/>
&lt;rect class="bx" x="310" y="50" width="120" height="44" rx="6"/>&lt;text x="370" y="69" text-anchor="middle" class="tl">3 · Sweep&lt;/text>&lt;text x="370" y="85" text-anchor="middle" class="ts">pasar el codo&lt;/text>
&lt;path class="ar" d="M430,72 L455,72"/>
&lt;rect class="bx" x="455" y="50" width="120" height="44" rx="6"/>&lt;text x="515" y="69" text-anchor="middle" class="tl">4 · Recoger&lt;/text>&lt;text x="515" y="85" text-anchor="middle" class="ts">JSON con percentiles&lt;/text>
&lt;path class="ar" d="M575,72 L600,72"/>
&lt;rect class="bx" x="600" y="50" width="120" height="44" rx="6"/>&lt;text x="660" y="69" text-anchor="middle" class="tl">5 · Comparar&lt;/text>&lt;text x="660" y="85" text-anchor="middle" class="ts">goodput vs SLO&lt;/text>
&lt;text x="20" y="130" class="ts">Fijar modelo, precisión, hardware, dataset y SLO antes del paso 1; pinearlos en la salida del paso 4.&lt;/text>
&lt;/svg>
&lt;/div>
&lt;ol>
&lt;li>&lt;strong>Desplegar&lt;/strong> el motor con la config exacta a medir (modelo, precisión, flags), pineada.&lt;/li>
&lt;li>&lt;strong>Calentar&lt;/strong>: lanzar unas peticiones y descartarlas, para que el prefix cache y el
autotuning no inflen los primeros números.&lt;/li>
&lt;li>&lt;strong>Sweep&lt;/strong>: barrer concurrencias crecientes (1, 8, 16, 24, 32…) &lt;strong>más allá del codo&lt;/strong>, para
ver dónde se dispara la latencia.&lt;/li>
&lt;li>&lt;strong>Recoger&lt;/strong> la salida en JSON con percentiles (TTFT/ITL/throughput/goodput) y los metadatos.&lt;/li>
&lt;li>&lt;strong>Comparar&lt;/strong>: leer el goodput bajo el SLO, no el throughput máximo.&lt;/li>
&lt;/ol>
&lt;p>Saltarse el paso 2 (warm-up) o no pasar el codo en el 3 son los dos errores que más sesgan el
resultado.&lt;/p>
&lt;hr>
&lt;h2 id="comparar-dos-motores-el-protocolo-justo">Comparar dos motores: el protocolo justo&lt;/h2>
&lt;p>Si el objetivo es elegir entre vLLM y SGLang (o TRT-LLM), el protocolo que evita conclusiones
falsas:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Misma herramienta de carga&lt;/strong> (GuideLLM o AIPerf) contra ambos endpoints — nunca el
micro-bench de cada motor.&lt;/li>
&lt;li>&lt;strong>Mismo dataset y distribución de longitudes.&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Mismo hardware y precisión.&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Mismo SLO&lt;/strong> para calcular el goodput de ambos.&lt;/li>
&lt;li>Variar &lt;strong>solo el motor&lt;/strong>; todo lo demás, fijo.&lt;/li>
&lt;/ul>
&lt;p>Solo así la diferencia que midas es del motor y no de la herramienta, el dataset o el hardware.
Es el experimento controlado que sostiene la fila del cuadro de mando (artículo B8).&lt;/p>
&lt;hr>
&lt;h2 id="formato-de-salida-y-comparabilidad">Formato de salida y comparabilidad&lt;/h2>
&lt;p>Lo que registres junto al número es lo que lo hace comparable. Una salida útil incluye, en
JSON para versionarla:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;tool&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;guidellm&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;version&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;x.y.z&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;model&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Llama-3.1-70B&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;precision&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;FP16&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;hardware&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;8xH100 SXM NVLink&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;load&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;prompt_tokens&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1024&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;output_tokens&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">256&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;concurrency&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">16&lt;/span>&lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;results&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>&lt;span class="nt">&amp;#34;ttft_p50_ms&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">180&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;ttft_p99_ms&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">460&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;itl_p50_ms&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">22&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;throughput_tok_s&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3400&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nt">&amp;#34;goodput_tok_s&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">3330&lt;/span>&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Guardar esto por cada corrida convierte un benchmark en un dato auditable: cualquiera reproduce
la cifra con la misma herramienta, versión, modelo, hardware y carga. Es el material del
harness reproducible (artículo S4), y la diferencia entre un número defendible y una captura de
consola.&lt;/p>
&lt;hr>
&lt;h2 id="ejemplo-trabajado-leer-la-salida-de-un-sweep">Ejemplo trabajado: leer la salida de un sweep&lt;/h2>
&lt;p>Una salida ilustrativa de un sweep de GuideLLM sobre un 70B en 8×H100 (SLO: P99 de TTFT &amp;lt;
500 ms), tal como la leerías:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Concurrencia&lt;/th>
&lt;th>TTFT P99 (ms)&lt;/th>
&lt;th>ITL P50 (ms)&lt;/th>
&lt;th>Throughput (tok/s)&lt;/th>
&lt;th>Goodput (tok/s)&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>8&lt;/td>
&lt;td>240&lt;/td>
&lt;td>20&lt;/td>
&lt;td>2.100&lt;/td>
&lt;td>2.100&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>16&lt;/td>
&lt;td>460&lt;/td>
&lt;td>22&lt;/td>
&lt;td>3.400&lt;/td>
&lt;td>3.330&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>24&lt;/td>
&lt;td>980&lt;/td>
&lt;td>31&lt;/td>
&lt;td>3.900&lt;/td>
&lt;td>2.420&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>32&lt;/td>
&lt;td>1.800&lt;/td>
&lt;td>54&lt;/td>
&lt;td>4.000&lt;/td>
&lt;td>800&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Cómo se lee: el &lt;strong>codo&lt;/strong> está entre 16 y 24. A concurrencia 16, el P99 (460 ms) cumple el SLO
y el goodput (3.330 tok/s) ≈ throughput. A 24, el throughput sube poco (3.400 → 3.900) pero el
P99 ya viola el SLO y el goodput &lt;strong>cae&lt;/strong> a 2.420. A 32, el throughput es máximo (4.000) pero el
goodput se desploma a 800: el sistema &amp;ldquo;rinde mucho&amp;rdquo; sirviendo peticiones que incumplen. La
&lt;strong>capacidad defendible&lt;/strong> es la de concurrencia 16 (3.330 tok/s útiles), y ese es el número que
entra en el &lt;a href="https://blog.lo0.es/posts/capacity-planning-inferencia-llm-on-premise/">capacity planning&lt;/a> y en
el coste por token. Quien reporte &amp;ldquo;4.000 tok/s&amp;rdquo; está describiendo el punto donde el sistema ya
no cumple su SLO.&lt;/p>
&lt;hr>
&lt;h2 id="automatizar-el-harness">Automatizar el harness&lt;/h2>
&lt;p>Una corrida manual no escala a un programa de benchmarking. La automatización mínima:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Script idempotente&lt;/strong> que despliega el motor, calienta, corre el sweep y guarda el JSON con
todos los metadatos (modelo, versión, hardware, dataset, SLO).&lt;/li>
&lt;li>&lt;strong>Nombrado por fecha y config&lt;/strong>, para versionar las corridas y comparar en el tiempo.&lt;/li>
&lt;li>&lt;strong>Almacén de resultados&lt;/strong> (un repo git de JSONs, o un bucket) para que cualquiera reproduzca y
compare.&lt;/li>
&lt;/ul>
&lt;p>El objetivo es que reproducir un número sea un comando, no una tarde. Es la base del harness del
artículo S4, y lo que convierte el benchmarking de una actividad puntual en una capacidad
continua de la plataforma.&lt;/p>
&lt;hr>
&lt;h2 id="integración-en-ci-benchmarking-continuo">Integración en CI: benchmarking continuo&lt;/h2>
&lt;p>El siguiente nivel es medir &lt;strong>en cada cambio&lt;/strong>: un job de CI que, al actualizar el motor o la
config, lanza un sweep corto contra un entorno de pruebas y &lt;strong>compara con la línea base&lt;/strong>. Si
el goodput cae más de un umbral, falla el pipeline. Así una regresión de rendimiento se detecta
en el commit, no en producción. Cuidado con dos cosas: el benchmarking en CI consume GPU-horas
(presupuéstalo) y necesita un entorno estable (mismo hardware) para que la comparación sea
válida. No hace falta el sweep completo en cada commit: un sweep corto que cubra el codo basta
para detectar regresiones; el sweep exhaustivo, para los releases.&lt;/p>
&lt;hr>
&lt;h2 id="el-coste-de-medir-en-euros">El coste de medir (en euros)&lt;/h2>
&lt;p>Benchmarkear &lt;strong>consume GPU-horas&lt;/strong>, y eso tiene un coste que conviene presupuestar. Un sweep
serio sobre un nodo 8×H100 puede ocupar las tarjetas un par de horas; a coste amortizado de
~11 €/h, son ~22 € por sweep completo, más si barres varios modelos y precisiones. No es mucho
por corrida, pero un programa de benchmarking continuo (cada release, cada cambio de config)
suma. La regla práctica: automatiza el harness para que cada corrida sea barata y reproducible,
y mide lo que vas a usar para decidir, no por exhaustividad. El coste de medir es parte del
coste de la plataforma —pequeño frente al de servir, pero real—.&lt;/p>
&lt;hr>
&lt;h2 id="observar-durante-el-benchmark-una-corrida-tres-ejes">Observar durante el benchmark: una corrida, tres ejes&lt;/h2>
&lt;p>Un truco que ahorra trabajo y conecta la serie: &lt;strong>mientras corre el sweep, captura también las
métricas de GPU&lt;/strong>. Con DCGM exportando a Prometheus durante la corrida, registras a la vez:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Eje&lt;/th>
&lt;th>Fuente durante el sweep&lt;/th>
&lt;th>Métrica&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Rendimiento&lt;/td>
&lt;td>la herramienta (GuideLLM/AIPerf)&lt;/td>
&lt;td>TTFT, ITL, throughput, goodput&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Energía&lt;/td>
&lt;td>DCGM&lt;/td>
&lt;td>potencia (W) → J/token&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Coste&lt;/td>
&lt;td>precio del nodo (OpenCost)&lt;/td>
&lt;td>€/hora → CPM por punto&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Así, de &lt;strong>una sola corrida&lt;/strong> sacas los tres números del mismo punto de operación: a concurrencia
16, el goodput (3.330 tok/s), la potencia media (de DCGM, que dividida por el throughput da los
J/token) y el coste por token (con el precio del nodo). En vez de tres campañas separadas,
mides los tres ejes a la vez, y quedan &lt;strong>coherentes por construcción&lt;/strong> porque corresponden al
mismo instante y la misma carga. Es lo que hace el harness del artículo S4, y la razón de
exportar DCGM durante el benchmark aunque solo busques rendimiento: la energía y el coste salen
casi gratis si los capturas en la misma ventana.&lt;/p>
&lt;p>La advertencia metodológica: alinea las &lt;strong>ventanas temporales&lt;/strong>. La potencia de DCGM y las
métricas de la herramienta tienen que cubrir exactamente el mismo intervalo (sin warm-up ni
apagado), o el J/token no corresponde al throughput medido. Misma ventana, mismos tres números.&lt;/p>
&lt;hr>
&lt;h2 id="el-benchmark-es-también-finops-y-energía">El benchmark es también FinOps y energía&lt;/h2>
&lt;p>Una idea que conecta este artículo con el resto de la serie: &lt;strong>medir rendimiento es, de hecho,
medir coste y energía&lt;/strong>. Por la identidad del &lt;a href="https://blog.lo0.es/posts/tres-ejes-coste-rendimiento-energia-inferencia-llm/">artículo de apertura&lt;/a>,
el goodput es el denominador del coste por token y de la energía por token. Cuando un sweep
revela que la config A da 3.330 tok/s de goodput y la config B da 4.000, no estás midiendo solo
velocidad: estás midiendo que B cuesta menos euros y menos vatios por token. Por eso el JSON de
salida de un benchmark debería acompañarse del coste de hierro (de OpenCost) para calcular el
CPM real de cada punto del sweep: throughput × precio del nodo = coste por token. El
benchmarking no es un eje aislado; es la herramienta que, indirectamente, más mueve el coste y
la energía de la plataforma, y la que llena la columna de rendimiento del cuadro de mando con
números que se traducen directamente a euros.&lt;/p>
&lt;p>La consecuencia operativa: no benchmarkees el rendimiento en el vacío. Cada corrida que guardes
con su throughput y su goodput debería poder cruzarse con el coste del nodo (€/hora) y la
energía (J/token) para dar las tres caras del mismo punto de operación. Esa es la forma de que
el track de benchmarking alimente al de FinOps y al de energía, en vez de vivir aparte.&lt;/p>
&lt;hr>
&lt;h2 id="estado-del-arte-2026-y-límites">Estado del arte 2026 y límites&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Migración a multi-proceso&lt;/strong>: AIPerf (ex genai-perf) y GuideLLM consolidan la medición de
capacidad real; los micro-benchs quedan para tunear motores.&lt;/li>
&lt;li>&lt;strong>GuideLLM como estándar OSS&lt;/strong> de evaluación dirigida por SLO con informe automático.&lt;/li>
&lt;li>&lt;strong>Cuidado con comparar entre clases&lt;/strong>: un micro-bench y un generador de carga no son
comparables; fija la clase y la herramienta.&lt;/li>
&lt;li>&lt;strong>Versión y dataset importan&lt;/strong>: el mismo comando con otro dataset o versión da otro número;
pínealos.&lt;/li>
&lt;li>&lt;strong>MLPerf no dimensiona tu caso&lt;/strong>: compara fabricantes, no sustituye un sweep sobre tu carga.&lt;/li>
&lt;/ul>
&lt;p>Con el catálogo práctico cubierto, el siguiente artículo del track (B3) entra en GuideLLM y la
validación de SLO bajo carga a fondo. La herramienta es el medio; el dato reproducible, el fin.&lt;/p>
&lt;h2 id="errores-que-invalidan-un-benchmark">Errores que invalidan un benchmark&lt;/h2>
&lt;p>Para terminar, la lista de lo que convierte una corrida en basura, por frecuencia:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Error&lt;/th>
&lt;th>Efecto&lt;/th>
&lt;th>Arreglo&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Comparar clases distintas&lt;/td>
&lt;td>hasta 7× de diferencia espuria&lt;/td>
&lt;td>misma herramienta para todos&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>No descartar el warm-up&lt;/td>
&lt;td>TTFT artificialmente bajo&lt;/td>
&lt;td>calentar y descartar&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>No pasar el codo&lt;/td>
&lt;td>no conoces la capacidad segura&lt;/td>
&lt;td>extender el sweep&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Dataset irreal (longitud fija)&lt;/td>
&lt;td>throughput que no aplica&lt;/td>
&lt;td>sharegpt o trazas propias&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Reportar media, no P99&lt;/td>
&lt;td>oculta la cola&lt;/td>
&lt;td>percentiles siempre&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Tokenizer ajeno al modelo&lt;/td>
&lt;td>tok/s y coste/token sesgados&lt;/td>
&lt;td>contar con el del modelo&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>No pinear versión/config&lt;/td>
&lt;td>irreproducible&lt;/td>
&lt;td>guardar todo en el JSON&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Cualquiera de estos basta para que el número no sea defendible. Un benchmark es tan bueno como
su metodología: la herramienta importa menos que ejecutarla bien y registrarlo todo.&lt;/p>
&lt;h2 id="cierre">Cierre&lt;/h2>
&lt;p>El catálogo de herramientas de benchmark se reduce a una decisión simple —micro-bench para
tunear un motor, generador de carga para medir capacidad, MLPerf para comparar fabricantes— y a
una disciplina que pesa más que la elección: &lt;strong>el método&lt;/strong>. La misma &lt;code>guidellm benchmark&lt;/code> da un
dato de oro o uno inútil según el dataset, el warm-up, hasta dónde llegue el sweep y qué
registres en la salida. Para una propuesta de arquitectura soberana, el rendimiento solo cuenta
si viene con su comando, su versión, su carga y su goodput bajo SLO —y, cruzado con el coste en
euros y la energía por token, se convierte en la columna del cuadro de mando que decide qué
motor y qué configuración sostienen la plataforma. La herramienta la eliges en cinco minutos; la
metodología es lo que hace que el número aguante una auditoría.&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/nvidia-genai-perf-a-fondo/">GenAI-Perf a fondo&lt;/a> — ficha ampliada del perfilador de NVIDIA: métricas (TTFT/TPOT/ISL/OSL), invocación contra endpoint OpenAI-compatible y comparación con GuideLLM/LLMPerf.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/comparativa-motores-serving-pareto/">Comparativa de motores de serving (vLLM/SGLang/TRT-LLM/Dynamo)&lt;/a> — una vez medido el goodput con estas herramientas, aquí se ven qué motor gana en cada punto de la frontera de Pareto.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/sesgo-medicion-reproducibilidad-bench/">Sesgo de medición y reproducibilidad&lt;/a> — las fuentes de sesgo que invalidan resultados aunque la herramienta esté bien configurada: warmup, dataset real vs sintético, entorno compartido.&lt;/li>
&lt;/ul>
&lt;h2 id="fuentes">Fuentes&lt;/h2>
&lt;ul>
&lt;li>vLLM · CLI de benchmark (&lt;code>bench serve&lt;/code>) — &lt;a href="https://docs.vllm.ai/en/latest/cli/bench/serve/">https://docs.vllm.ai/en/latest/cli/bench/serve/&lt;/a>&lt;/li>
&lt;li>vLLM · &lt;code>bench sweep serve&lt;/code> — &lt;a href="https://docs.vllm.ai/en/latest/cli/bench/sweep/serve/">https://docs.vllm.ai/en/latest/cli/bench/sweep/serve/&lt;/a>&lt;/li>
&lt;li>Red Hat · desplegar y benchmarkear vLLM con GuideLLM en Kubernetes — &lt;a href="https://developers.redhat.com/articles/2025/12/24/how-deploy-and-benchmark-vllm-guidellm-kubernetes">https://developers.redhat.com/articles/2025/12/24/how-deploy-and-benchmark-vllm-guidellm-kubernetes&lt;/a>&lt;/li>
&lt;li>GuideLLM · GitHub (proyecto vLLM) — &lt;a href="https://github.com/vllm-project/guidellm">https://github.com/vllm-project/guidellm&lt;/a>&lt;/li>
&lt;li>NVIDIA AIPerf · guía de benchmarking — &lt;a href="https://lucaberton.com/blog/nvidia-aiperf-llm-inference-benchmarking-guide/">https://lucaberton.com/blog/nvidia-aiperf-llm-inference-benchmarking-guide/&lt;/a>&lt;/li>
&lt;li>Medium · Benchmarking LLM Serving Performance (guía) — &lt;a href="https://medium.com/@kimdoil1211/benchmarking-llm-serving-performance-a-comprehensive-guide-db94b1bfe8cf">https://medium.com/@kimdoil1211/benchmarking-llm-serving-performance-a-comprehensive-guide-db94b1bfe8cf&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Benchmarking de inferencia LLM: frameworks, métricas y estado del arte (ficha a ficha)</title><link>https://blog.lo0.es/posts/benchmarking-llm-frameworks-estado-del-arte/</link><pubDate>Sat, 13 Jun 2026 02:30:00 +0200</pubDate><guid>https://blog.lo0.es/posts/benchmarking-llm-frameworks-estado-del-arte/</guid><description>&lt;blockquote>
&lt;p>Notación: importes en &lt;strong>euros (N €)&lt;/strong>, decimales con coma. El rendimiento es poco
sensible al país, pero su coste asociado (coste/token) se expresa en € y enlaza con el
&lt;a href="https://blog.lo0.es/posts/tres-ejes-coste-rendimiento-energia-inferencia-llm/">artículo de apertura&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;h2 id="qué-cubre-esta-introducción">Qué cubre esta introducción&lt;/h2>
&lt;p>Tercer artículo de la serie de datos, &lt;em>deep dive&lt;/em> del eje de &lt;strong>rendimiento&lt;/strong>. Medir el
rendimiento de un motor de inferencia parece trivial —&amp;quot;¿cuántos tokens por segundo?&amp;quot;— y es
justo donde más se engaña la gente: dos herramientas pueden reportar resultados que difieren
en un factor de 7 para el mismo sistema. Este artículo inventaría las métricas que importan
y &lt;strong>cómo se definen&lt;/strong>, por qué la arquitectura de la herramienta sesga el dato, cómo se
halla el punto de saturación con un &lt;em>sweep&lt;/em> de concurrencia, y la ficha de cada framework.
Sin recomendaciones: la elección de motor se decide en el artículo de Pareto (B8); aquí
solo están los hechos y la metodología, porque &lt;strong>un benchmark sin metodología publicada no
es comparable&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h2 id="las-métricas-de-rendimiento">Las métricas de rendimiento&lt;/h2>
&lt;p>No hay una métrica de rendimiento, hay cinco, y mezclarlas es la primera fuente de error:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Métrica&lt;/th>
&lt;th>Definición&lt;/th>
&lt;th>Unidad&lt;/th>
&lt;th>Fase que domina&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>TTFT&lt;/strong> (Time To First Token)&lt;/td>
&lt;td>tiempo desde que se envía el prompt hasta el primer token&lt;/td>
&lt;td>ms&lt;/td>
&lt;td>prefill&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>TPOT / ITL&lt;/strong> (Time Per Output Token / Inter-Token Latency)&lt;/td>
&lt;td>tiempo medio entre tokens de salida una vez empezada la generación&lt;/td>
&lt;td>ms/token&lt;/td>
&lt;td>decode&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Request throughput&lt;/strong>&lt;/td>
&lt;td>ciclos completos petición-respuesta por segundo a la concurrencia probada&lt;/td>
&lt;td>req/s&lt;/td>
&lt;td>ambas&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Token throughput&lt;/strong>&lt;/td>
&lt;td>tokens totales (entrada + salida) por segundo entre todas las peticiones concurrentes&lt;/td>
&lt;td>tok/s&lt;/td>
&lt;td>ambas&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Goodput&lt;/strong>&lt;/td>
&lt;td>porcentaje de peticiones que &lt;strong>cumplen el SLO&lt;/strong> definido&lt;/td>
&lt;td>tok/s útiles&lt;/td>
&lt;td>ambas&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>P50 / P95 / P99&lt;/strong>&lt;/td>
&lt;td>percentiles de latencia (no la media)&lt;/td>
&lt;td>ms&lt;/td>
&lt;td>—&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Definiciones precisas, porque cada herramienta las calcula a su manera (&lt;a href="https://docs.anyscale.com/llm/serving/benchmarking/metrics">Anyscale ·
métricas de latencia y throughput&lt;/a>):
el &lt;strong>TTFT&lt;/strong> es lo que un usuario espera antes de ver el primer carácter, dominado por el
cómputo de prefill; la &lt;strong>ITL&lt;/strong> es el tiempo medio entre tokens sucesivos de salida y fija la
&amp;ldquo;velocidad de tecleo&amp;rdquo; percibida de la respuesta; el &lt;strong>request throughput&lt;/strong> son ciclos
completos por segundo; el &lt;strong>token throughput&lt;/strong> son tokens totales (entrada más salida) por
segundo entre todas las peticiones concurrentes.&lt;/p>
&lt;h3 id="la-descomposición-de-la-latencia">La descomposición de la latencia&lt;/h3>
&lt;p>La latencia total de una petición de \(N\) tokens de salida se descompone:&lt;/p>
$$\text{latencia} \approx \text{TTFT} + (N-1)\times \text{TPOT}$$
&lt;p>Por eso TTFT y TPOT se reportan &lt;strong>por separado&lt;/strong>: una misma media de latencia esconde
perfiles muy distintos. Un sistema con TTFT alto y TPOT bajo (prefill caro, decode rápido)
y otro al revés pueden tener la misma latencia media para una longitud concreta, pero se
comportan de forma opuesta al cambiar el tamaño de la respuesta. Para una experiencia de
chat interactivo manda el TTFT y el TPOT; para un batch de resúmenes largos, el token
throughput. Medir la media oculta ambas realidades.&lt;/p>
&lt;h3 id="goodput-la-métrica-honesta">Goodput: la métrica honesta&lt;/h3>
&lt;p>El &lt;strong>throughput bruto&lt;/strong> (TPS, RPS) dice cuánto trabajo hace el sistema; el &lt;strong>goodput&lt;/strong> dice
cuánto de ese trabajo &lt;strong>cumple tus estándares de calidad de servicio&lt;/strong> (SLO)
(&lt;a href="https://docs.anyscale.com/llm/serving/benchmarking/metrics">Anyscale&lt;/a>). Un motor puede
presumir de 10.000 tok/s agregados, pero si la mitad de las peticiones violan el SLO de P99
de TTFT, su goodput es 5.000. La cifra que se defiende en una propuesta es el &lt;strong>goodput&lt;/strong>,
no el throughput de catálogo: es lo único que se traduce en usuarios satisfechos y en un
coste por token honesto.&lt;/p>
&lt;hr>
&lt;h2 id="cómo-se-instrumenta-cada-métrica-y-dónde-se-cuela-el-error">Cómo se instrumenta cada métrica (y dónde se cuela el error)&lt;/h2>
&lt;p>Antes de comparar números conviene saber &lt;strong>dónde empieza y acaba cada reloj&lt;/strong>, porque dos
herramientas pueden llamar &amp;ldquo;TTFT&amp;rdquo; a cosas distintas:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>TTFT lado cliente vs lado servidor.&lt;/strong> El TTFT medido por el cliente incluye la latencia
de red y de la cola del gateway; el medido por el servidor, no. Para una comparación de
motores interesa el del servidor; para la experiencia de usuario, el del cliente. Mezclar
ambos invalida la comparación.&lt;/li>
&lt;li>&lt;strong>Requiere streaming.&lt;/strong> El TTFT y la ITL solo se pueden medir si la respuesta llega en
&lt;em>streaming&lt;/em> (token a token). Si la herramienta mide sobre respuestas completas, no hay
TTFT real: hay latencia total disfrazada.&lt;/li>
&lt;li>&lt;strong>Conteo de tokens.&lt;/strong> El throughput en tok/s depende de &lt;strong>qué tokenizer&lt;/strong> cuenta los
tokens. Si la herramienta usa un tokenizer distinto al del modelo, el número de tokens
—y por tanto el tok/s y el coste/token— está sesgado. Hay que contar con el tokenizer del
modelo servido.&lt;/li>
&lt;li>&lt;strong>Warm-up y prefix cache.&lt;/strong> Las primeras peticiones de un benchmark se benefician del
prefix cache caliente y dan TTFT artificialmente bajo; hay que descartar el warm-up o el
resultado infla la realidad.&lt;/li>
&lt;/ul>
&lt;p>Estas cuatro decisiones de instrumentación explican buena parte de las discrepancias entre
herramientas. Un número de rendimiento sin especificar dónde se mide el reloj y con qué
tokenizer no es comparable, por muy preciso que parezca.&lt;/p>
&lt;hr>
&lt;h2 id="la-arquitectura-de-la-herramienta-sesga-el-dato">La arquitectura de la herramienta sesga el dato&lt;/h2>
&lt;p>Aquí está la trampa que invalida la mitad de los benchmarks publicados. Las herramientas se
dividen en dos clases por la &lt;strong>arquitectura del cliente que genera la carga&lt;/strong>, y esa
arquitectura determina si la medida es fiable a alta concurrencia:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Micro-bench mono-proceso&lt;/strong> (vLLM bench, SGLang bench, genai-perf): un cliente Python
con asyncio en un solo proceso. Útiles para experimentos rápidos sobre un motor concreto,
pero la arquitectura mono-proceso &lt;strong>introduce un cuello de botella en el lado cliente&lt;/strong>
que &lt;strong>sesga los datos a alta concurrencia&lt;/strong> (&lt;a href="https://kchandan.medium.com/llm-inference-benchmarking-genai-perf-and-vllm-5dd06b57428e">genAI-perf y vLLM&lt;/a>):
el cliente no consigue generar carga suficiente y mides el límite del cliente, no el del
motor.&lt;/li>
&lt;li>&lt;strong>Carga multi-proceso&lt;/strong> (GuideLLM, AIPerf): reparten la generación de carga entre varios
procesos, evitando ese límite. Son la clase que ha emergido para medir a escala real.&lt;/li>
&lt;/ul>
&lt;p>La magnitud del sesgo es enorme: a 1.000 QPS, un benchmark mono-proceso llegó a procesar
&lt;strong>75.574 tokens&lt;/strong> frente a los &lt;strong>545.733 tokens&lt;/strong> de una arquitectura distribuida — una
&lt;strong>discrepancia de 7,2×&lt;/strong> en la capacidad de medición para el mismo sistema ([búsqueda]).
Quien compare dos motores con herramientas de clases distintas no está comparando los
motores: está comparando los clientes de benchmark.&lt;/p>
&lt;div class="diagram" style="max-width:780px;margin:1rem auto;">
&lt;svg viewBox="0 0 780 210" role="img" aria-label="Dos clases de herramientas de benchmark: cliente mono-proceso que se satura a alta concurrencia frente a generador de carga multi-proceso que mide el motor" xmlns="http://www.w3.org/2000/svg">
&lt;style>.bx{fill:none;stroke:currentColor;stroke-width:1.3}.dsh{fill:none;stroke:currentColor;stroke-width:1.3;stroke-dasharray:5 3}.tl{font:600 12px sans-serif;fill:currentColor}.ts{font:11px sans-serif;fill:currentColor}.ar{fill:none;stroke:currentColor;stroke-width:1.3;marker-end:url(#bm)}&lt;/style>
&lt;defs>&lt;marker id="bm" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto">&lt;path d="M0,0 L10,5 L0,10 z" fill="currentColor"/>&lt;/marker>&lt;/defs>
&lt;text x="20" y="26" class="tl">Mono-proceso (vLLM bench, SGLang bench, genai-perf)&lt;/text>
&lt;rect class="bx" x="20" y="36" width="150" height="40" rx="6"/>
&lt;text x="32" y="62" class="ts">1 cliente asyncio&lt;/text>
&lt;path class="ar" d="M170,58 L215,58"/>
&lt;rect class="dsh" x="215" y="36" width="120" height="40" rx="6"/>
&lt;text x="227" y="56" class="ts">cuello cliente&lt;/text>
&lt;text x="227" y="71" class="ts">sesga a alta conc.&lt;/text>
&lt;path class="ar" d="M335,58 L380,58"/>
&lt;rect class="bx" x="380" y="36" width="110" height="40" rx="6"/>
&lt;text x="392" y="62" class="ts">motor (vLLM…)&lt;/text>
&lt;text x="510" y="52" class="ts">mides el cliente,&lt;/text>
&lt;text x="510" y="68" class="ts">no el motor&lt;/text>
&lt;text x="20" y="118" class="tl">Multi-proceso (GuideLLM, AIPerf)&lt;/text>
&lt;rect class="bx" x="20" y="128" width="150" height="46" rx="6"/>
&lt;text x="32" y="148" class="ts">N procesos de carga&lt;/text>
&lt;text x="32" y="164" class="ts">(carga real)&lt;/text>
&lt;path class="ar" d="M170,151 L380,151"/>
&lt;rect class="bx" x="380" y="131" width="110" height="40" rx="6"/>
&lt;text x="392" y="155" class="ts">motor (vLLM…)&lt;/text>
&lt;text x="510" y="145" class="ts">mides el motor;&lt;/text>
&lt;text x="510" y="161" class="ts">7,2× más capacidad&lt;/text>
&lt;/svg>
&lt;/div>
&lt;hr>
&lt;h2 id="frameworks-ficha-a-ficha">Frameworks, ficha a ficha&lt;/h2>
&lt;h3 id="vllm-bench-y-sglang-bench--micro-bench-del-motor">vLLM bench y SGLang bench — micro-bench del motor&lt;/h3>
&lt;p>Qué miden: TTFT, TPOT y throughput del propio motor (vLLM o SGLang). Clase: micro-bench
mono-proceso. Uso: experimentos rápidos para tunear un motor concreto y ver el efecto de
sus optimizaciones (ver &lt;a href="https://blog.lo0.es/posts/decode-optimizaciones-vllm/">decode&lt;/a> y
&lt;a href="https://blog.lo0.es/posts/prefill-optimizaciones-vllm/">prefill&lt;/a>). Límite: se saturan en el cliente a
alta concurrencia; no sirven para medir la capacidad real a escala.&lt;/p>
&lt;h3 id="aiperf--el-de-nvidia-ex-genai-perf-multi-proceso">AIPerf — el de NVIDIA (ex genai-perf), multi-proceso&lt;/h3>
&lt;p>Qué mide: TTFT, ITL, throughput y latencia sobre &lt;strong>vLLM, NIM, TGI y cualquier endpoint
compatible&lt;/strong>. Clase: carga multi-proceso. Dato de estado del arte: NVIDIA &lt;strong>jubiló
genai-perf y lo sustituyó por AIPerf el 15 de abril de 2026&lt;/strong>. AIPerf, durante el &lt;em>sweep&lt;/em>,
&lt;strong>detecta la saturación de la GPU&lt;/strong> e identifica la iteración anterior, devolviéndola como
&lt;code>estimatedCapacity&lt;/code>; si no detecta saturación, &lt;code>estimatedCapacity&lt;/code> es la última iteración
probada —por eso el sweep tiene que extenderse &lt;strong>más allá del codo&lt;/strong> (&lt;a href="https://lucaberton.com/blog/nvidia-aiperf-llm-inference-benchmarking-guide/">AIPerf&lt;/a>).&lt;/p>
&lt;h3 id="guidellm--del-proyecto-vllm-orientado-a-slo">GuideLLM — del proyecto vLLM, orientado a SLO&lt;/h3>
&lt;p>Qué mide: distribuciones completas de TTFT, ITL y comportamiento de extremo a extremo, para
evaluación &lt;strong>dirigida por SLO&lt;/strong>. Clase: carga multi-proceso. Diferenciador: genera patrones
de tráfico realistas y configurables en modos &lt;strong>síncrono, concurrente y por tasa&lt;/strong>,
incluyendo &lt;strong>sweeps reproducibles&lt;/strong> para identificar rangos de operación seguros
(&lt;a href="https://developers.redhat.com/articles/2025/06/20/guidellm-evaluate-llm-deployments-real-world-inference">Red Hat · GuideLLM&lt;/a>,
&lt;a href="https://github.com/vllm-project/guidellm">GuideLLM · GitHub&lt;/a>). Es la herramienta para
responder &amp;ldquo;¿hasta dónde puedo cargar este motor sin romper el SLO?&amp;rdquo;.&lt;/p>
&lt;h3 id="llmperf--el-clásico-de-anyscaleray">LLMPerf — el clásico de Anyscale/Ray&lt;/h3>
&lt;p>Qué mide: throughput y latencia a nivel de inferencia. Uso: validación de endpoints, muy
extendido históricamente. Clase: carga. Límite: menos centrado en distribuciones y sweeps
que GuideLLM/AIPerf.&lt;/p>
&lt;h3 id="mlperf-inference--el-estándar-de-la-industria">MLPerf Inference — el estándar de la industria&lt;/h3>
&lt;p>Qué mide: rendimiento bajo &lt;strong>escenarios normalizados&lt;/strong> con reglas estrictas, para
comparabilidad entre fabricantes. Mantenedor: &lt;strong>MLCommons&lt;/strong>. Es el patrón oro de
comparabilidad cross-vendor; se desarrolla abajo en detalle.&lt;/p>
&lt;h3 id="tabla-comparativa">Tabla comparativa&lt;/h3>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Herramienta&lt;/th>
&lt;th>Clase&lt;/th>
&lt;th>Qué mide&lt;/th>
&lt;th>Mantenedor&lt;/th>
&lt;th>Cuándo usarla&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>vLLM bench&lt;/strong>&lt;/td>
&lt;td>micro mono-proceso&lt;/td>
&lt;td>TTFT, TPOT, throughput de vLLM&lt;/td>
&lt;td>vLLM (OSS)&lt;/td>
&lt;td>tunear vLLM, experimentos rápidos&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>SGLang bench&lt;/strong>&lt;/td>
&lt;td>micro mono-proceso&lt;/td>
&lt;td>métricas del motor SGLang&lt;/td>
&lt;td>SGLang (OSS)&lt;/td>
&lt;td>tunear SGLang&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>AIPerf&lt;/strong> (ex genai-perf)&lt;/td>
&lt;td>carga multi-proceso&lt;/td>
&lt;td>TTFT, ITL, throughput; estimatedCapacity&lt;/td>
&lt;td>NVIDIA (OSS)&lt;/td>
&lt;td>capacidad real, multi-endpoint&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>GuideLLM&lt;/strong>&lt;/td>
&lt;td>carga multi-proceso&lt;/td>
&lt;td>distribuciones, SLO, sweeps&lt;/td>
&lt;td>vLLM (OSS)&lt;/td>
&lt;td>validar SLO, hallar el codo&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>LLMPerf&lt;/strong>&lt;/td>
&lt;td>carga&lt;/td>
&lt;td>throughput y latencia&lt;/td>
&lt;td>Anyscale/Ray (OSS)&lt;/td>
&lt;td>validación de endpoints&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>MLPerf Inference&lt;/strong>&lt;/td>
&lt;td>suite estándar&lt;/td>
&lt;td>escenarios server/offline/interactive&lt;/td>
&lt;td>MLCommons&lt;/td>
&lt;td>comparabilidad cross-vendor&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;hr>
&lt;h2 id="el-sweep-de-concurrencia-hallar-el-codo">El sweep de concurrencia: hallar el codo&lt;/h2>
&lt;p>La medida más útil para dimensionar no es un número, es una &lt;strong>curva&lt;/strong>: cómo cambian la
latencia y el throughput a medida que sube la concurrencia. Subir la concurrencia mantiene
la GPU más ocupada y sube el RPS, pero a partir de cierto punto &lt;strong>dispara el TTFT, la ITL y
la latencia de extremo a extremo&lt;/strong> ([búsqueda]). El objetivo del &lt;em>sweep&lt;/em> es encontrar el
&lt;strong>codo&lt;/strong> (&lt;em>knee&lt;/em>): la concurrencia máxima donde el throughput sigue subiendo sin que la
latencia rompa el SLO.&lt;/p>
&lt;div class="diagram" style="max-width:780px;margin:1rem auto;">
&lt;svg viewBox="0 0 780 260" role="img" aria-label="Curva del sweep de concurrencia: el throughput sube y satura mientras la latencia se dispara más allá del codo, que marca la capacidad segura bajo SLO" xmlns="http://www.w3.org/2000/svg">
&lt;style>.ax{fill:none;stroke:currentColor;stroke-width:1}.cv{fill:none;stroke:currentColor;stroke-width:1.6}.dsh{fill:none;stroke:currentColor;stroke-width:1;stroke-dasharray:4 3}.tl{font:600 12px sans-serif;fill:currentColor}.ts{font:11px sans-serif;fill:currentColor}&lt;/style>
&lt;line class="ax" x1="60" y1="40" x2="60" y2="200"/>
&lt;line class="ax" x1="60" y1="200" x2="720" y2="200"/>
&lt;text x="20" y="120" class="ts" transform="rotate(-90 20 120)">métrica&lt;/text>
&lt;text x="360" y="228" class="ts">concurrencia →&lt;/text>
&lt;path class="cv" d="M60,190 C200,150 300,120 400,112 C520,104 620,100 700,98"/>
&lt;text x="600" y="92" class="ts">throughput (satura)&lt;/text>
&lt;path class="cv" d="M60,180 C260,176 360,170 430,150 C520,120 600,70 700,46"/>
&lt;text x="600" y="40" class="ts">latencia (se dispara)&lt;/text>
&lt;line class="dsh" x1="430" y1="40" x2="430" y2="200"/>
&lt;text x="392" y="56" class="tl">codo (knee)&lt;/text>
&lt;text x="362" y="216" class="ts">capacidad segura bajo SLO&lt;/text>
&lt;text x="60" y="250" class="ts">Antes del codo, subir concurrencia da más throughput "gratis". Después, la latencia rompe el SLO sin apenas ganar throughput.&lt;/text>
&lt;/svg>
&lt;/div>
&lt;p>Por eso AIPerf extiende el sweep &lt;strong>más allá del codo&lt;/strong>: solo viendo dónde se dispara la
latencia se puede devolver la capacidad segura (&lt;code>estimatedCapacity&lt;/code>). Esta curva es la
materia prima del &lt;a href="https://blog.lo0.es/posts/capacity-planning-inferencia-llm-on-premise/">capacity planning&lt;/a>:
del codo sale el número de réplicas y el coste por token a la carga objetivo.&lt;/p>
&lt;hr>
&lt;h3 id="ejemplo-trabajado-lectura-de-un-sweep">Ejemplo trabajado: lectura de un sweep&lt;/h3>
&lt;p>Un sweep &lt;strong>ilustrativo&lt;/strong> sobre un nodo de ejemplo (un 70B en 8×H100, SLO de P99 de TTFT &amp;lt;
500 ms), para ver cómo se lee el codo:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Concurrencia&lt;/th>
&lt;th>RPS&lt;/th>
&lt;th>TTFT P50 (ms)&lt;/th>
&lt;th>TTFT P99 (ms)&lt;/th>
&lt;th>Token tput (tok/s)&lt;/th>
&lt;th>Goodput&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>1&lt;/td>
&lt;td>2&lt;/td>
&lt;td>80&lt;/td>
&lt;td>110&lt;/td>
&lt;td>350&lt;/td>
&lt;td>100 %&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>8&lt;/td>
&lt;td>14&lt;/td>
&lt;td>110&lt;/td>
&lt;td>240&lt;/td>
&lt;td>2.100&lt;/td>
&lt;td>100 %&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>16&lt;/td>
&lt;td>22&lt;/td>
&lt;td>180&lt;/td>
&lt;td>460&lt;/td>
&lt;td>3.400&lt;/td>
&lt;td>98 %&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>24&lt;/td>
&lt;td>26&lt;/td>
&lt;td>320&lt;/td>
&lt;td>980&lt;/td>
&lt;td>3.900&lt;/td>
&lt;td>62 %&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>32&lt;/td>
&lt;td>27&lt;/td>
&lt;td>540&lt;/td>
&lt;td>1.800&lt;/td>
&lt;td>4.000&lt;/td>
&lt;td>20 %&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>Lectura: hasta concurrencia ~16 el throughput crece y el P99 se mantiene bajo el SLO
(goodput ~100 %). Entre 16 y 24 está el &lt;strong>codo&lt;/strong>: el throughput ya casi no sube (3.400 →
3.900 tok/s) pero el P99 se dispara (460 → 980 ms) y el goodput se desploma (98 % → 62 %).
A concurrencia 32 el throughput bruto es máximo (4.000 tok/s) pero &lt;strong>el goodput es 20 %&lt;/strong>:
el sistema &amp;ldquo;rinde mucho&amp;rdquo; sirviendo sobre todo peticiones que violan el SLO. La capacidad
segura defendible es la de concurrencia ~16, no la del throughput máximo. Este es el número
que entra en el &lt;a href="https://blog.lo0.es/posts/capacity-planning-inferencia-llm-on-premise/">capacity planning&lt;/a>
y en el coste por token: a 3.400 tok/s útiles, no a 4.000 tok/s brutos.&lt;/p>
&lt;hr>
&lt;h2 id="mlperf-inference-el-estándar-de-comparabilidad">MLPerf Inference: el estándar de comparabilidad&lt;/h2>
&lt;p>Para comparar &lt;strong>entre fabricantes y motores&lt;/strong> con reglas idénticas existe &lt;strong>MLPerf
Inference&lt;/strong> (MLCommons). La categoría de datacenter se centra en dos escenarios, más uno
opcional (&lt;a href="https://mlcommons.org/benchmarks/inference-datacenter/">MLCommons · datacenter&lt;/a>):&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Escenario&lt;/th>
&lt;th>Qué simula&lt;/th>
&lt;th>Métrica&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Offline&lt;/strong>&lt;/td>
&lt;td>throughput bruto procesando todo el dataset en batch&lt;/td>
&lt;td>máximo throughput&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Server&lt;/strong>&lt;/td>
&lt;td>entorno interactivo: peticiones de una en una según Poisson a un RPS medio&lt;/td>
&lt;td>RPS bajo límites de TTFT y TPOT&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Interactive&lt;/strong> (opcional)&lt;/td>
&lt;td>como server pero con &lt;strong>límites de latencia más estrictos&lt;/strong>&lt;/td>
&lt;td>RPS bajo SLO duro&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>El escenario &lt;strong>Server&lt;/strong> es el realista para inferencia online: el generador de carga manda
peticiones siguiendo una distribución de Poisson y exige cumplir &lt;strong>cotas concretas de TTFT
y TPOT&lt;/strong>. &lt;strong>MLPerf Inference v5.0&lt;/strong> (abril 2025) introdujo un benchmark de &lt;strong>405B a gran
escala&lt;/strong> y uno &lt;strong>interactivo de 70B de baja latencia&lt;/strong>, ofreciendo benchmarks de lenguaje a
todas las escalas (7B a 405B), diversidad de arquitecturas (incluido MoE) y escenarios
(&lt;a href="https://mlcommons.org/2025/04/llm-inference-v5/">MLCommons · v5.0&lt;/a>); &lt;strong>v5.1&lt;/strong> (septiembre
2025) amplió los resultados con participación récord
(&lt;a href="https://mlcommons.org/2025/09/mlperf-inference-v5-1-results/">MLCommons · v5.1&lt;/a>).&lt;/p>
&lt;p>El valor de MLPerf es la &lt;strong>comparabilidad&lt;/strong>: todos miden lo mismo bajo las mismas reglas. Su
límite es que esas reglas pueden no coincidir con tu carga (tu distribución de longitudes,
tu SLO concreto), así que sirve para comparar hardware/motores entre sí, no necesariamente
para dimensionar tu caso —para eso, el sweep propio.&lt;/p>
&lt;hr>
&lt;h2 id="el-sesgo-de-medición-y-la-reproducibilidad">El sesgo de medición y la reproducibilidad&lt;/h2>
&lt;p>Que dos benchmarks den resultados muy distintos para el mismo sistema no es un accidente:
el sesgo sistemático de medición en benchmarks de producción está &lt;strong>caracterizado en la
literatura&lt;/strong> (&lt;a href="https://arxiv.org/html/2605.24217">arXiv 2605.24217&lt;/a>), y hay trabajo
dedicado a las &lt;strong>meta-métricas y buenas prácticas&lt;/strong> del benchmarking de rendimiento a nivel
de sistema (&lt;a href="https://arxiv.org/pdf/2508.10251">arXiv 2508.10251&lt;/a>). Las fuentes de sesgo más
comunes:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Fuente de sesgo&lt;/th>
&lt;th>Efecto&lt;/th>
&lt;th>Mitigación&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Cliente mono-proceso&lt;/td>
&lt;td>infravalora el throughput a alta concurrencia&lt;/td>
&lt;td>usar carga multi-proceso&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Distribución de longitudes irreal&lt;/td>
&lt;td>resultados que no aplican a tu tráfico&lt;/td>
&lt;td>usar trazas realistas&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Medir media en vez de percentiles&lt;/td>
&lt;td>oculta la cola de latencia&lt;/td>
&lt;td>reportar P95/P99&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Warm-up no controlado&lt;/td>
&lt;td>el prefix cache infla los primeros resultados&lt;/td>
&lt;td>descartar el warm-up&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>No fijar versión de motor/modelo&lt;/td>
&lt;td>irreproducible&lt;/td>
&lt;td>pinear todo y publicarlo&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>La conclusión metodológica de este artículo: &lt;strong>un benchmark sin metodología publicada no es
comparable&lt;/strong>. Para que un número de rendimiento sostenga una propuesta tiene que venir con
la herramienta, su versión, el modelo y precisión, la distribución de carga y el SLO. El
artículo de síntesis S4 monta un harness reproducible que fija todo eso.&lt;/p>
&lt;hr>
&lt;h2 id="checklist-de-un-benchmark-reproducible">Checklist de un benchmark reproducible&lt;/h2>
&lt;p>Para que un número de rendimiento sea defendible ante un comité, tiene que venir con todo
lo que permite reproducirlo. El mínimo que se publica junto al resultado:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Qué fijar&lt;/th>
&lt;th>Por qué&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>Herramienta + versión&lt;/td>
&lt;td>cada una mide distinto; la versión cambia el comportamiento&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Modelo + precisión (FP16/FP8/INT4)&lt;/td>
&lt;td>la precisión cambia throughput y calidad&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Hardware (GPU, nº, interconexión)&lt;/td>
&lt;td>un 8×H100 NVLink no es 8×H100 PCIe&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Motor + versión + flags&lt;/td>
&lt;td>vLLM/SGLang/TRT-LLM y su configuración&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Distribución de longitudes (in/out)&lt;/td>
&lt;td>el tráfico real no es de longitud fija&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Niveles de concurrencia del sweep&lt;/td>
&lt;td>hay que pasar el codo&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>SLO (qué percentil, qué umbral)&lt;/td>
&lt;td>define el goodput&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Tratamiento del warm-up&lt;/td>
&lt;td>descartarlo o sesga el resultado&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>Tokenizer usado para contar&lt;/td>
&lt;td>afecta a tok/s y coste/token&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>La regla práctica: si no puedes entregar esta tabla junto a la cifra, la cifra no es un
dato, es una anécdota. El harness reproducible del artículo S4 automatiza el registro de
todos estos parámetros para que cualquiera —incluido quien rebata la propuesta— pueda
reproducir el número exacto.&lt;/p>
&lt;hr>
&lt;h2 id="rendimiento--calidad">Rendimiento ≠ calidad&lt;/h2>
&lt;p>Una advertencia que evita el error más caro: estas herramientas miden &lt;strong>velocidad y
throughput, no acierto&lt;/strong>. Un motor puede ser rapidísimo sirviendo un modelo que responde
mal. La &lt;strong>calidad&lt;/strong> se mide con otra familia de herramientas —&lt;strong>lm-evaluation-harness&lt;/strong>,
&lt;strong>HELM&lt;/strong>, &lt;em>leaderboards&lt;/em> de tareas— que es &lt;strong>otro eje&lt;/strong> del cuadro de mando (artículo B7).
Confundir &amp;ldquo;rápido&amp;rdquo; con &amp;ldquo;bueno&amp;rdquo; es montar una plataforma que sirve respuestas malas muy
deprisa. En la frontera de Pareto final, rendimiento y calidad son dos ejes distintos que
hay que ver juntos, nunca uno en lugar del otro.&lt;/p>
&lt;p>La otra familia de herramientas, para referencia (se desarrolla en B7):&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Herramienta&lt;/th>
&lt;th>Qué mide&lt;/th>
&lt;th>Trampa habitual&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>lm-evaluation-harness&lt;/strong>&lt;/td>
&lt;td>acierto en cientos de tareas estandarizadas&lt;/td>
&lt;td>contaminación del dataset de test&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>HELM&lt;/strong>&lt;/td>
&lt;td>evaluación holística (acierto, robustez, sesgo, eficiencia)&lt;/td>
&lt;td>pesado de ejecutar&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>LiveBench / leaderboards dinámicos&lt;/strong>&lt;/td>
&lt;td>tareas que rotan para evitar contaminación&lt;/td>
&lt;td>comparabilidad temporal&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>El punto de datos: la &lt;strong>contaminación&lt;/strong> —que el modelo haya visto el test en su
entrenamiento— infla las métricas de calidad igual que el warm-up infla las de rendimiento.
Por eso los leaderboards dinámicos rotan las preguntas. Calidad y rendimiento comparten esa
lección: el método de medida sesga el resultado tanto como el sistema medido.&lt;/p>
&lt;hr>
&lt;h2 id="el-trade-off-latencia-vs-throughput">El trade-off latencia vs throughput&lt;/h2>
&lt;p>Una propiedad que el sweep deja ver y que conviene tener presente: &lt;strong>latencia y throughput
tiran en direcciones opuestas&lt;/strong>. El batching agrupa peticiones para amortizar el coste de
mover los pesos desde la VRAM —sube el throughput— pero cada petición espera a que se forme
el lote, lo que &lt;strong>sube la latencia individual&lt;/strong>. Hay dos regímenes de operación, y el
benchmark sirve para situarse en el correcto:&lt;/p>
&lt;table>
&lt;thead>
&lt;tr>
&lt;th>Régimen&lt;/th>
&lt;th>Optimiza&lt;/th>
&lt;th>Configuración&lt;/th>
&lt;th>Caso&lt;/th>
&lt;/tr>
&lt;/thead>
&lt;tbody>
&lt;tr>
&lt;td>&lt;strong>Latencia&lt;/strong>&lt;/td>
&lt;td>TTFT/TPOT bajos&lt;/td>
&lt;td>batch pequeño, baja concurrencia&lt;/td>
&lt;td>chat interactivo, copilotos&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>&lt;strong>Throughput&lt;/strong>&lt;/td>
&lt;td>tok/s máximos&lt;/td>
&lt;td>batch grande, alta concurrencia&lt;/td>
&lt;td>batch nocturno, ingestión&lt;/td>
&lt;/tr>
&lt;/tbody>
&lt;/table>
&lt;p>No existe un único &amp;ldquo;mejor&amp;rdquo; punto: existe el mejor punto &lt;strong>para tu SLO&lt;/strong>. Un benchmark que
reporta solo el throughput máximo está describiendo el régimen de throughput e ignorando si
ese punto cumple la latencia que tu caso necesita. Por eso el &lt;strong>goodput&lt;/strong> —throughput bajo
el SLO— es la métrica que reconcilia los dos regímenes: mide cuánto throughput consigues
&lt;strong>sin&lt;/strong> salirte de la latencia aceptable. El sweep recorre la curva entre ambos regímenes; tu
SLO marca dónde, en esa curva, está tu sistema.&lt;/p>
&lt;hr>
&lt;h2 id="la-conexión-con-coste-y-energía">La conexión con coste y energía&lt;/h2>
&lt;p>El rendimiento no es un eje aislado: por la identidad del &lt;a href="https://blog.lo0.es/posts/tres-ejes-coste-rendimiento-energia-inferencia-llm/">artículo de apertura&lt;/a>,
el throughput es el denominador del coste por token y de la energía por token. Un sweep que
encuentra un codo a 4.000 tok/s en vez de 2.800 no es solo &amp;ldquo;más rápido&amp;rdquo;: baja el CPM de
~1,09 a ~0,76 €/1M tok &lt;strong>y&lt;/strong> la energía por token en la misma proporción, sobre el mismo
hierro. Por eso el benchmarking de rendimiento es la herramienta que, indirectamente, más
mueve el coste: cada mejora de goodput se traduce en euros y en vatios por token. El número
que conecta los tres ejes es el &lt;strong>goodput&lt;/strong> —el throughput que cumple el SLO—, no el
throughput de catálogo.&lt;/p>
&lt;hr>
&lt;h2 id="estado-del-arte-2026">Estado del arte 2026&lt;/h2>
&lt;ul>
&lt;li>&lt;strong>Migración genai-perf → AIPerf&lt;/strong> (15-abr-2026): NVIDIA consolida su benchmarking en una
herramienta multi-proceso con detección de saturación.&lt;/li>
&lt;li>&lt;strong>GuideLLM&lt;/strong> como estándar OSS de evaluación dirigida por SLO con sweeps reproducibles.&lt;/li>
&lt;li>&lt;strong>MLPerf Inference v5.0/v5.1&lt;/strong> amplía a 405B, interactivo de 70B y MoE, con participación
récord: la comparabilidad cross-vendor madura.&lt;/li>
&lt;li>&lt;strong>Sesgo de medición caracterizado&lt;/strong>: la comunidad reconoce que el método de medida importa
tanto como el sistema medido; crece el énfasis en reproducibilidad y meta-métricas.&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="límites-y-trampas-data-driven">Límites y trampas (data-driven)&lt;/h2>
&lt;ol>
&lt;li>&lt;strong>Comparar herramientas de clases distintas.&lt;/strong> Un micro-bench mono-proceso y una carga
multi-proceso no son comparables; la diferencia puede ser 7×. Fija la clase.&lt;/li>
&lt;li>&lt;strong>Throughput de catálogo en vez de goodput.&lt;/strong> El número honesto es el que cumple el SLO.&lt;/li>
&lt;li>&lt;strong>Medias en vez de percentiles.&lt;/strong> La media oculta la cola; reporta P95/P99.&lt;/li>
&lt;li>&lt;strong>No extender el sweep más allá del codo.&lt;/strong> Sin ver dónde se dispara la latencia no
conoces la capacidad segura.&lt;/li>
&lt;li>&lt;strong>Confundir rendimiento con calidad.&lt;/strong> Son ejes distintos; rápido no es bueno.&lt;/li>
&lt;li>&lt;strong>No pinear versiones.&lt;/strong> Motor, modelo, precisión y carga sin fijar = irreproducible = no
defendible.&lt;/li>
&lt;/ol>
&lt;p>El siguiente artículo del track (B2) entra en el catálogo de herramientas a fondo; este fija
las métricas y la metodología. Con el rendimiento medido de forma reproducible, el cuadro de
mando puede cruzarlo con el coste (en €) y la energía para la decisión final.&lt;/p>
&lt;h2 id="cierre">Cierre&lt;/h2>
&lt;p>El benchmarking de rendimiento parece el eje más &amp;ldquo;objetivo&amp;rdquo; de los tres —al fin y al cabo,
son tokens por segundo— y es justo donde más se manipula, casi siempre sin mala intención:
una herramienta mono-proceso aquí, una media en vez de un P99 allá, un throughput de
catálogo en vez del goodput. La diferencia entre un número de marketing y un dato defendible
no está en el motor medido, sino en la &lt;strong>metodología&lt;/strong>: la clase de herramienta, dónde se
mide el reloj, con qué tokenizer, hasta dónde llega el sweep y qué SLO define el goodput.
Para una propuesta de arquitectura soberana, el rendimiento solo vale si se entrega con esa
ficha de reproducibilidad —y, cruzado con el coste en euros y la energía por token, se
convierte en la columna de la frontera de Pareto que decide qué motor y qué configuración
sostienen la plataforma. El número que se defiende no es el más alto: es el &lt;strong>goodput
reproducible&lt;/strong>.&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/comparativa-motores-serving-pareto/">Comparativa de motores de serving (vLLM/SGLang/TRT-LLM/Dynamo)&lt;/a> — la elección del motor tras medir el goodput: de la metodología de esta ficha a la frontera de Pareto.&lt;/li>
&lt;li>&lt;a href="https://blog.lo0.es/posts/sesgo-medicion-reproducibilidad-bench/">Sesgo de medición y reproducibilidad&lt;/a> — fuentes de sesgo sistemático en benchmarks de rendimiento y cómo controlarlas para obtener datos defendibles.&lt;/li>
&lt;/ul>
&lt;h2 id="fuentes">Fuentes&lt;/h2>
&lt;ul>
&lt;li>Anyscale · métricas de latencia y throughput de LLM — &lt;a href="https://docs.anyscale.com/llm/serving/benchmarking/metrics">https://docs.anyscale.com/llm/serving/benchmarking/metrics&lt;/a>&lt;/li>
&lt;li>Red Hat · GuideLLM: evaluar despliegues LLM para inferencia real — &lt;a href="https://developers.redhat.com/articles/2025/06/20/guidellm-evaluate-llm-deployments-real-world-inference">https://developers.redhat.com/articles/2025/06/20/guidellm-evaluate-llm-deployments-real-world-inference&lt;/a>&lt;/li>
&lt;li>GuideLLM · GitHub (proyecto vLLM) — &lt;a href="https://github.com/vllm-project/guidellm">https://github.com/vllm-project/guidellm&lt;/a>&lt;/li>
&lt;li>NVIDIA AIPerf · guía de benchmarking (ex genai-perf) — &lt;a href="https://lucaberton.com/blog/nvidia-aiperf-llm-inference-benchmarking-guide/">https://lucaberton.com/blog/nvidia-aiperf-llm-inference-benchmarking-guide/&lt;/a>&lt;/li>
&lt;li>MLCommons · MLPerf Inference datacenter (escenarios) — &lt;a href="https://mlcommons.org/benchmarks/inference-datacenter/">https://mlcommons.org/benchmarks/inference-datacenter/&lt;/a>&lt;/li>
&lt;li>MLCommons · MLPerf Inference v5.0 (405B + 70B interactivo) — &lt;a href="https://mlcommons.org/2025/04/llm-inference-v5/">https://mlcommons.org/2025/04/llm-inference-v5/&lt;/a>&lt;/li>
&lt;li>MLCommons · MLPerf Inference v5.1 — &lt;a href="https://mlcommons.org/2025/09/mlperf-inference-v5-1-results/">https://mlcommons.org/2025/09/mlperf-inference-v5-1-results/&lt;/a>&lt;/li>
&lt;li>arXiv 2605.24217 · sesgo sistemático de medición en benchmarks de inferencia LLM — &lt;a href="https://arxiv.org/html/2605.24217">https://arxiv.org/html/2605.24217&lt;/a>&lt;/li>
&lt;li>arXiv 2508.10251 · meta-métricas y buenas prácticas de benchmarking de rendimiento — &lt;a href="https://arxiv.org/pdf/2508.10251">https://arxiv.org/pdf/2508.10251&lt;/a>&lt;/li>
&lt;li>Medium · LLM Inference Benchmarking (genAI-perf y vLLM) — &lt;a href="https://kchandan.medium.com/llm-inference-benchmarking-genai-perf-and-vllm-5dd06b57428e">https://kchandan.medium.com/llm-inference-benchmarking-genai-perf-and-vllm-5dd06b57428e&lt;/a>&lt;/li>
&lt;/ul></description></item></channel></rss>