Benchmarks
All figures below are from an Apple M1 (4 performance + 4 efficiency cores). Treat them as a shape, not a spec: they move with hardware, style complexity, and network.
Graph evaluation, single-threaded
Section titled “Graph evaluation, single-threaded”A Protomaps basemap MapLibre style, converted with ezu translate, rendered at
512 px — pure graph evaluation, with MVT fetch and decode excluded:
cargo run --release -p ezu-compare -- \ --style crates/ezu-compare/samples/protomaps-basemap.json \ --tiles 12/3637/1613,13/7275/3225,14/14550/6452,15/29101/12904 \ --bench --repeat 5# eval: z12 ~22 ms, z13 ~30 ms, z14 ~19 ms, z15 ~13 msRoughly 13–30 ms per tile. Note that it is not monotonic in zoom: z13 is the most expensive here because that is where this style draws the most — feature count, not zoom level, is what costs.
End to end, parallel
Section titled “End to end, parallel”A 251-tile z13–z14 pyramid via ezu tiles, parallel evaluator across all 8 cores:
~9 s wall, ~37 ms/tile amortized — including HTTP tile fetch, MVT decode, and PNG encode. At this render cost those three dominate the per-tile wall clock, which is worth internalising: for vector-ish styles you are often optimising I/O, not rendering.
Parallel evaluator, painterly style
Section titled “Parallel evaluator, painterly style”The parallel evaluator buckets nodes by longest-path depth and fans each bucket across Rayon. On a six-node-wide watercolour graph, four Tokyo tiles go from 6.3 s to 1.3 s.
The win scales with graph width, not node count. A deep, narrow graph gets almost nothing from it.
A real theme, with labels
Section titled “A real theme, with labels”The style above is a converted basemap with no text. A fuller one —
protomaps-light,
68 layers, 11 of them symbol, its own glyph endpoint — expands to a 149-node
graph, and evaluates in 42–105 ms per tile across z12–z15 on the same
machine:
cargo run --release -p ezu-compare -- \ --style https://papers.reearth.land/styles/protomaps-light/style.json \ --tiles 14/14550/6452,12/3637/1613,15/29101/12904 --bench --repeat 3# eval: z14 ~105 ms, z12 ~105 ms, z15 ~42 msWhere that time goes is worth knowing, because it is not where people expect:
| op | share of eval |
|---|---|
stroke (123 nodes) |
69.5 % |
stack |
12.4 % |
fill-solid |
9.8 % |
text-labels + text-draw + label-placement |
5.2 % |
Text is cheap here; road casings are the bill. A style with dozens of line
layers pays for them, whatever its labels are doing.
What the numbers do not say
Section titled “What the numbers do not say”- Painterly styles cost more than translated basemaps.
fill-dabsandlineplace real dabs along real geometry; a dab-heavy style at z15 over dense polygons is the most expensive thing you can ask for. Do not plan capacity for a watercolour style from a basemap benchmark. - The cache is warm within a style, cold between styles. A pyramid run reuses work across tiles; a benchmark that renders one tile per process does not, and will look worse than production.
--repeatmeasures a warm cache by design. Cold-start latency — what a tile server serving an uncached tile actually sees — is the first iteration, not the average.
Reproducing
Section titled “Reproducing”# Evaluation only, with repeatscargo run --release -p ezu-compare -- --style STYLE --tiles Z/X/Y[,…] --bench --repeat 5
# End to end over a pyramidtime ezu tiles --style STYLE --bbox W,S,E,N --min-zoom 13 --max-zoom 14 --out /tmp/pyr
# Per-node breakdown: op, cache hit/miss, output shape, durationezu --verbose tile --style STYLE --tile Z/X/Y --out /tmp/t.png--verbose is the one to reach for first when a style is slower than you expect.
A node missing the cache on every tile — when you thought it was shared — almost
always means an asset hash that changes when it should not.
WebAssembly
Section titled “WebAssembly”The ezu-wasm README carries browser benchmarks for the scalar, SIMD, and threads
builds. Expect wasm to be slower than native, SIMD to help the image-processing
ops most, and the threads build to behave like the native parallel evaluator when
the page is cross-origin isolated. See
use in the browser.
Map renders on this site are made fromOpenStreetMap data viaProtomaps (© OpenStreetMap contributors), elevation from Re:Earth Terrain,Mapterhorn andEGM2008 (NGA), and aerial imagery from GSI Japan(© 国土地理院). The painterly styles use CC0 brushes byDavid Revoy.