Benchmarks

Understand Wenmode’s benchmark cases, parser configuration, dependency versions, and current Markdown-to-HTML results.


Run the benchmark suite from the repository root:

uv run --group benchmark python scripts/benchmark.py --case all

The script compares Markdown-to-HTML throughput across Wenmode and the parser libraries covered by the migration guides. It reports best time, mean time, throughput, and relative speed versus wenmode-core.

Cases

Case

Source

What it represents

docs

Wenmode’s own docs/*.md files

short project documentation pages

rust-book

Rust Book Markdown files from the upstream archive

large CommonMark-style technical documentation

progit

Pro Git English Markdown files from the upstream archive

medium-size book-style Markdown with older conventions

Remote archives are cached under the system temporary directory in wenmode-benchmark.

Parser configuration

All benchmark targets are created once before warmup and timed iterations, then reused for every render call.

Target

Configuration

wenmode-core

Wenmode([Table, *commonmark], HTMLRenderer(escape=False, sanitize_urls=False))

wenmode-all

github plus directives, math, definition lists, abbreviations, spoilers, ruby, and extra formatting rules

mistune

mistune.create_markdown(renderer='html', plugins=['table', 'speedup'])

python-markdown

one reusable markdown.Markdown(extensions=['tables', 'sane_lists']), reset before each conversion

markdown-it-py

MarkdownIt('commonmark', {'html': True}).enable('table')

markdown2

one reusable markdown2.Markdown(extras=['tables'])

marko

marko.ext.gfm.gfm, a reusable GFM Markdown instance

commonmark.py

one reusable commonmark.Parser() and commonmark.HtmlRenderer()

The rule sets are intentionally close, not identical. Most non-Wenmode parsers enable table support to approximate wenmode-core. Marko’s GFM helper is broader than tables, and commonmark.py is CommonMark-only because it does not support pipe tables. wenmode-all is deliberately broader than the other targets and measures the overhead of carrying many enabled rules.

Versions

Library

Version

wenmode

0.1.0

mistune

3.2.1

python-markdown

3.10.2

markdown-it-py

4.2.0

markdown2

2.5.5

marko

2.2.3

commonmark.py

0.9.2

Current results

These numbers are from one local --case all run. Lower mean time is better. vs core is relative to wenmode-core.

Case

Bytes

Library

Mean

MB/s

vs core

docs

53,792

wenmode-core

4.84ms

11.58

1.00x

docs

53,792

wenmode-all

5.89ms

9.59

0.82x

docs

53,792

mistune

8.64ms

6.89

0.56x

docs

53,792

markdown-it-py

13.27ms

4.19

0.36x

docs

53,792

commonmark.py

20.72ms

2.67

0.23x

docs

53,792

python-markdown

28.98ms

1.88

0.17x

docs

53,792

markdown2

43.34ms

1.25

0.11x

docs

53,792

marko

49.65ms

1.11

0.10x

rust-book

1,225,464

wenmode-core

138.87ms

9.07

1.00x

rust-book

1,225,464

wenmode-all

156.48ms

8.09

0.89x

rust-book

1,225,464

mistune

214.92ms

6.53

0.65x

rust-book

1,225,464

markdown-it-py

360.20ms

3.49

0.39x

rust-book

1,225,464

python-markdown

624.73ms

2.00

0.22x

rust-book

1,225,464

marko

1.178s

1.04

0.12x

rust-book

1,225,464

markdown2

4.082s

0.30

0.03x

rust-book

1,225,464

commonmark.py

9.619s

0.14

0.01x

progit

502,090

wenmode-core

26.61ms

19.24

1.00x

progit

502,090

wenmode-all

35.31ms

16.36

0.75x

progit

502,090

mistune

44.01ms

12.40

0.60x

progit

502,090

markdown-it-py

76.29ms

7.15

0.35x

progit

502,090

python-markdown

149.01ms

3.47

0.18x

progit

502,090

commonmark.py

347.45ms

1.49

0.08x

progit

502,090

marko

357.08ms

1.43

0.07x

progit

502,090

markdown2

1.425s

0.35

0.02x

Benchmark numbers are hardware- and corpus-dependent. Use the command above in your own environment before making performance-sensitive migration decisions.