---
title: "GenAI-Perf a fondo: perfilado de inferencia LLM con datos reales"
url: https://blog.lo0.es/posts/nvidia-genai-perf-a-fondo/
markdown: https://blog.lo0.es/posts/nvidia-genai-perf-a-fondo/index.md
lang: es
date: 2026-06-15
lastmod: 2026-06-17
author: "José Manuel Román"
description: "Deep dive de datos sobre NVIDIA GenAI-Perf: métricas (TTFT, ITL/TPOT, throughput P99), flags de invocación contra endpoints OpenAI-compatible (vLLM, NIM, TRT-LLM), sweep de concurrencia con el subcomando analyze, artefactos JSON/CSV, tabla comparativa frente a GuideLLM/LLMPerf/vLLM bench, y metodología para no medir mal."
tags: ["benchmarking","genai-perf","nvidia","triton","vllm","ttft","serie-datos"]
translations:
  en: https://blog.lo0.es/en/posts/genai-perf-llm-inference-profiling-in-depth/index.md
---

# GenAI-Perf a fondo: perfilado de inferencia LLM con datos reales


> Notación: importes en **euros (N EUR)**, decimales con coma. No se usa el símbolo de dólar
> (en este sitio es delimitador de fórmula).

## TL;DR

GenAI-Perf (paquete `genai-perf`, parte del ecosistema Triton de NVIDIA) es el profiler de inferencia LLM de referencia para endpoints OpenAI-compatible. Instalable con `pip install genai-perf`. Un solo comando de `genai-perf profile` produce una tabla de consola con TTFT, ITL, request latency (avg/min/max/P75/P90/P99), output sequence length, output token throughput y request throughput, más artefactos `profile_export_genai_perf.json` y `.csv`. El subcomando `analyze` barre automáticamente concurrencias de 1 a 256 (potencias de 2) y genera un `analyze_export_genai_perf.csv` resumen. GenAI-Perf fue declarado **en retirada en abril de 2026** (sustituido por AIPerf); sigue siendo el benchmark de referencia para corridas históricas y comparaciones documentadas, y la herramienta con más documentación pública de NVIDIA para LLMs pre-2026.

---

## Qué es GenAI-Perf y dónde encaja

GenAI-Perf es una herramienta de línea de comandos para medir throughput y latencia de modelos generativos de IA servidos a través de un servidor de inferencia. Forma parte del repositorio `triton-inference-server/perf_analyzer` de GitHub y se distribuye como paquete pip (`genai-perf`) y dentro del contenedor SDK de Triton (`nvcr.io/nvidia/tritonserver:YY.MM-py3-sdk`).

**Posición en el ecosistema NVIDIA:**

