Skip to content

Бенчмарки производительности

Реальные бенчмарки производительности, сравнивающие TCPDF-Next с тремя устоявшимися PHP-библиотеками для работы с PDF: TCPDF, DomPDF и mPDF. Все тесты выполнены на идентичном оборудовании в контролируемых условиях Docker. Результаты представляют медианы 20 итераций для устранения статистических выбросов.

Тестовое окружение

ПараметрЗначение
CPUIntel Core i9-13900K (x86-64)
RAM64 ГБ DDR5 (Docker ограничен 16 ГБ)
Docker4 CPU, 16 ГБ RAM, Debian bookworm
PHP8.5.3 (CLI, OPcache включён, JIT включён)
TCPDF-Next1.7.0
TCPDF6.10.1
DomPDFv3.1.4
mPDFv8.2.7
Artisan (Chrome)Headless Chromium через CDP
RoadRunnerspiral/roadrunner-http ^3.6 (тесты HTTP-пропускной способности)
Прогрев3 итерации (отброшены)
Измерения20 итераций (представлена медиана)
Хронометражhrtime(true) наносекундная точность

Интерактивное сравнение

▼ 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

Скорость генерации

Каждый сценарий выполнялся 20 раз после 3 прогревочных итераций. Представлено медианное время генерации.

Простой документ (1 страница)

Одна страница A4 с заголовком и базовым форматированным текстом на встроенном шрифте Helvetica. Без изображений, без таблиц.

БиблиотекаВремя (мс)
TCPDF-Next0,68
TCPDF2,55
DomPDF4,16
mPDF6,71

TCPDF-Next завершает простейший сценарий менее чем за 1 мс — в 3,8x быстрее TCPDF, в 6,1x быстрее DomPDF и в 9,9x быстрее mPDF.

Счёт (2 страницы)

Двухстраничный счёт с 25-строчной таблицей позиций, промежуточными итогами, колонтитулами и изображением логотипа.

БиблиотекаВремя (мс)
TCPDF1,96
TCPDF-Next2,01
mPDF15,86
DomPDF17,33

TCPDF-Next и TCPDF фактически равны в сценарии счёта (~1,0x). Оба значительно превосходят mPDF (в 7,9x медленнее) и DomPDF (в 8,6x медленнее).

100-страничный отчёт

100-страничный документ с плотным смешанным контентом: заголовки, абзацы и структурированные данные.

БиблиотекаВремя (мс)
TCPDF-Next34,29
TCPDF105,39
mPDF1 106,59*
DomPDF2 129,12

TCPDF-Next завершает 100-страничный отчёт за 34,29 мс — в 3,1x быстрее TCPDF, в 32,3x быстрее mPDF и в 62,1x быстрее DomPDF.

Примечание по совместимости с JIT

*Результат mPDF для 100-страничного отчёта получен с выключенным JIT (opcache.jit=0) из-за segfault PHP JIT (SIGSEGV, exit code 139) в пути выполнения кода mPDF. Кеширование байт-кода OPcache оставалось активным. Это известный класс ошибок PHP JIT, затрагивающих определённые сложные циклические паттерны. Все остальные сценарии mPDF выполнялись с включённым JIT.

TrueType-документ (1 страница)

Одна страница A4 с использованием DejaVu Sans (~700 КБ TrueType-шрифт). Этот сценарий выявляет реальные затраты на парсинг шрифтовых файлов — в отличие от Helvetica (встроенный шрифт Base14, не требующий файлового ввода-вывода).

БиблиотекаВремя (мс)
TCPDF-Next4,08
TCPDF12,11
mPDF16,51
DomPDF24,14

TCPDF-Next парсит и встраивает TrueType-шрифт в 3,0x быстрее TCPDF, в 4,0x быстрее mPDF и в 5,9x быстрее DomPDF.

Относительная скорость (все сценарии)

Все значения относительно TCPDF-Next (базовый уровень 1,0x). Меньше = быстрее.

СценарийTCPDF-NextTCPDFDomPDFmPDF
Простой документ1,0x3,8x6,1x9,9x
Счёт1,0x~1,0x8,6x7,9x
100-стр. отчёт1,0x3,1x62,1x32,3x
TrueType-документ1,0x3,0x5,9x4,0x

