Performance

Performance depends on the operation. Alto measures direct conversion, document creation, existing-document rendering, analysis, formatting, and memory separately.

Choose the right path

Need API
Convert once Markdown::github()->toHtml($source)
Convert an inline-only field Markdown::github()->toInlineHtml($source)
Query, lint, or edit Markdown::github()->fromString($source)
Render an existing document $document->toHtml()
Preserve edited source $document->toMarkdown()

Direct conversion avoids the public document workspace. A document costs more to create but can reuse its parsed representation and inline caches across several operations.

Inline conversion also skips the block scanner and never creates paragraph, heading, list, or reference-definition nodes. It is the narrow path for already-scoped rich-text fields, not a faster substitute for document conversion.

Avoid materializing query results unless needed. first() can stop early, while all() and count() consume the complete lazy collection.

Reference results

The release corpus contains 95 public Markdown files totaling about 1.2 MiB. On the reference Apple M1 with PHP 8.5, CLI OPcache enabled, and JIT disabled, one complete direct-conversion iteration falls in these observed ranges:

Engine Typical median time Cold peak memory
Alto 110--120 ms 4.6 MiB
League CommonMark 270--280 ms 17.8 MiB
Parsedown 65--70 ms 4.4 MiB
Michelf PHP Markdown 140--150 ms 3.1 MiB
cebe/markdown 55--60 ms 6.7 MiB

These are reference measurements, not universal rankings. League uses its GFM converter. Parsedown, Michelf, and cebe are one-shot throughput references and do not provide Alto's complete document, conformance, query, lint, format, and editing contract.

The generated Markdown, HTML, SVG, and JSON reports contain every corpus, product lane, measured sample, protocol field, and input digest.

Extension dispatch

Public inline parsers are compiled into dispatch lists keyed by their trigger byte. When an installed extension's trigger is absent, instrumentation records zero calls to its parser.

A focused PHPBench run on the same reference machine measured the following modes with CLI OPcache enabled, 10 iterations, and 10 revolutions:

Subject PHPBench mode
Baseline source, no extension 2.154 ms
Same source, inline extension installed but not triggered 2.103 ms
Source containing 48 trigger bytes, no extension 2.076 ms
Same trigger source, installed parser declines all 48 matches 2.118 ms

The small differences overlap normal run variation. This benchmark guards the dispatch boundary rather than claiming that an extension makes conversion faster. A parser is called only for matching trigger bytes, and a declining parser adds work at those matches.

Measurement protocol

The comparative lane converts the complete official corpus with Alto, League CommonMark, Parsedown, Michelf, and cebe. Product-only lanes measure Alto direct conversion, document parsing, first and existing-document HTML rendering, queries, stats, lint, formatting, typed edits, diffs, protected atomic saves, and fresh CLI startup.

Time uses five measured iterations of one complete workload and no unmeasured target warmup. Each library is initialized with a small neutral document before measurement. Memory uses one fresh process per engine, corpus, temperature, or product lane. Cold and warm peaks remain separate and are never added.

Do not compare results produced with Xdebug or PCOV enabled. Keep the corpus, PHP version, OPcache state, warmup count, iterations, and HTML policy identical between engines. Use real documents for product comparisons and synthetic families only to locate a specific cost.