Skip to content

Benchmark Performa

Benchmark performa dunia nyata yang membandingkan TCPDF-Next terhadap tiga library PHP PDF yang sudah mapan: TCPDF, DomPDF, dan mPDF. Semua pengujian dijalankan pada hardware identik dalam kondisi Docker terkontrol. Hasil adalah median dari 20 iterasi untuk menghilangkan noise outlier.

Lingkungan Pengujian

ParameterNilai
CPUIntel Core i9-13900K (x86-64)
RAM64 GB DDR5 (Docker dibatasi 16 GB)
Docker4 CPU, 16 GB RAM, Debian bookworm
PHP8.5.3 (CLI, OPcache aktif, JIT aktif)
TCPDF-Next1.7.0
TCPDF6.10.1
DomPDFv3.1.4
mPDFv8.2.7
Artisan (Chrome)Headless Chromium via CDP
RoadRunnerspiral/roadrunner-http ^3.6 (pengujian throughput HTTP)
Warmup3 iterasi (dibuang)
Diukur20 iterasi (median dilaporkan)
Timinghrtime(true) wall clock presisi nanodetik

Perbandingan Interaktif

▼ 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

Kecepatan Pembuatan

Setiap skenario dijalankan 20 kali setelah 3 iterasi warmup. Waktu pembuatan median dilaporkan.

Dokumen Sederhana (1 Halaman)

Satu halaman A4 dengan heading dan teks berformat dasar menggunakan font Helvetica built-in. Tanpa gambar, tanpa tabel.

LibraryWaktu (ms)
TCPDF-Next0,68
TCPDF2,55
DomPDF4,16
mPDF6,71

TCPDF-Next menyelesaikan skenario paling sederhana dalam waktu kurang dari 1 ms — 3,8x lebih cepat dari TCPDF, 6,1x lebih cepat dari DomPDF, dan 9,9x lebih cepat dari mPDF.

Invoice (2 Halaman)

Invoice dua halaman dengan 25 baris item tabular, subtotal, header, footer, dan gambar logo.

LibraryWaktu (ms)
TCPDF1,96
TCPDF-Next2,01
mPDF15,86
DomPDF17,33

TCPDF-Next dan TCPDF hampir setara dalam skenario Invoice (~1,0x). Keduanya jauh mengungguli mPDF (7,9x lebih lambat) dan DomPDF (8,6x lebih lambat).

Laporan 100 Halaman

Dokumen 100 halaman dengan konten campuran padat: heading, paragraf, dan data terstruktur.

LibraryWaktu (ms)
TCPDF-Next34,29
TCPDF105,39
mPDF1.106,59*
DomPDF2.129,12

TCPDF-Next menyelesaikan laporan 100 halaman dalam 34,29 ms — 3,1x lebih cepat dari TCPDF, 32,3x lebih cepat dari mPDF, dan 62,1x lebih cepat dari DomPDF.

Catatan Kompatibilitas JIT

*Hasil Laporan 100 Halaman mPDF diukur dengan JIT dinonaktifkan (opcache.jit=0) karena segfault JIT PHP (SIGSEGV, exit code 139) di jalur kode mPDF. Caching bytecode OPcache tetap aktif. Ini adalah kelas bug JIT PHP yang diketahui yang memengaruhi pola loop kompleks tertentu. Semua skenario mPDF lainnya berjalan dengan JIT aktif.

Dokumen TrueType (1 Halaman)

Satu halaman A4 menggunakan DejaVu Sans (~700 KB font TrueType). Skenario ini mengekspos biaya parsing file font yang sebenarnya — tidak seperti Helvetica (font Base14 built-in yang memerlukan nol file I/O).

LibraryWaktu (ms)
TCPDF-Next4,08
TCPDF12,11
mPDF16,51
DomPDF24,14

TCPDF-Next mem-parse dan meng-embed font TrueType 3,0x lebih cepat dari TCPDF, 4,0x lebih cepat dari mPDF, dan 5,9x lebih cepat dari DomPDF.

Kecepatan Relatif (Semua Skenario)

Semua nilai relatif terhadap TCPDF-Next (baseline 1,0x). Lebih rendah = lebih cepat.

