Skip to content

Benchmarks de rendimiento

Benchmarks de rendimiento del mundo real comparando TCPDF-Next contra tres bibliotecas de PDF PHP establecidas: TCPDF, DomPDF y mPDF. Todas las pruebas se ejecutaron en hardware idéntico bajo condiciones Docker controladas. Los resultados son medianas de 20 iteraciones para eliminar ruido de valores atípicos.

Entorno de pruebas

ParámetroValor
CPUIntel Core i9-13900K (x86-64)
RAM64 GB DDR5 (Docker limitado a 16 GB)
Docker4 CPUs, 16 GB RAM, Debian bookworm
PHP8.5.3 (CLI, OPcache habilitado, JIT habilitado)
TCPDF-Next1.7.0
TCPDF6.10.1
DomPDFv3.1.4
mPDFv8.2.7
Artisan (Chrome)Headless Chromium via CDP
RoadRunnerspiral/roadrunner-http ^3.6 (pruebas de throughput HTTP)
Warmup3 iteraciones (descartadas)
Medidas20 iteraciones (mediana reportada)
Temporizaciónhrtime(true) reloj de pared con precisión de nanosegundos

Comparación interactiva

▼ Lower is better
TCPDF-Next
0.68 ms
TCPDF
2.55 ms3.7x
DomPDF
4.16 ms6.1x
mPDF
6.71 ms9.9x

PHP 8.5.3 + OPcache + JIT · Docker 4 CPUs / 16 GB · i9-13900K · Median of 20 runs

Velocidad de generación

Cada escenario se ejecutó 20 veces después de 3 iteraciones de warmup. Se reporta el tiempo de generación mediano.

Documento simple (1 página)

Una sola página A4 con un encabezado y texto formateado básico usando fuente Helvetica integrada. Sin imágenes, sin tablas.

BibliotecaTiempo (ms)
TCPDF-Next0.68
TCPDF2.55
DomPDF4.16
mPDF6.71

TCPDF-Next completa el escenario más simple en menos de 1 ms — 3.8x más rápido que TCPDF, 6.1x más rápido que DomPDF y 9.9x más rápido que mPDF.

Factura (2 páginas)

Una factura de dos páginas con 25 filas de líneas de detalle tabulares, subtotales, headers, footers y una imagen de logo.

BibliotecaTiempo (ms)
TCPDF1.96
TCPDF-Next2.01
mPDF15.86
DomPDF17.33

TCPDF-Next y TCPDF están virtualmente empatados en el escenario de factura (~1.0x). Ambos superan significativamente a mPDF (7.9x más lento) y DomPDF (8.6x más lento).

Reporte de 100 páginas

Un documento de 100 páginas con contenido mixto denso: encabezados, párrafos y datos estructurados.

BibliotecaTiempo (ms)
TCPDF-Next34.29
TCPDF105.39
mPDF1,106.59*
DomPDF2,129.12

TCPDF-Next completa un reporte de 100 páginas en 34.29 ms — 3.1x más rápido que TCPDF, 32.3x más rápido que mPDF y 62.1x más rápido que DomPDF.

Nota de compatibilidad JIT

*El resultado del reporte de 100 páginas de mPDF fue medido con JIT deshabilitado (opcache.jit=0) debido a un segfault PHP JIT (SIGSEGV, código de salida 139) en la ruta de código de mPDF. El caché de bytecode OPcache permaneció activo. Esta es una clase conocida de bugs JIT de PHP que afectan ciertos patrones de bucle complejos. Todos los demás escenarios de mPDF se ejecutaron con JIT habilitado.

Documento TrueType (1 página)

Una sola página A4 usando DejaVu Sans (~700 KB fuente TrueType). Este escenario expone los costos reales de parseo de archivos de fuente — a diferencia de Helvetica (fuente integrada Base14 que requiere cero I/O de archivo).

BibliotecaTiempo (ms)
TCPDF-Next4.08
TCPDF12.11
mPDF16.51
DomPDF24.14

TCPDF-Next parsea e incrusta la fuente TrueType 3.0x más rápido que TCPDF, 4.0x más rápido que mPDF y 5.9x más rápido que DomPDF.

