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:

Motor de inferenciaTriton + TRT-LLM / vLLMEndpointOpenAI-compatibleGenAI-Perfprofiler (hasta abr-2026)AIPerfsucesor (abr-2026+)GenAI-Perf funciona contra cualquier endpoint compatible con la API OpenAI (vLLM, NIM, Triton, SGLang, TGI…).AIPerf es el sucesor oficial desde abril de 2026 (GitHub: ai-dynamo/aiperf).

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:

# 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étricaSímboloDefinición exacta (GenAI-Perf)Unidad
Time to First TokenTTFTTiempo desde que se envía la petición hasta que se recibe el primer token (incluye cola, prefill y red)ms
Inter-Token LatencyITL (= TPOT)(\frac{e2e_latency - TTFT}{tokens_salida - 1}) — solo fase de decode, excluye el primer tokenms/token
Request Latencye2e_latency(e2e = TTFT + Generation_time) — de la primera petición a la última respuestams
Output Token ThroughputOTT(\frac{total_output_tokens}{T_y - T_x}) donde (T_x) = primera petición, (T_y) = último token recibidotok/s
Request ThroughputRPS(\frac{total_requests_completados}{T_y - T_x})req/s
Input Sequence LengthISLLongitud media en tokens del prompt de entradatokens
Output Sequence LengthOSLLongitud media en tokens de la respuesta generadatokens

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)

# 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)

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)

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)

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

FlagValores típicosFunción
--endpoint-typechat, completions, embeddingsTipo de endpoint OpenAI-compatible
--streaming(booleano)Activa streaming SSE; necesario para medir TTFT e ITL reales
--concurrency1, 8, 16, 32, 64Número de peticiones concurrentes mantenidas; GenAI-Perf garantiza N activas en todo momento
--request-rate1.0, 5.0, 10.0Tasa de llegada constante (req/s); no garantiza N activas
--synthetic-input-tokens-mean128–8192Media de tokens ISL sintéticos
--synthetic-input-tokens-stddev0–512Desviación estándar del ISL (0 = fija)
--output-tokens-mean64–2048Media 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-count100–2000Número de peticiones a benchmarkear
--warmup-request-count10–50Peticiones 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.
--tokenizerHF model idTokenizador para contar tokens; obligatorio cuando ISL/OSL importan
--backendtensorrtllm, vllmBackend de Triton (para servicio directo vía Triton sin endpoint OpenAI)
--extra-inputsignore_eos:truePará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/:

ArtefactoFormatoContenido
profile_export_genai_perf.jsonJSONMétricas completas (avg, min, max, P75, P90, P99) + argumentos CLI usados
profile_export_genai_perf.csvCSVTablas de consola exportadas, listas para import a Excel/pandas
profile_export.jsonJSONDatos crudos de perf_analyzer (trazas por petición)
inputs.jsonJSONPayloads sintéticos enviados (para reproducibilidad)
Gráficas PNGPNGTTFT 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)

# 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

# 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)

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

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ónGenAI-PerfGuideLLMLLMPerfvLLM bench serve
Origen / mantenedorNVIDIA / Triton team (en retirada abr-2026)Red Hat / proyecto vLLMAnyscale / Rayproyecto vLLM
Clasegenerador de carga multi-procesogenerador de carga multi-procesogenerador de carga multi-procesomicro-bench mono-proceso
Endpoints soportadosOpenAI-compatible + KServe + Triton nativoOpenAI-compatibleOpenAI-compatiblevLLM nativo
Modo de carga principalconcurrencia fija N (recomendado) o request-rate constantesynchronous, concurrent, poisson, throughput, sweep automáticobatches de N concurrentes (con draining period al final)request-rate, concurrencia
Draining periodNO — garantiza N activas en todo momentoNO (poisson)SÍ — al final de cada batch el sistema se vacía, la concurrencia cae a 0N/A
Sweep automáticoanalyze (concurrencia, request-rate, ISL, OSL)--rate-type sweep (idle a saturación, 10 rondas)manual (varias corridas)vllm bench sweep serve
Métricas LLMTTFT, ITL, e2e latency, OTT, RPS, ISL/OSLTTFT, ITL/TPOT, throughput, goodput bajo SLOTTFT, ITL (incluye TTFT en el promedio), TPS (duración total del benchmark)TTFT, TPOT, throughput
Diferencia ITLexcluye TTFT: ((e2e - TTFT) / (N_{tok}-1))excluye TTFT (mismo que GenAI-Perf)incluye TTFT en el promedioexcluye 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 / SLONOSÍ (clave diferencial)NONO
ExportesJSON + CSV + PNG + checkpointJSON + YAML + CSV + HTML interactivoJSONconsola / JSON
Warmup integradoSÍ (--warmup-request-count)SÍ (peticiones de calentamiento)NO nativo
Datasets realesOpenOrca, CNN DailyMail, fichero JSONL, moon_cakefichero con distribución de tráficofichero JSONLsharegpt, random
GPU telemetríaSÍ (vía server-metrics-urls de Triton → CSV resumen)NO nativo (integrar DCGM aparte)NONO
Cuándo elegirperfilado fino de un punto de operación, comparación de configs con mismo harness, integración con NIM/Tritonsweep dirigido por SLO, hallar el codo, dimensionar réplicasvalidación rápida de endpoint en ecosistema Rayiterar 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)

ConcurrenciaTTFT P50 (ms)TTFT P99 (ms)ITL P50 (ms)ITL P99 (ms)OTT (tok/s)RPS
138456,47,11300,51
440516,88,25102,00
846627,39,49803,83
1668988,912,11.7206,72
3214528413,721,42.1308,32
4838074022,338,62.2808,90
648901.82041,278,32.3409,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 usoISL típicoOSL típico--synthetic-input-tokens-mean--output-tokens-mean
Chat interactivo corto~300 tok~100 tok300100
Copilot de código~800 tok~200 tok800200
Resumen de documentos~2000 tok~256 tok2000256
RAG con contexto largo~4096 tok~512 tok4096512
Batch sin latencia~512 tok~1024 tok5121024

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

ModoComportamientoCuándo usar
--concurrency NSiempre N peticiones activas; cuando una termina, se envía la siguienteCurva latencia-throughput limpia; comparación entre configs
--request-rate RSe envía 1 petición cada 1/R segundos; la cola puede crecer sin límiteSimular 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.

1 · Motorconfig pineada2 · Warmup≥10 peticiones3 · Sweep1:256, pasar el codo4 · ArtefactosJSON + CSV versionados5 · CompararP99 en el codoPinear: versión de genai-perf, versión del motor, modelo, precisión, ISL/OSL, hardware, tokenizador.Sin esos metadatos en el JSON, el numero no es reproducible ni comparable.

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:

EjeFuenteMétrica
RendimientoGenAI-PerfOTT (tok/s), TTFT P99, ITL P99
EnergíaDCGM vía server-metrics-urlsPotencia (W) → (J/token = W / OTT)
Costeprecio del nodoEUR/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 para la captura de potencia, y con anatomía de una request LLM 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 cubre la comparativa completa incluyendo AIPerf. El artículo GuideLLM validación SLO bajo carga 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.


Ver también

Fuentes