SkenarioTCPDF-NextTCPDFDomPDFmPDF
Dokumen Sederhana1,0x3,8x6,1x9,9x
Invoice1,0x~1,0x8,6x7,9x
Laporan 100 Halaman1,0x3,1x62,1x32,3x
Dokumen TrueType1,0x3,0x5,9x4,0x

HTML ke PDF

Pendekatan Pemrosesan HTML

Library yang berbeda mengambil pendekatan yang sangat berbeda untuk mengonversi HTML ke PDF. Memahami perbedaan ini penting untuk menginterpretasikan hasil benchmark:

Translasi Langsung (TCPDF-Next, TCPDF) — Parser HTML built-in melakukan tokenisasi tag HTML dan memetakannya langsung ke perintah drawing PDF (Cell, MultiCell, Image) dalam satu pass streaming. Pendekatan ini sangat cepat tetapi hanya mendukung tag HTML dasar dan CSS inline — tanpa Flexbox, tanpa Grid, tanpa selector CSS kompleks.

CSS Layout Engine (DomPDF, mPDF) — Library ini dirancang dengan HTML sebagai interface utama mereka. DomPDF membangun DOM tree penuh, menerapkan CSS cascade (specificity, inheritance), dan menghitung layout box-model sebelum me-render ke PDF. WriteHTML() mPDF juga memproses HTML melalui CSS layout engine-nya sendiri. Keduanya mendukung lebih banyak fitur CSS daripada parser translasi langsung (float, elemen terposisi, tabel bergaya) tetapi masih belum mencapai CSS3 level browser penuh.

Rendering Browser Penuh (Artisan / Chrome) — TCPDF-NextArtisan mendelegasikan rendering ke headless Chromium via Chrome DevTools Protocol (CDP). Ini menyediakan dukungan CSS3 pixel-perfect: Flexbox, Grid, Web Font, media query, variabel CSS — output identik dengan apa yang akan diproduksi browser Chrome.

Benchmark membandingkan pendekatan native setiap library: TCPDF-Next dan TCPDF menggunakan parser translasi langsung built-in mereka; DomPDF dan mPDF menggunakan CSS rendering engine mereka (API utama mereka); Artisan menggunakan Chrome.

Hasil

LibraryPendekatanWaktu (ms)
TCPDF-NextTranslasi langsung1,51
TCPDFTranslasi langsung6,60
DomPDFCSS layout engine13,69
mPDFCSS layout engine29,63
Artisan (Chrome)Rendering browser penuh66,70

Waktu Relatif (HTML ke PDF)

LibraryRelatif
TCPDF-Next1,0x
TCPDF4,4x
DomPDF9,0x
mPDF19,6x
Artisan (Chrome)44,1x

Parser translasi langsung TCPDF-Next memberikan performa sub-2 ms — 4,4x lebih cepat dari parser berbasis regex TCPDF, 9,0x lebih cepat dari CSS layout engine DomPDF, dan 19,6x lebih cepat dari mPDF. Artisan (Chrome) 44,1x lebih lambat tetapi menyediakan fidelitas CSS3 penuh yang tidak dapat ditandingi library lain.

Artisan Chrome — Breakdown Per Fase

Menguraikan pipeline Artisan (Chrome) menjadi dua fase:

  1. Chrome CDP Render — headless Chrome mengonversi HTML ke byte PDF via printToPDF
  2. PDF Import + Embed — TCPDF-Next mem-parse PDF Chrome, mengekstrak halaman sebagai Form XObject, dan meng-embed-nya ke dokumen target
FaseMedian (ms)Mean (ms)Min (ms)Max (ms)Stddev
Chrome CDP Render81,1781,1765,5195,804,84
PDF Import + Embed1,962,081,602,870,40
Total83,3583,2968,2097,564,70

Distribusi waktu: Chrome CDP = 97,4% | PDF Import = 2,3%

printToPDF Chrome mendominasi pipeline pada 97,4% total waktu. Fase PDF Import (PdfReader + PageImporter + embedding XObject) hanya menambah ~2 ms — overhead yang dapat diabaikan.

Pengukuran Standar vs Per Fase