Velocidad relativa (todos los escenarios)

Todos los valores relativos a TCPDF-Next (línea base 1.0x). Menor = más rápido.

EscenarioTCPDF-NextTCPDFDomPDFmPDF
Documento simple1.0x3.8x6.1x9.9x
Factura1.0x~1.0x8.6x7.9x
Reporte de 100 páginas1.0x3.1x62.1x32.3x
Documento TrueType1.0x3.0x5.9x4.0x

HTML a PDF

Enfoques de procesamiento HTML

Diferentes bibliotecas toman enfoques fundamentalmente diferentes para convertir HTML a PDF. Entender estas diferencias es esencial para interpretar los resultados de benchmarks:

Traducción directa (TCPDF-Next, TCPDF) — El parser HTML integrado tokeniza los tags HTML y los mapea directamente a comandos de dibujo PDF (Cell, MultiCell, Image) en un solo pase de streaming. Este enfoque es extremadamente rápido pero solo soporta tags HTML básicos y CSS inline — sin Flexbox, sin Grid, sin selectores CSS complejos.

Motor de layout CSS (DomPDF, mPDF) — Estas bibliotecas están diseñadas con HTML como su interfaz principal. DomPDF construye un árbol DOM completo, aplica la cascada CSS (especificidad, herencia) y calcula el layout de modelo de caja antes de renderizar a PDF. El WriteHTML() de mPDF procesa HTML de manera similar a través de su propio motor de layout CSS. Ambos soportan más funcionalidades CSS que los parsers de traducción directa (floats, elementos posicionados, tablas estilizadas) pero aún no alcanzan el CSS3 completo a nivel de navegador.

Renderizado de navegador completo (Artisan / Chrome) — TCPDF-Next Artisan delega el renderizado a Chromium headless via Chrome DevTools Protocol (CDP). Esto proporciona soporte CSS3 pixel-perfect: Flexbox, Grid, Web Fonts, media queries, variables CSS — salida idéntica a lo que un navegador Chrome produciría.

El benchmark compara el enfoque nativo de cada biblioteca: TCPDF-Next y TCPDF usan su parser de traducción directa integrado; DomPDF y mPDF usan sus motores de renderizado CSS (su API principal); Artisan usa Chrome.

Resultados

BibliotecaEnfoqueTiempo (ms)
TCPDF-NextTraducción directa1.51
TCPDFTraducción directa6.60
DomPDFMotor de layout CSS13.69
mPDFMotor de layout CSS29.63
Artisan (Chrome)Renderizado de navegador completo66.70

Tiempo relativo (HTML a PDF)

BibliotecaRelativo
TCPDF-Next1.0x
TCPDF4.4x
DomPDF9.0x
mPDF19.6x
Artisan (Chrome)44.1x

El parser de traducción directa de TCPDF-Next entrega rendimiento sub-2 ms — 4.4x más rápido que el parser basado en regex de TCPDF, 9.0x más rápido que el motor de layout CSS de DomPDF y 19.6x más rápido que mPDF. Artisan (Chrome) es 44.1x más lento pero proporciona fidelidad CSS3 completa que ninguna otra biblioteca puede igualar.

Artisan Chrome — Desglose por fases

Descompone el pipeline de Artisan (Chrome) en dos fases:

  1. Chrome CDP Render — Chrome headless convierte HTML a bytes PDF via printToPDF
  2. PDF Import + Embed — TCPDF-Next parsea el PDF de Chrome, extrae la página como Form XObject y la embebe en el documento destino
FaseMediana (ms)Media (ms)Mín (ms)Máx (ms)Stddev
Chrome CDP Render81.1781.1765.5195.804.84
PDF Import + Embed1.962.081.602.870.40
Total83.3583.2968.2097.564.70

Distribución de tiempo: Chrome CDP = 97.4% | PDF Import = 2.3%

El printToPDF de Chrome domina el pipeline con 97.4% del tiempo total. La fase de PDF Import (PdfReader + PageImporter + embedding de XObject) añade solo ~2 ms — overhead despreciable.

Medición estándar vs por fases

