Skip to content

RayoMD tester.md Warm Benchmark 2026 07 17

mkuch edited this page Jul 17, 2026 · 1 revision

RayoMD tester.md warm benchmark (2026-07-17)

Commit 49d35a2 reduced the warm native generation median for tester.md on WSL /mnt/e from 16.13 ms to 7.89 ms. Every candidate round was below the 10 ms goal. The current Windows build measured 1.21 ms median.

This is a focused before/after optimization record, not an end-to-end export number or a cross-engine ranking.

Scope and method

  • Baseline: RayoMD 2.4.0, commit 315b404.
  • Candidate: commit 49d35a2.
  • Fixture: repository tester.md, 3,896 bytes and 142 lines, using the Unicode embedded-font path and producing six pages. It exercises headings, inline styles, tables, lists, links, local/remote/missing images, math, and code. The same local mascot source occurs as a direct image, a reference image, and an inline reference image.
  • Renderer options: modern normal.
  • Host: Windows 11 Pro build 26200, AMD Ryzen 5 5600X, 128 GiB RAM.
  • Windows build: MinGW-w64 GCC 15.2.0 Release; 1,000 timed builds per process.
  • Linux build: WSL2 Ubuntu GCC 13.3.0 Release; 200 timed builds per process; source, fixture, and output on the Windows-backed /mnt/e mount.

RayoMD --bench reads the Markdown before timing, performs an untimed warm-up and sample build, then measures repeated in-memory BuildPdf calls. It excludes process startup, source-file reading, and timed output-file writing. See the --bench implementation.

Result

Platform/storage Sampling Baseline median (range) Candidate median (range) Median change
Linux WSL /mnt/e 5 interleaved rounds x 200 16.13 ms (14.89-18.83) 7.89 ms (7.30-9.40) -51.1%
Windows workspace baseline 9 x 1,000; candidate 5 x 1,000 1.26 ms (1.17-1.60) 1.21 ms (1.07-1.42) -4.0% nominal

Linux round averages in run order:

  • Baseline: 14.89, 18.83, 16.41, 16.13, 15.05 ms.
  • Candidate: 9.14, 9.40, 7.89, 7.30, 7.88 ms.

The Linux mean moved from 16.262 ms to 8.322 ms, a 48.8% reduction. All five candidate runs beat 10 ms. The small Windows movement is within the range where host variation can dominate, so it is treated as neutral; Windows already beat the target comfortably.

What changed

ImageRegistry now records a raw-source alias only after that source has passed the existing image policy and loaded successfully. When direct and reference syntax resolve to the same source string later in the same PDF build, the registry reuses the accepted image instead of repeating path policy resolution and weakly_canonical filesystem work. That repeated filesystem work was especially costly on WSL DrvFS.

The change is deliberately local and does not add a global or cross-document cache.

Security boundary

For a local source, the first use still canonicalizes and enforces the existing local-image policy; URL sources still follow the existing fetch policy. On a decoded-cache miss, the source is read or fetched and decoded. Failed or rejected sources never receive an alias, and the registry exists only for one PDF build. A later exact-source match can reuse only image bytes already accepted by that registry; it cannot authorize or read a new path. If a symlink changes during a single build, reuse keeps the initially accepted bytes rather than reopening a new target.

Correctness and guardrails

Candidate PDFs were byte-identical to the matching baseline on each platform:

Platform Average PDF bytes Baseline and candidate SHA-256
Linux 494,837 89E94517FE9CD99DC29CED66E299076874CEE39FBB4E0614A9FFC2AF49CEA5C4
Windows 379,528 67B5D19D092D910B573C954018B5B238248C6AC0DCC7FE0F4DD4067DBE9AE400

The hashes differ across platforms because their embedded font resources differ; equivalence is baseline versus candidate on the same platform. Packaged binary sizes were unchanged: 428,592 bytes on Linux and 2,806,784 bytes on Windows.

Order-balanced Windows image-free guardrails, seven rounds x 1,000:

Fixture Baseline median Candidate median
24 KiB table 0.97 ms 0.85 ms
24 KiB Unicode 1.67 ms 1.65 ms

Both Windows and Linux candidate trees passed all CTest entries (2/2), and git diff --check was clean.

Relation to the quoted Glu result

The quoted Glu transcript reported Build done at 13.033333 ms and total runtime at 13.557416 ms for barcodes.md. RayoMD's 7.89 ms median is numerically lower than that Build done value, but it is not an apples-to-apples head-to-head benchmark:

  • Glu's example barcodes.md is 490 bytes, 24 lines, and one page with custom barcode elements; RayoMD's tester.md is 3,896 bytes, 142 lines, and exercises a different feature mix.
  • Glu's internal build timer covers its input read, Markdown dispatch, HTML/Lua, typesetting, font, PDF, and auxiliary-file pipeline, but not process startup.
  • RayoMD's warm --bench number excludes input reading and timed output writing and averages many PDF builds in one process.
  • The quoted Glu run was not collected as an interleaved same-host A/B against RayoMD.

Relevant sources: Glu timing flow, Glu Markdown pipeline, and the barcodes.md fixture. The defensible statement is that RayoMD beat the requested 10 ms target and its measured warm number is below the quoted Glu number; it is not a general claim that one renderer is faster for equivalent work.

Reproduce

Build the exact candidate revision, then run several fresh benchmark processes:

git checkout 49d35a2
cmake -S . -B build/linux -DCMAKE_BUILD_TYPE=Release
cmake --build build/linux --config Release
build/linux/rayomd --bench tester.md benchmark-output/tester-warm/run-1 200 modern normal

Windows:

git checkout 49d35a2
cmake -S . -B build/windows -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release
cmake --build build/windows --config Release
build/windows/rayomd.exe --bench tester.md benchmark-output/tester-warm/run-1 1000 modern normal

Each command reports one process-level avg_ms. Repeat it in new processes and use the median. For a before/after check, build 315b404 and 49d35a2 with the same compiler, flags, filesystem location, renderer options, and iteration count, then interleave their runs.

Clone this wiki locally