Pengujian Artisan standar (66,70 ms) menggunakan method terintegrasi writeHtmlChrome() dengan BrowserPool keep-alive. Pengujian per fase (83,35 ms total) menginstrumentasi setiap fase secara terpisah, menambah overhead pengukuran. Keduanya menggunakan instance Chrome keep-alive yang sama — biaya cold-start ~250 ms untuk peluncuran Chromium awal dikecualikan karena merupakan biaya satu kali yang diamortisasi selama ribuan request.

Kapan Menggunakan Pendekatan Mana

Untuk HTML sederhana (tabel, format dasar), gunakan parser HTML built-in TCPDF-Next (1,51 ms). Untuk layout CSS3 kompleks yang memerlukan fidelitas pixel-perfect (Flexbox, Grid, Web Font), gunakan Artisan — overhead ~67 ms membeli kekuatan penuh rendering engine Chrome.

Siklus Hidup Worker (DocumentFactory vs Standalone)

TCPDF-Next menyediakan pola DocumentFactory yang dirancang untuk PHP worker yang berjalan lama (RoadRunner, Swoole, Laravel Octane). Factory melakukan pre-inisialisasi dan mengunci registry bersama (FontRegistry, ImageRegistry) saat boot. Setiap request HTTP membuat Document ringan dan sekali pakai dari factory — menghilangkan overhead inisialisasi per-request.

Bagian ini membandingkan DocumentFactory (registry bersama, terkunci) dengan createStandalone() (registry baru per panggilan).

Font Built-in (Helvetica)

ModeMedian (ms)Puncak Memori (MB)Ukuran File (KB)
DocumentFactory0,604,03,3
createStandalone()0,704,03,3

Hasil: ~setara (rasio 0,86x). Dengan font built-in (Helvetica), kedua mode berperforma identik karena tidak ada parsing file font yang perlu di-cache. Keunggulan nyata DocumentFactory muncul dengan font TrueType.

Font TrueType (DejaVu Sans)

Ini adalah pengujian utama untuk proposisi nilai DocumentFactory. Tidak seperti pengujian Helvetica di atas (font built-in, tanpa parsing), pengujian ini menggunakan DejaVu Sans (~700 KB font TrueType). DocumentFactory melakukan pre-registrasi dan caching data font yang telah di-parse saat boot — request selanjutnya melewatkan semua file I/O font. createStandalone() harus mem-parse file .ttf pada setiap request.

ModeMedian (ms)Puncak Memori (MB)Ukuran File (KB)
Factory (TTF cached)2,606,024,5
Standalone (TTF parse)4,096,024,3

Speedup Factory: 1,6x — Parsing font yang di-cache menghilangkan ~1,5 ms per request. Dalam worker RoadRunner/Swoole yang menangani 1.000 request/menit, ini menghemat ~25 detik waktu CPU per menit.

Penggunaan Puncak Memori

Semua nilai dalam MB (median). Benchmark setiap library berjalan di subprocess PHP-nya sendiri — hanya autoloader yang diperlukan yang dimuat, sehingga memory_get_peak_usage() mencerminkan biaya memori aktual library itu saja.

Skenario Standar

SkenarioTCPDF-NextTCPDFDomPDFmPDF
Dokumen Sederhana4,012,06,014,0
Invoice4,012,012,014,0
Laporan 100 Halaman4,012,066,027,9*
Dokumen TrueType6,014,020,016,0

TCPDF-Next mempertahankan footprint konsisten 4 MB dari dokumen 1 halaman hingga 100 halaman, mendemonstrasikan manajemen memori yang efisien melalui objek halaman yang dikompaksi dan referensi resource bersama.

Memori HTML ke PDF

LibraryPuncak Memori (MB)
TCPDF-Next4,0
Artisan (Chrome)4,0
DomPDF10,0
TCPDF12,0
mPDF18,0

Artisan (Chrome) mengukur hanya memori sisi PHP — proses headless Chrome memiliki ruang memorinya sendiri yang dikelola OS.

Ukuran File Output

Semua nilai dalam KB (median).

Skenario Standar

SkenarioTCPDF-NextTCPDFDomPDFmPDF
Dokumen Sederhana3,37,11,728,0
Invoice5,09,24,030,2
Laporan 100 Halaman96,4100,8128,7181,1*
Dokumen TrueType24,7101,316,142,4