La prueba estándar de Artisan (66.70 ms) usa el método integrado writeHtmlChrome() con BrowserPool keep-alive. La prueba por fases (83.35 ms total) instrumenta cada fase por separado, añadiendo overhead de medición. Ambas usan la misma instancia de Chrome keep-alive — el costo de arranque en frío de ~250 ms para el lanzamiento inicial de Chromium se excluye ya que es un costo único amortizado sobre miles de requests.

Cuándo usar cada enfoque

Para HTML simple (tablas, formato básico), usa el parser HTML integrado de TCPDF-Next (1.51 ms). Para layouts CSS3 complejos que requieren fidelidad pixel-perfect (Flexbox, Grid, Web Fonts), usa Artisan — el overhead de ~67 ms compra toda la potencia del motor de renderizado de Chrome.

Ciclo de vida del worker (DocumentFactory vs Standalone)

TCPDF-Next proporciona un patrón DocumentFactory diseñado para workers PHP de larga duración (RoadRunner, Swoole, Laravel Octane). El factory pre-inicializa y bloquea registros compartidos (FontRegistry, ImageRegistry) en el momento de arranque. Cada request HTTP crea un Document ligero y desechable desde el factory — eliminando el overhead de inicialización por request.

Esta sección compara DocumentFactory (registros compartidos y bloqueados) contra createStandalone() (registros frescos por llamada).

Fuentes integradas (Helvetica)

ModoMediana (ms)Memoria pico (MB)Tamaño archivo (KB)
DocumentFactory0.604.03.3
createStandalone()0.704.03.3

Resultado: ~equivalente (ratio 0.86x). Con fuentes integradas (Helvetica), ambos modos rinden de forma idéntica porque no hay parseo de archivos de fuente que cachear. La ventaja real de DocumentFactory aparece con fuentes TrueType.

Fuentes TrueType (DejaVu Sans)

Esta es la prueba clave para la propuesta de valor de DocumentFactory. A diferencia de la prueba de Helvetica anterior (fuente integrada, cero parseo), esta prueba usa DejaVu Sans (~700 KB fuente TrueType). DocumentFactory pre-registra y cachea los datos de fuente parseados en el arranque — los requests subsiguientes omiten toda la I/O de archivos de fuente. createStandalone() debe parsear el archivo .ttf en cada request individual.

ModoMediana (ms)Memoria pico (MB)Tamaño archivo (KB)
Factory (TTF cacheado)2.606.024.5
Standalone (TTF parseo)4.096.024.3

Aceleración del factory: 1.6x — El parseo de fuentes cacheado elimina ~1.5 ms por request. En un worker RoadRunner/Swoole manejando 1,000 requests/minuto, esto ahorra ~25 segundos de tiempo de CPU por minuto.

Uso de memoria pico

Todos los valores en MB (mediana). El benchmark de cada biblioteca se ejecuta en su propio subproceso PHP — solo se carga el autoloader requerido, así que memory_get_peak_usage() refleja el costo real de memoria de esa biblioteca sola.

Escenarios estándar

EscenarioTCPDF-NextTCPDFDomPDFmPDF
Documento simple4.012.06.014.0
Factura4.012.012.014.0
Reporte de 100 páginas4.012.066.027.9*
Documento TrueType6.014.020.016.0

TCPDF-Next mantiene una huella consistente de 4 MB desde documentos de 1 página hasta 100 páginas, demostrando gestión eficiente de memoria a través de objetos de página compactados y referencias a recursos compartidos.

Memoria HTML a PDF

BibliotecaMemoria pico (MB)
TCPDF-Next4.0
Artisan (Chrome)4.0
DomPDF10.0
TCPDF12.0
mPDF18.0

Artisan (Chrome) mide solo la memoria del lado PHP — el proceso de Chrome headless tiene su propio espacio de memoria gestionado por el SO.

Tamaño de archivo de salida

Todos los valores en KB (mediana).

Escenarios estándar

EscenarioTCPDF-NextTCPDFDomPDFmPDF
Documento simple3.37.11.728.0
Factura5.09.24.030.2
Reporte de 100 páginas96.4100.8128.7181.1*
Documento TrueType24.7101.316.142.4