> **Diagrama:** Ecosistema NVIDIA: Triton Inference Server y TensorRT-LLM como motores, NIM como microservicio, GenAI-Perf como profiler de endpoints, AIPerf como sucesor — [verlo en la versión HTML](https://blog.lo0.es/posts/nvidia-genai-perf-a-fondo/)

**Relación con perf_analyzer:** GenAI-Perf usa internamente el binario `perf_analyzer` de Triton para generar carga y medir latencias. perf_analyzer es el generador de carga de bajo nivel; GenAI-Perf es la capa de alto nivel que añade síntesis de prompts, construcción de payloads OpenAI y las métricas específicas de LLM (TTFT, ITL, longitudes de secuencia).

**Instalación:**

```bash
# Opción 1: pip (requiere CUDA 12, Ubuntu 24.04, Python 3.10+)
pip install genai-perf

# Opción 2: contenedor SDK de Triton (recomendado para reproducibilidad)
export RELEASE="25.01"
docker run -it --net=host --gpus=all \
  nvcr.io/nvidia/tritonserver:25.01-py3-sdk
# Dentro del contenedor:
genai-perf --help
```

---

## Métricas que produce GenAI-Perf

Las métricas cubren el ciclo completo de una petición de generación en streaming. Todas se reportan con avg, min, max, P75, P90 y P99 salvo las de throughput (solo avg).

### Glosario de métricas

| Métrica | Símbolo | Definición exacta (GenAI-Perf) | Unidad |
|---|---|---|---|
| **Time to First Token** | TTFT | Tiempo desde que se envía la petición hasta que se recibe el primer token (incluye cola, prefill y red) | ms |
| **Inter-Token Latency** | ITL (= TPOT) | \(\frac{e2e\_latency - TTFT}{tokens\_salida - 1}\) — solo fase de decode, excluye el primer token | ms/token |
| **Request Latency** | e2e_latency | \(e2e = TTFT + Generation\_time\) — de la primera petición a la última respuesta | ms |
| **Output Token Throughput** | OTT | \(\frac{total\_output\_tokens}{T_y - T_x}\) donde \(T_x\) = primera petición, \(T_y\) = último token recibido | tok/s |
| **Request Throughput** | RPS | \(\frac{total\_requests\_completados}{T_y - T_x}\) | req/s |
| **Input Sequence Length** | ISL | Longitud media en tokens del prompt de entrada | tokens |
| **Output Sequence Length** | OSL | Longitud media en tokens de la respuesta generada | tokens |

**Nota metodológica sobre ITL vs LLMPerf:** GenAI-Perf excluye el TTFT del cálculo de ITL (solo el decode puro). LLMPerf incluye el TTFT en su media de ITL. Los números no son directamente comparables.

**Nota metodológica sobre TPS vs LLMPerf:** GenAI-Perf mide el throughput entre la primera petición y el último token recibido (\(T_y - T_x\)). LLMPerf usa la duración total del benchmark incluyendo generación de prompts y almacenamiento de respuestas; en escenario de concurrencia 1, esa diferencia puede suponer hasta un 33% de diferencia en la cifra de throughput reportada.

### Tabla de salida de consola (ejemplo real, TRT-LLM backend)

La tabla que imprime GenAI-Perf para un perfil con ISL=200, OSL=100, concurrencia=1:

```
                              NVIDIA GenAI-Perf | LLM Metrics
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━┳━━━━━━━━┳━━━━━━━━┳━━━━━━━━┳━━━━━━━━┓
┃                         Statistic ┃    avg ┃    min ┃    max ┃    p99 ┃    p90 ┃    p75 ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━╇━━━━━━━━╇━━━━━━━━╇━━━━━━━━╇━━━━━━━━┩
│          Time to first token (ms) │  13.68 │  11.07 │  21.50 │  18.81 │  14.29 │  13.97 │
│          Inter token latency (ms) │   1.86 │   1.28 │   2.11 │   2.11 │   2.01 │   1.95 │
│              Request latency (ms) │ 203.70 │ 180.33 │ 228.30 │ 225.45 │ 216.48 │ 211.72 │
│            Output sequence length │ 103.46 │  95.00 │ 134.00 │ 122.96 │ 108.00 │ 104.75 │
│             Input sequence length │ 200.00 │ 200.00 │ 200.00 │ 200.00 │ 200.00 │ 200.00 │
│ Output token throughput (per sec) │ 504.02 │    N/A │    N/A │    N/A │    N/A │    N/A │
│      Request throughput (per sec) │   4.87 │    N/A │    N/A │    N/A │    N/A │    N/A │
└───────────────────────────────────┴────────┴────────┴────────┴────────┴────────┴────────┘
```

*(Fuente: docs.nvidia.com/deeplearning/triton-inference-server — tutorial LLM)*

---

## Invocación contra endpoints OpenAI-compatible

### Modo `profile`: un punto de carga

El subcomando `profile` mide un punto de operación fijo (concurrencia o request-rate, ISL/OSL sintéticos).

**Ejemplo 1: endpoint vLLM (chat, streaming)**

```bash
# 1. Levantar el servidor vLLM
docker run -it --net=host --rm --gpus=all \
  vllm/vllm-openai:latest \
  --model meta-llama/Llama-3.1-70B-Instruct \
  --dtype float16

# 2. Perfilar con GenAI-Perf
genai-perf profile \
  -m meta-llama/Llama-3.1-70B-Instruct \
  --endpoint-type chat \
  --streaming \
  --concurrency 16 \
  --synthetic-input-tokens-mean 1024 \
  --synthetic-input-tokens-stddev 128 \
  --output-tokens-mean 256 \
  --output-tokens-stddev 0 \
  --output-tokens-mean-deterministic \
  --request-count 200 \
  --warmup-request-count 20 \
  --tokenizer meta-llama/Llama-3.1-70B-Instruct
```

**Ejemplo 2: endpoint completions (sin streaming)**

```bash
genai-perf profile \
  -m meta-llama/Llama-3.1-70B-Instruct \
  --endpoint-type completions \
  --concurrency 32 \
  --synthetic-input-tokens-mean 512 \
  --synthetic-input-tokens-stddev 64 \
  --output-tokens-mean 128 \
  --request-count 200 \
  --warmup-request-count 20
```

**Ejemplo 3: NVIDIA NIM (endpoint TRT-LLM backend, via Triton)**

```bash
genai-perf profile \
  -m meta/llama-3.1-70b-instruct \
  --backend tensorrtllm \
  --streaming \
  --concurrency 8 \
  --synthetic-input-tokens-mean 2048 \
  --synthetic-input-tokens-stddev 0 \
  --output-tokens-mean 512 \
  --output-tokens-mean-deterministic \
  --request-count 100 \
  --warmup-request-count 10 \
  --generate-plots
```

**Ejemplo 4: request-rate en lugar de concurrencia (Poisson)**

```bash
genai-perf profile \
  -m meta-llama/Llama-3.1-70B-Instruct \
  --endpoint-type chat \
  --streaming \
  --request-rate 5.0 \
  --synthetic-input-tokens-mean 1024 \
  --output-tokens-mean 256 \
  --request-count 300 \
  --warmup-request-count 30
```

### Flags principales y su función

| Flag | Valores típicos | Función |
|---|---|---|
| `--endpoint-type` | `chat`, `completions`, `embeddings` | Tipo de endpoint OpenAI-compatible |
| `--streaming` | (booleano) | Activa streaming SSE; necesario para medir TTFT e ITL reales |
| `--concurrency` | 1, 8, 16, 32, 64 | Número de peticiones concurrentes mantenidas; GenAI-Perf garantiza N activas en todo momento |
| `--request-rate` | 1.0, 5.0, 10.0 | Tasa de llegada constante (req/s); no garantiza N activas |
| `--synthetic-input-tokens-mean` | 128–8192 | Media de tokens ISL sintéticos |
| `--synthetic-input-tokens-stddev` | 0–512 | Desviación estándar del ISL (0 = fija) |
| `--output-tokens-mean` | 64–2048 | Media de tokens OSL objetivo |
| `--output-tokens-mean-deterministic` | (booleano) | Fija el mínimo de output tokens = media objetivo (más preciso con TRT-LLM) |
| `--request-count` | 100–2000 | Número de peticiones a benchmarkear |
| `--warmup-request-count` | 10–50 | Peticiones de calentamiento descartadas de las métricas |
| `--generate-plots` | (booleano) | Genera gráficas PNG de TTFT vs ISL, ITL vs posición de token, etc. |
| `--tokenizer` | HF model id | Tokenizador para contar tokens; obligatorio cuando ISL/OSL importan |
| `--backend` | `tensorrtllm`, `vllm` | Backend de Triton (para servicio directo vía Triton sin endpoint OpenAI) |
| `--extra-inputs` | `ignore_eos:true` | Parámetros extra de la petición; `ignore_eos:true` garantiza OSL consistente |

**Nota sobre `--concurrency` vs `--request-rate`:** NVIDIA recomienda usar `--concurrency`. Con `--request-rate`, si la tasa supera el throughput del motor, la cola crece sin límite y las métricas dejan de ser estables. Con `--concurrency`, siempre hay exactamente N peticiones activas, lo que da una curva latencia-throughput limpia.

### Artefactos de salida

GenAI-Perf vuelca todos los resultados en un directorio `artifacts/`:

| Artefacto | Formato | Contenido |
|---|---|---|
| `profile_export_genai_perf.json` | JSON | Métricas completas (avg, min, max, P75, P90, P99) + argumentos CLI usados |
| `profile_export_genai_perf.csv` | CSV | Tablas de consola exportadas, listas para import a Excel/pandas |
| `profile_export.json` | JSON | Datos crudos de perf_analyzer (trazas por petición) |
| `inputs.json` | JSON | Payloads sintéticos enviados (para reproducibilidad) |
| Gráficas PNG | PNG | TTFT analysis, Request latency, TTFT vs ISL, ITL vs posición, ISL vs OSL (con `--generate-plots`) |

---

## Subcomando `analyze`: sweep automático de concurrencia

El subcomando `analyze` barre múltiples valores de un parámetro en un solo comando y genera un CSV resumen.

### Sweep de concurrencia (el más usado)

```bash
# Barre concurrencias 1, 2, 4, 8, 16, 32, 64, 128, 256
genai-perf analyze \
  -m meta-llama/Llama-3.1-70B-Instruct \
  --endpoint-type chat \
  --streaming \
  --sweep-type concurrency \
  --sweep-range 1:256 \
  --synthetic-input-tokens-mean 1024 \
  --output-tokens-mean 256 \
  --request-count 200 \
  --warmup-request-count 20
```

### Sweep de request-rate

```bash
# Barre 2, 4, 6, 8, 10, 12 req/s
genai-perf analyze \
  -m meta-llama/Llama-3.1-70B-Instruct \
  --endpoint-type chat \
  --streaming \
  --sweep-type request_rate \
  --sweep-list 2,4,6,8,10,12 \
  --synthetic-input-tokens-mean 1024 \
  --output-tokens-mean 256 \
  --request-count 200 \
  --warmup-request-count 20
```

### Sweep de ISL (para estudiar el efecto del prefill)

```bash
genai-perf analyze \
  -m meta-llama/Llama-3.1-70B-Instruct \
  --endpoint-type chat \
  --streaming \
  --sweep-type input_sequence_length \
  --sweep-list 256,512,1024,2048,4096 \
  --concurrency 16 \
  --output-tokens-mean 256 \
  --request-count 200 \
  --warmup-request-count 20
```

### Estructura de artefactos del `analyze`

Para un sweep `--sweep-type concurrency --sweep-range 1:32`:

```
artifacts/
  llama70b-openai-chat-concurrency1/
    inputs.json
    profile_export.json
    profile_export_genai_perf.json
    profile_export_genai_perf.csv
  llama70b-openai-chat-concurrency2/
    ...
  llama70b-openai-chat-concurrency4/
    ...
  [...]
analyze_export_genai_perf.csv    ← resumen de todos los escenarios
checkpoint.json                  ← permite reanudar sweeps interrumpidos
```

### Formato del CSV resumen

```csv
Config Name,Concurrency,ISL,p99 TTFT (ms),p99 ITL (ms),p99 Request Latency (ms),Avg. OTT (tok/s),RPS
llama70b_run_0,1,1024,45.2,6.8,1823.4,128.3,0.55
llama70b_run_1,4,1024,48.1,7.1,1901.2,510.7,2.18
llama70b_run_2,8,1024,61.3,7.9,2142.5,989.2,4.12
llama70b_run_3,16,1024,98.7,9.4,2891.3,1741.6,6.88
llama70b_run_4,32,1024,284.1,14.2,4320.8,2134.2,7.14
llama70b_run_5,64,1024,892.4,28.7,8741.2,2251.8,7.23
```

El CSV resumen incluye también una segunda tabla con métricas de GPU (potencia P99, energía, utilización, memoria) cuando se capturan vía las URLs de telemetría de Triton (`--server-metrics-urls http://localhost:8002/metrics`).

---

## Tabla comparativa: GenAI-Perf vs GuideLLM vs LLMPerf vs vLLM bench

La elección de herramienta cambia el número. No son comparables entre sí sin ajuste.

| Dimensión | **GenAI-Perf** | **GuideLLM** | **LLMPerf** | **vLLM bench serve** |
|---|---|---|---|---|
| **Origen / mantenedor** | NVIDIA / Triton team (en retirada abr-2026) | Red Hat / proyecto vLLM | Anyscale / Ray | proyecto vLLM |
| **Clase** | generador de carga multi-proceso | generador de carga multi-proceso | generador de carga multi-proceso | micro-bench mono-proceso |
| **Endpoints soportados** | OpenAI-compatible + KServe + Triton nativo | OpenAI-compatible | OpenAI-compatible | vLLM nativo |
| **Modo de carga principal** | concurrencia fija N (recomendado) o request-rate constante | synchronous, concurrent, poisson, throughput, **sweep automático** | batches de N concurrentes (con draining period al final) | request-rate, concurrencia |
| **Draining period** | NO — garantiza N activas en todo momento | NO (poisson) | SÍ — al final de cada batch el sistema se vacía, la concurrencia cae a 0 | N/A |
| **Sweep automático** | `analyze` (concurrencia, request-rate, ISL, OSL) | `--rate-type sweep` (idle a saturación, 10 rondas) | manual (varias corridas) | `vllm bench sweep serve` |
| **Métricas LLM** | TTFT, ITL, e2e latency, OTT, RPS, ISL/OSL | TTFT, ITL/TPOT, throughput, goodput bajo SLO | TTFT, ITL (incluye TTFT en el promedio), TPS (duración total del benchmark) | TTFT, TPOT, throughput |
| **Diferencia ITL** | excluye TTFT: \((e2e - TTFT) / (N_{tok}-1)\) | excluye TTFT (mismo que GenAI-Perf) | incluye TTFT en el promedio | excluye TTFT |
| **Diferencia TPS** | \(total\_tokens / (T_y - T_x)\) | throughput + goodput bajo SLO | \(total\_tokens / (T_{end} - T_{start})\) — hasta 33% menor | \(total\_tokens / (T_y - T_x)\) |
| **Goodput / SLO** | NO | SÍ (clave diferencial) | NO | NO |
| **Exportes** | JSON + CSV + PNG + checkpoint | JSON + YAML + CSV + HTML interactivo | JSON | consola / JSON |
| **Warmup integrado** | SÍ (`--warmup-request-count`) | SÍ (peticiones de calentamiento) | NO nativo | SÍ |
| **Datasets reales** | OpenOrca, CNN DailyMail, fichero JSONL, moon_cake | fichero con distribución de tráfico | fichero JSONL | sharegpt, random |
| **GPU telemetría** | SÍ (vía server-metrics-urls de Triton → CSV resumen) | NO nativo (integrar DCGM aparte) | NO | NO |
| **Cuándo elegir** | perfilado fino de un punto de operación, comparación de configs con mismo harness, integración con NIM/Triton | sweep dirigido por SLO, hallar el codo, dimensionar réplicas | validación rápida de endpoint en ecosistema Ray | iterar sobre flags de vLLM |

**Regla de comparación justa:** nunca cruzar números de herramientas distintas para la misma conclusión. Si se comparan vLLM vs TRT-LLM, usar GenAI-Perf contra ambos, con la misma ISL/OSL, la misma concurrencia y el mismo `--warmup-request-count`. La herramienta es la constante; el motor es la variable.

---

## Perfilado sobre 4×H100 SXM 80 GB: ejemplo de sweep completo

Hardware de referencia genérico: 4×H100 SXM 80 GB NVLink, modelo Llama-3.1-70B-Instruct FP16, ISL=1024 tokens, OSL=256 tokens, endpoint vLLM.

### Resultado ilustrativo de un sweep de concurrencia (1→64)

| Concurrencia | TTFT P50 (ms) | TTFT P99 (ms) | ITL P50 (ms) | ITL P99 (ms) | OTT (tok/s) | RPS |
|---|---|---|---|---|---|---|
| 1 | 38 | 45 | 6,4 | 7,1 | 130 | 0,51 |
| 4 | 40 | 51 | 6,8 | 8,2 | 510 | 2,00 |
| 8 | 46 | 62 | 7,3 | 9,4 | 980 | 3,83 |
| 16 | 68 | 98 | 8,9 | 12,1 | 1.720 | 6,72 |
| 32 | 145 | 284 | 13,7 | 21,4 | 2.130 | 8,32 |
| 48 | 380 | 740 | 22,3 | 38,6 | 2.280 | 8,90 |
| 64 | 890 | 1.820 | 41,2 | 78,3 | 2.340 | 9,14 |

Cómo se lee: el throughput satura alrededor de concurrencia 48–64, mientras el TTFT P99 ya supera los 500 ms a partir de concurrencia 32. El **codo** (último punto con TTFT P99 < 500 ms) está en concurrencia 16 con 1.720 tok/s útiles. Quien reporte "2.340 tok/s" (concurrencia 64) describe el throughput máximo, donde el sistema no cumple ningún SLO de chat interactivo.

### Fórmulas de las métricas clave

$$
\text{ITL} = \frac{e2e\_latency - TTFT}{N_{tokens\_salida} - 1}
$$

$$
\text{OTT} = \frac{\sum tokens\_salida}{T_y - T_x}
$$

$$
\text{RPS} = \frac{N_{requests}}{T_y - T_x}
$$

donde \(T_x\) es el timestamp de la primera petición enviada y \(T_y\) el timestamp del último token recibido de la última petición.

---

## Perfilado de ISL/OSL sintéticos: qué configurar para cada caso de uso

Los parámetros ISL/OSL determinan qué motor del sistema se estresa: ISL largo estresa el prefill (KV-cache, TTFT); OSL largo estresa el decode (ITL, ancho de banda de memoria).

| Caso de uso | ISL típico | OSL típico | `--synthetic-input-tokens-mean` | `--output-tokens-mean` |
|---|---|---|---|---|
| Chat interactivo corto | ~300 tok | ~100 tok | 300 | 100 |
| Copilot de código | ~800 tok | ~200 tok | 800 | 200 |
| Resumen de documentos | ~2000 tok | ~256 tok | 2000 | 256 |
| RAG con contexto largo | ~4096 tok | ~512 tok | 4096 | 512 |
| Batch sin latencia | ~512 tok | ~1024 tok | 512 | 1024 |

Con la opción `--extra-inputs ignore_eos:true` se desactiva el token EOS del motor, forzando que se generen exactamente los tokens pedidos. Imprescindible para medir OSL consistente en TRT-LLM; opcional en vLLM.

---

## Metodología honesta: cómo no medir mal

### 1. Warmup obligatorio

Sin warmup, las primeras peticiones incluyen la latencia de carga del KV-cache, el autotuning del motor y las inicializaciones. GenAI-Perf aplica una ventana deslizante para detectar estabilidad (ratio max/min dentro de un margen en las últimas 3 mediciones), pero el `--warmup-request-count` explícito descarta las primeras N peticiones de las métricas. Valor mínimo recomendado: 10 peticiones (o 5% del total si el total es grande).

### 2. El codo de concurrencia: extender el sweep hasta verlo

El throughput satura al llegar a la max batch size efectiva del motor. Si el sweep se detiene antes de alcanzar la saturación, la "capacidad máxima" reportada es la última concurrencia probada, no el codo real. La regla: el sweep debe llegar a un punto donde el TTFT P99 haya doblado respecto al valor de baja carga (o donde OTT deje de crecer más de un 5% entre pasos). Solo así el codo es visible.

Para un sweep `--sweep-range 1:256`, GenAI-Perf barre 1, 2, 4, 8, 16, 32, 64, 128, 256 (potencias de 2). En la mayoría de modelos 70B sobre 4×H100, la saturación ocurre entre concurrencia 32 y 64; el rango 1:128 cubre el codo con margen.

### 3. Concurrencia vs request-rate: elegir bien

| Modo | Comportamiento | Cuándo usar |
|---|---|---|
| `--concurrency N` | Siempre N peticiones activas; cuando una termina, se envía la siguiente | Curva latencia-throughput limpia; comparación entre configs |
| `--request-rate R` | Se envía 1 petición cada 1/R segundos; la cola puede crecer sin límite | Simular tráfico con llegadas a ritmo constante |

NVIDIA recomienda `--concurrency` para benchmarking. Con `--request-rate`, si R > throughput máximo del motor, la cola crece indefinidamente y las métricas se vuelven inestables.

### 4. Sesgo mono-proceso vs multi-proceso

GenAI-Perf es multi-proceso: mantiene N peticiones concurrentes usando el gestor interno de perf_analyzer. No hay riesgo de saturación del cliente. Esto lo diferencia de `vllm bench serve` (mono-proceso), que puede saturarse en el cliente a alta concurrencia y dar métricas de throughput infladas.

### 5. `ignore_eos` y OSL inconsistente

Sin `--extra-inputs ignore_eos:true`, el motor puede generar menos tokens de los pedidos (si el modelo produce un EOS antes). Esto hace que el OSL real varíe entre peticiones y el ITL se vuelva inconsistente entre corridas. Para benchmarks reproducibles con OSL controlado: activar `ignore_eos:true` siempre.

### 6. Tokenizador correcto

El flag `--tokenizer` debe apuntar al modelo que se sirve. Si se omite, GenAI-Perf usa un tokenizador por defecto que puede dar ISL/OSL distintos en tokens del modelo real, haciendo que los números de throughput en tok/s no sean comparables entre modelos con vocabularios diferentes.

### 7. Una corrida = un dato; tres o más = un número

La varianza entre corridas en condiciones idénticas puede ser del 5–10% en métricas de latencia de cola (P99). Un único perfil no es un número defendible; la media de tres corridas con la misma config lo es.

> **Diagrama:** Flujo de un benchmark reproducible con GenAI-Perf: desplegar motor, calentar, sweep de concurrencia mas alla del codo, recoger JSON, comparar — [verlo en la versión HTML](https://blog.lo0.es/posts/nvidia-genai-perf-a-fondo/)

---

## Conexión con el track de coste y energía

GenAI-Perf puede capturar métricas de GPU en el mismo CSV resumen si se pasa `--server-metrics-urls http://localhost:8002/metrics` (endpoint de métricas de Triton, que expone potencia y utilización vía DCGM). El CSV resumen de `analyze` incluye entonces una segunda tabla con P99 de potencia (W), energía (MJ), utilización (%) y memoria (GB) por GPU y por escenario.

Con esos datos, de un único sweep se obtienen los tres ejes del cuadro de mando:

| Eje | Fuente | Métrica |
|---|---|---|
| Rendimiento | GenAI-Perf | OTT (tok/s), TTFT P99, ITL P99 |
| Energía | DCGM vía server-metrics-urls | Potencia (W) → \(J/token = W / OTT\) |
| Coste | precio del nodo | EUR/hora → \(EUR/token = EUR_{hora} / (OTT \times 3600)\) |

La fórmula de coste por millón de tokens:

$$
CPM = \frac{EUR_{hora}}{OTT \times 3{,}6 \times 10^3}
$$

donde \(OTT\) es el output token throughput en tok/s y \(CPM\) es el coste por millón de tokens en EUR.

Conecta con [observabilidad GPU con DCGM](https://blog.lo0.es/posts/observabilidad-gpu-dcgm-llm/index.md) para la captura de potencia, y con [anatomía de una request LLM](https://blog.lo0.es/posts/anatomia-request-llm-mayo-2026/index.md) para el desglose de fases (prefill vs decode) que el TTFT y el ITL cuantifican.

---

## Estado 2026: GenAI-Perf → AIPerf

NVIDIA anunció en abril de 2026 que GenAI-Perf pasa a modo de mantenimiento pasivo (sin nuevas funcionalidades) y que el sucesor activo es **AIPerf** (`github.com/ai-dynamo/aiperf`). AIPerf añade detección automática del punto de saturación (`estimatedCapacity`) y está integrado en el pipeline de NVIDIA Dynamo.

Para benchmarks nuevos en producción: migrar a AIPerf. Para reproducir corridas históricas documentadas con GenAI-Perf o para usar los artefactos de NIM benchmarking de NVIDIA (que usan GenAI-Perf): seguir con GenAI-Perf 25.x.

El artículo [herramientas benchmark LLM ficha a ficha](https://blog.lo0.es/posts/herramientas-benchmark-llm-ficha-a-ficha/index.md) cubre la comparativa completa incluyendo AIPerf. El artículo [GuideLLM validación SLO bajo carga](https://blog.lo0.es/posts/guidellm-validacion-slo-bajo-carga/index.md) detalla el sweep dirigido por SLO que GenAI-Perf no hace nativamente. Para el contexto de metodología general: [benchmarking LLM frameworks estado del arte](https://blog.lo0.es/posts/benchmarking-llm-frameworks-estado-del-arte/index.md).

---

## Ver también

- [Sesgo de medición y reproducibilidad](https://blog.lo0.es/posts/sesgo-medicion-reproducibilidad-bench/index.md) — las trampas de configuración que invalidan un sweep de GenAI-Perf aunque los comandos sean correctos: warmup insuficiente, dataset sintético vs real, entorno compartido.
- [Comparativa de motores de serving (vLLM/SGLang/TRT-LLM/Dynamo)](https://blog.lo0.es/posts/comparativa-motores-serving-pareto/index.md) — dónde aterrizan los números medidos con GenAI-Perf: la frontera de Pareto goodput-latencia entre los cuatro motores principales.

## Fuentes

- NVIDIA · GenAI-Perf — README oficial — https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/perf_analyzer/genai-perf/README.html
- NVIDIA · Tutorial LLM con GenAI-Perf (comandos y tablas de salida reales) — https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/perf_analyzer/genai-perf/docs/tutorial.html
- NVIDIA · GenAI-Perf Analyze subcommand (sweep, CSV resumen, checkpoint) — https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/perf_analyzer/genai-perf/docs/analyze.html
- NVIDIA · NIM LLM Benchmarking — Métricas (definiciones TTFT, ITL, TPS, RPS, fórmulas exactas) — https://docs.nvidia.com/nim/benchmarking/llm/latest/metrics.html
- NVIDIA · NIM LLM Benchmarking — Parámetros y buenas prácticas (ISL/OSL, concurrencia vs request-rate, ignore_eos) — https://docs.nvidia.com/nim/benchmarking/llm/latest/parameters.html
- NVIDIA Technical Blog · Measuring Generative AI Model Performance Using NVIDIA GenAI-Perf and an OpenAI-Compatible API — https://developer.nvidia.com/blog/measuring-generative-ai-model-performance-using-nvidia-genai-perf-and-an-openai-compatible-api/
- GitHub · triton-inference-server/perf_analyzer (genai-perf) — https://github.com/triton-inference-server/perf_analyzer/blob/main/genai-perf/README.md
- GitHub · ray-project/llmperf (métricas y diferencias metodológicas) — https://github.com/ray-project/llmperf
- PyPI · nvidia-genai-perf-eval — https://pypi.org/project/nvidia-genai-perf-eval/
- Macnica · Benchmarking LLM Applications Part 1: What is GenAI-Perf? — https://www.macnica.co.jp/en/business/semiconductor/articles/nvidia/145977/

