Fork me on GitHub
Performance

Measured, not claimed.

Every number below is real, best-of-5 wall-clock from the cross-runtime suite — no estimates, no extrapolation. Where a runtime can't load a module it shows n/a. rbgo beats MRI on 9 of these standard-library modules outright (and is honest about the two where it loses).

A · Per-module benchmarks

Best-of-5 wall-clock, ms. Apple M-series · ruby 4.0.5 +PRISM (MRI & --yjit) · jruby 10.1.0.0 (OpenJDK 25) · truffleruby 34.0.1 (GraalVM CE Native) · rbgo @ 2026-06-30. Lower is better; ×MRI = rbgo ÷ MRI (<1 means rbgo is faster). Rows where rbgo beats MRI are marked ✓.

ModulerbgoMRIYJITJRubyTruffle×MRI
set2220220220124042010.1×
prime50305012301901.7×
matrix20505012302100.40×
complex10080701100901.25×
rational90504010901001.8×
cmath406060n/an/a0.67×
tsort80908012202500.89×
abbrev29022018013303801.32×
did-you-mean40145040026604800.03×
prettyprint80907013802200.89×
scanf150570550n/an/a0.26×
unicode-normalize11037037013803200.30×
cgi606060109019501.00×
zlib360606012203806.0×
ipaddr2101109016003501.9×
pathname26044042018907400.59×
rexml20510310285014900.04×

cmath / scanf are not bundled in JRuby 10.1 / TruffleRuby 34 (LoadError) → n/a. rbgo beats MRI on did-you-mean (~33×), rexml (~25×), scanf (~4×), unicode-normalize (~3×), matrix (2.5×), pathname (1.7×), cmath (1.5×) and tsort / prettyprint (~1.1×). It honestly loses two: zlib 6× (pure-Go flate vs C-zlib) and set 10× (per-element interpreter dispatch).

B · Runtime micro-benchmarks

rbgo's ahead-of-time backend compiles integer-bound methods to unboxed Go kernels. Measured on this project's own micro-benchmarks (bench/loop.rb, bench/fib.rb) on darwin/arm64, best-of-N whole-process wall time, against MRI 4.0.5 with YJIT enabled:

8.7×

AOT vs MRI+YJIT

On the tight-loop benchmark, rbgo+AOT ran 8.7× faster than MRI+YJIT (43 ms vs 373 ms). On recursive fib(35) the margin is 2.0× (56 ms vs 110 ms) — recursion keeps the call overhead the loop case removes. Only methods the AOT backend can lower benefit at all.

245k → 1

Small-integer interning

Interned small integers drop a small-int loop from ~245,000 allocations to 1 — the hot integers are shared, immutable singletons.

~14%

Frame recycling

Capture-tracked frame recycling is ≈14% faster on fib; frames are reused unless a closure captures them. Plus inline method caches on every call site.

C · Application conformance & performance

The pure-Go front-end and runtime, tested against real-world Ruby applications — parse, parse + compile, and end-to-end execution.

Runtime conformance — ruby/spec

22,488 examples pass in ruby/spec's language/ + core/ suites, measured 2026-09-26 on main (3e8e3cc). Three independent runs — two through the ratchet at different timeouts, one through a separate sweep — reported the same total.

  • CI gates file by file, not on a total: no spec file may pass fewer examples than its recorded row, and none may stop loading. The sum of those rows is 23,511 at rbgo v0.3.0 (2026-10-12) — it is what CI guarantees, while the measured total above is what one dated run did. This replaced a single shrink-only floor of 22,475, which needed a margin wider than the largest spec file and so could not see a regression smaller than that.
  • Only language/ and core/ are swept. ruby/spec's library/, optional/ and security/ trees are not run at all, so this figure is not a percentage of Ruby, and most of the standard library sits outside it.
  • Of the examples that ran, 93.3% pass (22,488 of 24,116); 477 more are skipped because our shim stubs the matcher they need, and 10 of 2,206 spec files produce no result. Skips and unreadable files sit outside the ratio entirely.
  • The guarantee has climbed from a floor of 6,000 on 2026-08-03 to a per-file baseline summing 23,511. Two earlier jumps were fixes to the measurement — the mspec shim, and a parser upgrade that made 13 previously-unparseable spec files visible — which are gains in what the measurement can see, not in what the VM can do.

Front-end conformance (measured 2026-06-27)

~100% of all valid Ruby parsed across Rails + Puppet — 99.96% of files; the 2 misses are syntax-error fixtures MRI itself rejects. Not re-measured since.

  • Parse + compile: Rails 99.82% / Puppet 100%, with 0 over-permissive.
  • RuboCop 99.7%.
  • Sinatra / Jekyll / Thor / Kramdown / dry-struct 100%.
  • RSpec DSL 10/10.

Runtime — the real puppet apply CLI

The genuine puppet apply CLI runs end-to-end on a CGO=0 rbgo:

  • Puppet 8.11.0 boots — all pure-Ruby gem deps on the path.
  • The real CommandLine → Apply path converges notify / file / exec resources.
  • exec runs via pure-Go process exec with onlyif / unless / creates / path guards.
  • Emits real Puppet output and exits 0, with the YAML run report round-tripped.

Per-module cross-runtime application benchmarks beyond the front-end conformance suite are in progress.

← Back to overview