DomPDF produce los archivos más pequeños para documentos simples (1.7 KB) a través de optimización agresiva del content stream. TCPDF-Next produce salida compacta a través de cross-reference streams y object streams de PDF 2.0. TCPDF embebe un subset de fuente TrueType significativamente más grande (101.3 KB vs 24.7 KB).

Tamaño de archivo HTML a PDF

BibliotecaTamaño archivo (KB)
DomPDF5.3
TCPDF-Next6.6
TCPDF12.6
Artisan (Chrome)36.9
mPDF46.0

La salida de Artisan (Chrome) es más grande (36.9 KB) porque el printToPDF de Chrome genera un PDF completo independiente con recursos embebidos.

Throughput

Las pruebas de throughput se ejecutan continuamente durante 30 segundos usando el escenario de documento simple. Los valores reflejan la capacidad de generación sostenida bajo carga.

Estándar (docs/seg)

ModoTCPDF-NextTCPDFDomPDFmPDF
Hilo único2,6051,169233130
4 Workers9,2214,163841487

Documentos por minuto

ModoTCPDF-NextTCPDFDomPDFmPDF
Hilo único156,28470,13413,9567,800
4 Workers553,280249,75250,48429,194

Con 4 workers, TCPDF-Next sostiene más de 9,200 documentos por segundo — más de 553,000 documentos por minuto. Esto es 2.2x el throughput de TCPDF, 11.0x de DomPDF y 19.0x de mPDF.

Throughput de ciclo de vida del worker

Compara DocumentFactory vs createStandalone() throughput usando fuente Helvetica integrada.

ModoDocumentFactorycreateStandalone()
Hilo único2,4902,515
4 Workers9,0749,191

Con fuentes integradas, DocumentFactory y createStandalone() producen throughput equivalente — sin parseo de fuentes que cachear.

Throughput de documento TrueType

Throughput con fuentes TrueType (DejaVu Sans) — expone el overhead real de parseo de fuentes por biblioteca.

BibliotecaHilo único (docs/seg)
TCPDF-Next242
TCPDF81
mPDF50
DomPDF30

El throughput TrueType de TCPDF-Next es 3.0x TCPDF, 4.8x mPDF y 8.0x DomPDF — reflejando su eficiente subsetting y caché de fuentes.

Throughput TTF de ciclo de vida del worker

DocumentFactory (datos de fuente TrueType cacheados) vs createStandalone() (parsear TTF en cada request).

ModoFactory (TTF cacheado)Standalone (TTF parseo)
Hilo único364243
4 Workers1,327871

Ventaja de throughput del factory: 1.5x (hilo único). Los datos de fuente TrueType cacheados eliminan el overhead de parseo de .ttf por request. Con 4 workers, el factory logra 1,327 docs/seg — una mejora del 52.4% sobre standalone.

Throughput HTTP RoadRunner

Benchmark de servidor HTTP real usando RoadRunner con patrón de worker DocumentFactory. Medido via ab (Apache Bench).

ConfiguraciónDocs/segLatencia media (ms)p50 (ms)p99 (ms)Fallidos
1 worker / 1 concurrente1,3200.76110
4 workers / 4 concurrentes4,8120.83110

Overhead HTTP vs pcntl_fork raw:

  • Hilo único: 49.3% overhead (1,320 vs 2,605 docs/seg)
  • Multi-worker: 47.8% overhead (4,812 vs 9,221 docs/seg)

El overhead de ~48% refleja el costo del stack HTTP completo (TCP accept, HTTP parse, escritura de respuesta). Incluso con este overhead, TCPDF-Next detrás de RoadRunner entrega 4,812 respuestas HTTP PDF reales por segundo con latencia sub-milisegundo y cero requests fallidos.