HTML в PDF

Подходы к обработке HTML

Различные библиотеки используют принципиально разные подходы к конвертации HTML в PDF. Понимание этих различий важно для интерпретации результатов бенчмарков:

Прямая трансляция (TCPDF-Next, TCPDF) — Встроенный парсер HTML токенизирует HTML-теги и отображает их непосредственно на команды отрисовки PDF (Cell, MultiCell, Image) за один потоковый проход. Этот подход крайне быстр, но поддерживает только базовые HTML-теги и inline CSS — без Flexbox, Grid и сложных CSS-селекторов.

Движок CSS-макетов (DomPDF, mPDF) — Эти библиотеки разработаны с HTML как основным интерфейсом. DomPDF строит полное DOM-дерево, применяет каскад CSS (специфичность, наследование) и вычисляет блочную модель макета перед рендерингом в PDF. mPDF аналогично обрабатывает HTML через свой движок CSS-макетов. Обе поддерживают больше CSS-возможностей, чем парсеры прямой трансляции (float, позиционированные элементы, стилизованные таблицы), но не достигают полной поддержки CSS3 уровня браузера.

Полноценный рендеринг браузера (Artisan / Chrome) — TCPDF-Next Artisan делегирует рендеринг headless Chromium через Chrome DevTools Protocol (CDP). Это обеспечивает пиксельно-точную поддержку CSS3: Flexbox, Grid, Web Fonts, media queries, CSS-переменные — результат идентичен тому, что производит браузер Chrome.

Бенчмарк сравнивает нативный подход каждой библиотеки: TCPDF-Next и TCPDF используют встроенный парсер прямой трансляции; DomPDF и mPDF используют свои движки CSS-рендеринга (их основной API); Artisan использует Chrome.

Результаты

БиблиотекаПодходВремя (мс)
TCPDF-NextПрямая трансляция1,51
TCPDFПрямая трансляция6,60
DomPDFДвижок CSS-макетов13,69
mPDFДвижок CSS-макетов29,63
Artisan (Chrome)Полный рендеринг браузера66,70

Относительное время (HTML в PDF)

БиблиотекаОтносительно
TCPDF-Next1,0x
TCPDF4,4x
DomPDF9,0x
mPDF19,6x
Artisan (Chrome)44,1x

Парсер прямой трансляции TCPDF-Next обеспечивает производительность менее 2 мс — в 4,4x быстрее парсера TCPDF на основе regex, в 9,0x быстрее движка CSS-макетов DomPDF и в 19,6x быстрее mPDF. Artisan (Chrome) в 44,1x медленнее, но обеспечивает полную точность CSS3, которую не может обеспечить ни одна другая библиотека.

Artisan Chrome — разбивка по фазам

Декомпозиция пайплайна Artisan (Chrome) на две фазы:

  1. Chrome CDP Render — headless Chrome конвертирует HTML в PDF-байты через printToPDF
  2. PDF Import + Embed — TCPDF-Next парсит PDF Chrome, извлекает страницу как Form XObject и встраивает в целевой документ
ФазаМедиана (мс)Среднее (мс)Мин (мс)Макс (мс)Стд. откл.
Chrome CDP Render81,1781,1765,5195,804,84
PDF Import + Embed1,962,081,602,870,40
Итого83,3583,2968,2097,564,70

Распределение времени: Chrome CDP = 97,4% | PDF Import = 2,3%

printToPDF Chrome доминирует в пайплайне — 97,4% общего времени. Фаза PDF Import (PdfReader + PageImporter + встраивание XObject) добавляет лишь ~2 мс — пренебрежимые накладные расходы.

Стандартное vs пофазное измерение

Стандартный тест Artisan (66,70 мс) использует интегрированный метод writeHtmlChrome() с keep-alive BrowserPool. Пофазный тест (83,35 мс итого) инструментирует каждую фазу отдельно, добавляя накладные расходы измерения. Оба используют тот же Chrome-инстанс с keep-alive — стоимость холодного старта ~250 мс при первоначальном запуске Chromium исключена как разовая стоимость, амортизируемая на тысячи запросов.

Когда использовать какой подход