DomPDF menghasilkan file terkecil untuk dokumen sederhana (1,7 KB) melalui optimasi content-stream yang agresif. TCPDF-Next menghasilkan output kompak melalui cross-reference stream dan object stream PDF 2.0. TCPDF meng-embed subset font TrueType yang jauh lebih besar (101,3 KB vs 24,7 KB).

Ukuran File HTML ke PDF

LibraryUkuran File (KB)
DomPDF5,3
TCPDF-Next6,6
TCPDF12,6
Artisan (Chrome)36,9
mPDF46,0

Output Artisan (Chrome) lebih besar (36,9 KB) karena printToPDF Chrome menghasilkan PDF standalone lengkap dengan resource tertanam.

Throughput

Pengujian throughput berjalan secara kontinu selama 30 detik menggunakan skenario dokumen sederhana. Nilai mencerminkan kapasitas pembuatan berkelanjutan di bawah beban.

Standar (dok/detik)

ModeTCPDF-NextTCPDFDomPDFmPDF
Thread Tunggal2.6051.169233130
4 Worker9.2214.163841487

Dokumen per Menit

ModeTCPDF-NextTCPDFDomPDFmPDF
Thread Tunggal156.28470.13413.9567.800
4 Worker553.280249.75250.48429.194

Dengan 4 worker, TCPDF-Next mempertahankan lebih dari 9.200 dokumen per detik — lebih dari 553.000 dokumen per menit. Ini 2,2x throughput TCPDF, 11,0x DomPDF, dan 19,0x mPDF.

Throughput Siklus Hidup Worker

Membandingkan throughput DocumentFactory vs createStandalone() menggunakan font Helvetica built-in.

ModeDocumentFactorycreateStandalone()
Thread Tunggal2.4902.515
4 Worker9.0749.191

Dengan font built-in, DocumentFactory dan createStandalone() menghasilkan throughput yang setara — tidak ada parsing font yang perlu di-cache.

Throughput Dokumen TrueType

Throughput dengan font TrueType (DejaVu Sans) — mengekspos overhead parsing font per library yang sebenarnya.

LibraryThread Tunggal (dok/detik)
TCPDF-Next242
TCPDF81
mPDF50
DomPDF30

Throughput TrueType TCPDF-Next adalah 3,0x TCPDF, 4,8x mPDF, dan 8,0x DomPDF — mencerminkan subsetting font dan caching yang efisien.

Throughput TTF Siklus Hidup Worker

DocumentFactory (data font TrueType cached) vs createStandalone() (parse TTF setiap request).

ModeFactory (TTF cached)Standalone (TTF parse)
Thread Tunggal364243
4 Worker1.327871

Keunggulan throughput Factory: 1,5x (thread tunggal). Data font TrueType yang di-cache menghilangkan overhead parsing .ttf per-request. Dengan 4 worker, factory mencapai 1.327 dok/detik — peningkatan 52,4% dibanding standalone.

Throughput HTTP RoadRunner

Benchmark server HTTP nyata menggunakan RoadRunner dengan pola worker DocumentFactory. Diukur via ab (Apache Bench).

KonfigurasiDok/detikLatensi Rata-rata (ms)p50 (ms)p99 (ms)Gagal
1 worker / 1 concurrent1.3200,76110
4 worker / 4 concurrent4.8120,83110

Overhead HTTP vs pcntl_fork mentah:

  • Thread tunggal: overhead 49,3% (1.320 vs 2.605 dok/detik)
  • Multi-worker: overhead 47,8% (4.812 vs 9.221 dok/detik)

Overhead ~48% mencerminkan biaya stack HTTP penuh (TCP accept, HTTP parse, response write). Bahkan dengan overhead ini, TCPDF-Next di belakang RoadRunner mengirimkan 4.812 respons HTTP PDF nyata per detik dengan latensi sub-milidetik dan nol request gagal.