Metodología

  • Entorno: Todas las bibliotecas se ejecutan dentro del mismo contenedor Docker (PHP 8.5.3, Debian bookworm) con configuración idéntica.
  • Restricciones de recursos: Contenedor limitado a 4 CPUs y 16 GB RAM via restricciones de recursos Docker.
  • Runtime: OPcache y JIT habilitados para todas las bibliotecas. Advertencias de deprecación suprimidas globalmente para temporización justa.
  • Aislamiento por subproceso: Cada par biblioteca/escenario se ejecuta en un proceso PHP separado (exec()) para medición de memoria precisa — las clases del autoloader de otras bibliotecas no contaminan memory_get_peak_usage().
  • Paridad de API: TCPDF-Next y TCPDF usan la API nativa Cell/MultiCell para escenarios no HTML. DomPDF y mPDF usan markup HTML equivalente (su interfaz nativa).
  • Prueba de fuente TrueType usa DejaVu Sans (~700 KB .ttf) para exponer costos reales de parseo de fuentes; las pruebas de Helvetica (Base14) muestran la línea base de cero overhead.
  • Artisan (Chrome) usa Chromium headless via CDP para renderizado CSS3 pixel-perfect (JavaScript deshabilitado via CSP).
  • Artisan por fases descompone el renderizado de Chrome: Fase 1 (Chrome CDP printToPDF) vs Fase 2 (PdfReader + PageImporter + embed).
  • Ciclo de vida del worker compara DocumentFactory (FontRegistry compartido + lock, ImageRegistry) vs createStandalone() (registros frescos por llamada).
  • Ciclo de vida del worker TTF demuestra el valor clave de DocumentFactory: datos de fuente TrueType cacheados a través de miles de requests del worker.
  • RoadRunner HTTP usa roadrunner-server/roadrunner con patrón de worker DocumentFactory, medido via ab (Apache Bench).
  • Warmup: Se ejecutan y descartan 3 iteraciones antes de comenzar la medición, asegurando que OPcache y JIT estén completamente precalentados.
  • Iteraciones: 20 iteraciones medidas por escenario. Se reporta la mediana para eliminar ruido de valores atípicos.
  • Throughput: Las pruebas se ejecutan continuamente durante 30 segundos.
  • Temporización: hrtime(true) proporciona medición de reloj de pared con precisión de nanosegundos.
  • Memoria: memory_get_peak_usage(true) reporta la memoria pico real (RSS).
  • Tamaño de archivo: La salida se escribe a disco y se mide con filesize().

Notas sobre interpretación de datos

  • Aislamiento por subproceso para memoria: El benchmark de latencia de cada biblioteca se ejecuta en su propio subproceso PHP. Solo se carga el autoloader requerido, así que memory_get_peak_usage() refleja el costo real de memoria de esa biblioteca sola — no contaminación acumulativa del autoloader de otras bibliotecas.
  • Artisan (Chrome) usa BrowserPool keep-alive: El proceso de Chrome permanece activo entre iteraciones, igualando el comportamiento en producción (RoadRunner/Swoole/Octane). El overhead de arranque en frío (~250 ms para el lanzamiento inicial de Chromium) se excluye — es un costo único amortizado sobre miles de requests.
  • Brecha latencia vs throughput: Las mediciones de latencia de ejecución única incluyen overhead de gc_collect_cycles(), memory_reset_peak_usage() y hrtime() (~0.3 ms). Las pruebas de throughput se ejecutan en un bucle ajustado sin overhead de medición, así que su tiempo por documento (1000/docs_por_seg) es menor que la mediana de ejecución única. Los números de throughput reflejan más precisamente el rendimiento en producción.
  • Helvetica vs TrueType: Helvetica es una fuente PDF integrada (Base14) que requiere cero I/O de archivo. El escenario TrueType usa DejaVu Sans, que requiere parsear archivos .ttf (~700 KB). La ventaja del FontRegistry cacheado de DocumentFactory solo se manifiesta con fuentes TrueType.
  • Compatibilidad JIT (*): Los valores marcados con * fueron medidos con JIT deshabilitado (opcache.jit=0) debido a un segfault PHP JIT (SIGSEGV, código de salida 139) en la ruta de código de esa biblioteca. El caché de bytecode OPcache permanece activo. Esta es una clase conocida de bugs JIT de PHP que afectan ciertos patrones de bucle complejos.

Reproducir los benchmarks

La suite de benchmarks está incluida en el repositorio. Para reproducir estos resultados:

bash
cd benchmark
docker compose up --build

Los resultados se imprimen a stdout al final de la ejecución. La configuración Docker asegura un entorno idéntico independientemente del SO del host.

Lectura adicional

Distribuido bajo la licencia LGPL-3.0-or-later.