Для простого HTML (таблицы, базовое форматирование) используйте встроенный HTML-парсер TCPDF-Next (1,51 мс). Для сложных CSS3-макетов, требующих пиксельной точности (Flexbox, Grid, Web Fonts), используйте Artisan — накладные расходы ~67 мс дают полную мощь движка рендеринга Chrome.

Жизненный цикл воркеров (DocumentFactory vs Standalone)

TCPDF-Next предоставляет паттерн DocumentFactory, разработанный для долгоживущих PHP-воркеров (RoadRunner, Swoole, Laravel Octane). Фабрика предварительно инициализирует и блокирует общие реестры (FontRegistry, ImageRegistry) при загрузке. Каждый HTTP-запрос создаёт лёгкий, одноразовый Document из фабрики — устраняя накладные расходы на инициализацию каждого запроса.

Этот раздел сравнивает DocumentFactory (общие, заблокированные реестры) с createStandalone() (свежие реестры при каждом вызове).

Встроенные шрифты (Helvetica)

РежимМедиана (мс)Пиковая память (МБ)Размер файла (КБ)
DocumentFactory0,604,03,3
createStandalone()0,704,03,3

Результат: ~эквивалентно (соотношение 0,86x). Со встроенными шрифтами (Helvetica) оба режима работают идентично, поскольку нет парсинга шрифтовых файлов для кеширования. Реальное преимущество DocumentFactory проявляется с TrueType-шрифтами.

TrueType-шрифты (DejaVu Sans)

Это ключевой тест ценности DocumentFactory. В отличие от теста Helvetica выше (встроенный шрифт, нулевой парсинг), этот тест использует DejaVu Sans (~700 КБ TrueType-шрифт). DocumentFactory предварительно регистрирует и кеширует распарсенные данные шрифта при загрузке — последующие запросы пропускают весь файловый ввод-вывод шрифтов. createStandalone() должен парсить файл .ttf при каждом запросе.

РежимМедиана (мс)Пиковая память (МБ)Размер файла (КБ)
Factory (TTF кешировано)2,606,024,5
Standalone (TTF парсинг)4,096,024,3

Ускорение Factory: 1,6x — Кешированный парсинг шрифтов устраняет ~1,5 мс на запрос. В воркере RoadRunner/Swoole, обрабатывающем 1 000 запросов/минуту, это экономит ~25 секунд CPU-времени в минуту.

Пиковое использование памяти

Все значения в МБ (медиана). Бенчмарк каждой библиотеки выполняется в собственном подпроцессе PHP — загружается только необходимый автозагрузчик, поэтому memory_get_peak_usage() отражает фактическую стоимость памяти только этой библиотеки.

Стандартные сценарии

СценарийTCPDF-NextTCPDFDomPDFmPDF
Простой документ4,012,06,014,0
Счёт4,012,012,014,0
100-стр. отчёт4,012,066,027,9*
TrueType-документ6,014,020,016,0

TCPDF-Next поддерживает стабильный отпечаток 4 МБ от 1-страничных до 100-страничных документов, демонстрируя эффективное управление памятью через уплотнённые объекты страниц и общие ссылки на ресурсы.

Память HTML в PDF

БиблиотекаПиковая память (МБ)
TCPDF-Next4,0
Artisan (Chrome)4,0
DomPDF10,0
TCPDF12,0
mPDF18,0

Artisan (Chrome) измеряет только память на стороне PHP — процесс headless Chrome имеет собственное пространство памяти, управляемое ОС.

Размер выходного файла

Все значения в КБ (медиана).

Стандартные сценарии

СценарийTCPDF-NextTCPDFDomPDFmPDF
Простой документ3,37,11,728,0
Счёт5,09,24,030,2
100-стр. отчёт96,4100,8128,7181,1*
TrueType-документ24,7101,316,142,4

DomPDF создаёт наименьшие файлы для простых документов (1,7 КБ) за счёт агрессивной оптимизации потоков контента. TCPDF-Next создаёт компактный вывод через потоки перекрёстных ссылок и объектные потоки PDF 2.0. TCPDF встраивает значительно больший подмножество TrueType-шрифта (101,3 КБ vs 24,7 КБ).