Metodologi

  • Lingkungan: Semua library berjalan di dalam container Docker yang sama (PHP 8.5.3, Debian bookworm) dengan konfigurasi identik.
  • Batasan resource: Container dibatasi 4 CPU dan 16 GB RAM via Docker resource constraint.
  • Runtime: OPcache dan JIT aktif untuk semua library. Warning deprecation ditekan secara global untuk timing yang adil.
  • Isolasi subprocess: Setiap pasangan library/skenario berjalan di proses PHP terpisah (exec()) untuk pengukuran memori yang akurat — class autoloader dari library lain tidak mencemari memory_get_peak_usage().
  • Paritas API: TCPDF-Next dan TCPDF menggunakan API native Cell/MultiCell untuk skenario non-HTML. DomPDF dan mPDF menggunakan markup HTML yang setara (interface native mereka).
  • Pengujian font TrueType menggunakan DejaVu Sans (~700 KB .ttf) untuk mengekspos biaya parsing font yang sebenarnya; pengujian Helvetica (Base14) menunjukkan baseline tanpa overhead.
  • Artisan (Chrome) menggunakan headless Chromium via CDP untuk rendering CSS3 pixel-perfect (JavaScript dinonaktifkan via CSP).
  • Artisan per fase menguraikan rendering Chrome: Fase 1 (Chrome CDP printToPDF) vs Fase 2 (PdfReader + PageImporter + embed).
  • Siklus hidup worker membandingkan DocumentFactory (FontRegistry + lock bersama, ImageRegistry) vs createStandalone() (registry baru per panggilan).
  • Siklus hidup worker TTF mendemonstrasikan nilai utama DocumentFactory: data font TrueType yang di-cache di seluruh ribuan request worker.
  • HTTP RoadRunner menggunakan roadrunner-server/roadrunner dengan pola worker DocumentFactory, diukur via ab (Apache Bench).
  • Warmup: 3 iterasi dijalankan dan dibuang sebelum pengukuran dimulai, memastikan OPcache dan JIT sepenuhnya warm.
  • Iterasi: 20 iterasi terukur per skenario. Median dilaporkan untuk menghilangkan noise outlier.
  • Throughput: Pengujian berjalan kontinu selama 30 detik.
  • Timing: hrtime(true) menyediakan pengukuran wall-clock presisi nanodetik.
  • Memori: memory_get_peak_usage(true) melaporkan puncak memori (RSS) yang sebenarnya.
  • Ukuran file: Output di-flush ke disk dan diukur dengan filesize().

Catatan Interpretasi Data

  • Isolasi subprocess untuk memori: Benchmark latensi setiap library berjalan di subprocess PHP-nya sendiri. Hanya autoloader yang diperlukan yang dimuat, sehingga memory_get_peak_usage() mencerminkan biaya memori aktual library itu saja — bukan polusi autoloader kumulatif dari library lain.
  • Artisan (Chrome) menggunakan BrowserPool keep-alive: Proses Chrome tetap hidup di seluruh iterasi, sesuai perilaku produksi (RoadRunner/Swoole/Octane). Overhead cold-start (~250 ms untuk peluncuran Chromium awal) dikecualikan — ini biaya satu kali yang diamortisasi selama ribuan request.
  • Gap Latensi vs Throughput: Pengukuran latensi single-run mencakup gc_collect_cycles(), memory_reset_peak_usage(), dan overhead hrtime() (~0,3 ms). Pengujian throughput berjalan dalam tight loop tanpa overhead pengukuran, sehingga waktu per-dokumennya (1000/dok_per_detik) lebih rendah dari median single-run. Angka throughput lebih akurat mencerminkan performa produksi.
  • Helvetica vs TrueType: Helvetica adalah font PDF built-in (Base14) yang memerlukan nol file I/O. Skenario TrueType menggunakan DejaVu Sans, yang memerlukan parsing file .ttf (~700 KB). Keunggulan FontRegistry cached DocumentFactory hanya muncul dengan font TrueType.
  • Kompatibilitas JIT (*): Nilai yang ditandai * diukur dengan JIT dinonaktifkan (opcache.jit=0) karena segfault JIT PHP (SIGSEGV, exit code 139) di jalur kode library tersebut. Caching bytecode OPcache tetap aktif. Ini adalah kelas bug JIT PHP yang diketahui yang memengaruhi pola loop kompleks tertentu.

Mereproduksi Benchmark

Suite benchmark disertakan dalam repository. Untuk mereproduksi hasil ini:

bash
cd benchmark
docker compose up --build

Hasil dicetak ke stdout di akhir run. Setup Docker memastikan lingkungan identik terlepas dari OS host.

Bacaan Lanjutan

Didistribusikan di bawah lisensi LGPL-3.0-or-later.