Benchmarks

Regenerated by rake bench before each release. Every chart has its table.

Three documents, two engines

Loading the latest numbers…

Prawn compresses its streams only when asked: it is measured with compress: true, at its lightest. Peak memory is the whole process’s maximum resident set size, Ruby included.

Why it is faster

Line breaking. Prawn rebuilds its regular expressions for every line it wraps. PrawnX compiles them once per text encoding, and keeps Prawn’s greedy algorithm, so lines break at the same places.

Numbers. Prawn formats every number it writes, then patches the string with a regular expression. PrawnX trims the formatted digits byte by byte.

Fonts. Prawn reads a TrueType file again for each document. PrawnX parses it once per process, freezes it, and shares it between documents and threads.

Weight. An object stream and a cross-reference stream pack what Prawn writes as plain objects and an xref table.

Reproduce

bundle install && BUNDLE_GEMFILE=oracle/Gemfile bundle install
bundle exec rake corpus:fetch  # Prawn's fonts and images, into corpus/cache
bundle exec rake bench         # BENCH_ITERATIONS=20 by default

bench/compare.rb renders each document of bench/documents/ with Prawn, from its own bundle in oracle/Gemfile, and with PrawnX, in 7 fresh YJIT processes per engine that take turns. Each process measures the median of 20 renders, the objects one render allocates, the file’s weight and its peak memory; the site shows the median of the 7 processes, as docs/benchmarks.json records it. Peak memory varies by about 20% from one process to the next, which one process cannot show. It writes docs/benchmarks.json, which every page of this site reads.