Размер файла HTML в PDF

БиблиотекаРазмер файла (КБ)
DomPDF5,3
TCPDF-Next6,6
TCPDF12,6
Artisan (Chrome)36,9
mPDF46,0

Вывод Artisan (Chrome) больше (36,9 КБ), потому что printToPDF Chrome генерирует полный самостоятельный PDF со встроенными ресурсами.

Пропускная способность

Тесты пропускной способности выполняются непрерывно в течение 30 секунд с использованием сценария простого документа. Значения отражают устойчивую производительность генерации под нагрузкой.

Стандартная (док/сек)

РежимTCPDF-NextTCPDFDomPDFmPDF
Один поток2 6051 169233130
4 воркера9 2214 163841487

Документов в минуту

РежимTCPDF-NextTCPDFDomPDFmPDF
Один поток156 28470 13413 9567 800
4 воркера553 280249 75250 48429 194

С 4 воркерами TCPDF-Next поддерживает свыше 9 200 документов в секунду — более 553 000 документов в минуту. Это в 2,2x превышает пропускную способность TCPDF, в 11,0x DomPDF и в 19,0x mPDF.

Пропускная способность жизненного цикла воркеров

Сравнение DocumentFactory и createStandalone() при использовании встроенного шрифта Helvetica.

РежимDocumentFactorycreateStandalone()
Один поток2 4902 515
4 воркера9 0749 191

Со встроенными шрифтами DocumentFactory и createStandalone() обеспечивают эквивалентную пропускную способность — нет парсинга шрифтов для кеширования.

Пропускная способность TrueType-документов

Пропускная способность с TrueType-шрифтами (DejaVu Sans) — выявляет реальные накладные расходы парсинга шрифтов для каждой библиотеки.

БиблиотекаОдин поток (док/сек)
TCPDF-Next242
TCPDF81
mPDF50
DomPDF30

Пропускная способность TCPDF-Next с TrueType в 3,0x превышает TCPDF, в 4,8x mPDF и в 8,0x DomPDF — отражая эффективный subsetting и кеширование шрифтов.

Пропускная способность TTF жизненного цикла воркеров

DocumentFactory (кешированные данные TrueType-шрифта) vs createStandalone() (парсинг TTF при каждом запросе).

РежимFactory (TTF кешировано)Standalone (TTF парсинг)
Один поток364243
4 воркера1 327871

Преимущество пропускной способности Factory: 1,5x (один поток). Кешированные данные TrueType-шрифта устраняют накладные расходы парсинга .ttf при каждом запросе. С 4 воркерами фабрика достигает 1 327 док/сек — улучшение на 52,4% по сравнению со standalone.

HTTP-пропускная способность RoadRunner

Реальный бенчмарк HTTP-сервера с использованием RoadRunner с паттерном воркера DocumentFactory. Измерено через ab (Apache Bench).

КонфигурацияДок/секСредняя задержка (мс)p50 (мс)p99 (мс)Ошибки
1 воркер / 1 параллельный1 3200,76110
4 воркера / 4 параллельных4 8120,83110

Накладные расходы HTTP vs чистый pcntl_fork:

  • Один поток: 49,3% накладных расходов (1 320 vs 2 605 док/сек)
  • Несколько воркеров: 47,8% накладных расходов (4 812 vs 9 221 док/сек)

~48% накладных расходов отражают стоимость полного HTTP-стека (TCP accept, парсинг HTTP, запись ответа). Даже с этими накладными расходами TCPDF-Next за RoadRunner обеспечивает 4 812 реальных HTTP PDF-ответов в секунду с субмиллисекундной задержкой и нулём ошибок.

Методология

  • Окружение: Все библиотеки работают внутри одного Docker-контейнера (PHP 8.5.3, Debian bookworm) с идентичной конфигурацией.
  • Ограничения ресурсов: Контейнер ограничен 4 CPU и 16 ГБ RAM через ограничения ресурсов Docker.
  • Среда выполнения: OPcache и JIT включены для всех библиотек. Предупреждения об устаревании подавлены глобально для честного хронометража.
  • Изоляция подпроцессов: Каждая пара библиотека/сценарий выполняется в отдельном PHP-процессе (exec()) для точного измерения памяти — классы автозагрузчика других библиотек не загрязняют memory_get_peak_usage().
  • Паритет API: TCPDF-Next и TCPDF используют нативный API Cell/MultiCell для не-HTML сценариев. DomPDF и mPDF используют эквивалентную HTML-разметку (их нативный интерфейс).
  • Тест TrueType-шрифтов использует DejaVu Sans (~700 КБ .ttf) для выявления реальных затрат на парсинг шрифтов; тесты Helvetica (Base14) показывают базовый уровень без накладных расходов.
  • Artisan (Chrome) использует headless Chromium через CDP для пиксельно-точного рендеринга CSS3 (JavaScript отключён через CSP).
  • Artisan пофазный декомпозирует рендеринг Chrome: Фаза 1 (Chrome CDP printToPDF) vs Фаза 2 (PdfReader + PageImporter + встраивание).
  • Жизненный цикл воркеров сравнивает DocumentFactory (общие FontRegistry + блокировка, ImageRegistry) vs createStandalone() (свежие реестры при каждом вызове).
  • Жизненный цикл воркеров TTF демонстрирует ключевую ценность DocumentFactory: кешированные данные TrueType-шрифта для тысяч запросов воркера.
  • RoadRunner HTTP использует roadrunner-server/roadrunner с паттерном воркера DocumentFactory, измерено через ab (Apache Bench).
  • Прогрев: 3 итерации выполняются и отбрасываются перед началом измерений, обеспечивая полный прогрев OPcache и JIT.
  • Итерации: 20 измеренных итераций на сценарий. Представлена медиана для устранения статистических выбросов.
  • Пропускная способность: Тесты выполняются непрерывно 30 секунд.
  • Хронометраж: hrtime(true) обеспечивает наносекундную точность.
  • Память: memory_get_peak_usage(true) показывает реальный (RSS) пик памяти.
  • Размер файла: Вывод записывается на диск и измеряется через filesize().

Примечания по интерпретации данных

  • Изоляция подпроцессов для памяти: Бенчмарк задержки каждой библиотеки выполняется в собственном подпроцессе PHP. Загружается только необходимый автозагрузчик, поэтому memory_get_peak_usage() отражает фактическую стоимость памяти только этой библиотеки — без кумулятивного загрязнения автозагрузчиком других библиотек.
  • Artisan (Chrome) использует BrowserPool keep-alive: Процесс Chrome остаётся живым между итерациями, соответствуя поведению в продакшене (RoadRunner/Swoole/Octane). Накладные расходы холодного старта (~250 мс на первоначальный запуск Chromium) исключены — это разовая стоимость, амортизируемая на тысячи запросов.
  • Разрыв задержка vs пропускная способность: Измерения задержки одного запуска включают gc_collect_cycles(), memory_reset_peak_usage() и накладные расходы hrtime() (~0,3 мс). Тесты пропускной способности выполняются в плотном цикле без накладных расходов измерения, поэтому их время на документ (1000/док_в_сек) ниже медианы одного запуска. Показатели пропускной способности точнее отражают производственную производительность.
  • Helvetica vs TrueType: Helvetica — встроенный PDF-шрифт (Base14), не требующий файлового ввода-вывода. Сценарий TrueType использует DejaVu Sans, что требует парсинга файлов .ttf (~700 КБ). Преимущество кешированного FontRegistry у DocumentFactory проявляется только с TrueType-шрифтами.
  • Совместимость с JIT (*): Значения, помеченные *, измерены с выключенным JIT (opcache.jit=0) из-за segfault PHP JIT (SIGSEGV, exit code 139) в пути выполнения кода этой библиотеки. Кеширование байт-кода OPcache остаётся активным. Это известный класс ошибок PHP JIT, затрагивающих определённые сложные циклические паттерны.

Воспроизведение бенчмарков

Набор бенчмарков включён в репозиторий. Для воспроизведения результатов:

bash
cd benchmark
docker compose up --build

Результаты выводятся в stdout по завершении теста. Настройка Docker обеспечивает идентичное окружение независимо от хостовой ОС.

Дополнительные материалы

Распространяется по лицензии LGPL-3.0-or-later.