Ruby Logo

Benchmarking & Profiling

Measure Ruby performance with benchmark-ips, ruby-prof, and stack sampling to locate hotspots.

Home Ruby Benchmarking & Profiling

Benchmarking & Profiling Ruby Code

Performance work starts with measurement. Pair micro-benchmarks with system-level profiling so we optimise the right code, under the right conditions, and prove the results with data.

Benchmarking pipeline

  1. Baseline: capture current timings (APM, logs, queue latency). Note Ruby version, CPU model, and environment.
  2. Micro-benchmark: isolate the hot function with Benchmark::IPS or benchmark-driver; keep inputs realistic.
  3. Profile: record stack samples (stackprof, rbspy) or allocations (ruby-prof, memory_profiler) to trace hotspots.
  4. Experiment: change one variable at a time—algorithm, data structure, caching, or concurrency primitive.
  5. Validate: compare deltas, run regression tests, and document assumptions/risks in the PR.

Toolkit overview

Tool Primary use Command / notes
Benchmark::IPS Compare Ruby implementations (IPS, stddev, iterations) `bundle exec ruby script/bench/lesson_order.rb`
benchmark-driver Run parameterised benchmarks, compare Ruby versions `bundle exec benchmark-driver bench.yml --rbenv 3.2.2:3.3.0-preview`
ruby-prof Method-level CPU/alloc analysis `bundle exec ruby script/profile_recommendations.rb`
stackprof Sampling flamegraphs (CPU or wall time) `STACKPROF=tmp/stackprof.dump bundle exec rails s` + `stackprof --flamegraph`
rbspy Attach to live processes (Sidekiq, Puma) `rbspy record --pid --duration 60 --format flamegraph`
perf/eBPF (advanced) Kernel-level profiling to rule out syscalls or network stack issues Run from host: `sudo perf record -g --pid `; use only in staging/low-traffic windows

Example: optimizing recommendation scoring

require 'benchmark/ips' require_relative '../app/services/recommendations/score' data = JSON.parse(File.read('tmp/lesson_scores.json')) Benchmark.ips do |x| x.report('naive score') { Recommendations::Score.naive(data) } x.report('vectorised score') { Recommendations::Score.vectorised(data) } x.compare! end

Bake these scripts into script/benchmark/ and link them in the PR so reviewers and QA can reproduce numbers locally.

Advanced tips

  • Pin Ruby version and gemset to avoid noisy comparisons; performance varies across patch releases.
  • For multi-threaded code, disable CPU frequency scaling (performance governor) on local machines to reduce jitter.
  • Integrate with CI (GitHub Actions artifacts) to keep historical benchmark charts for critical paths (render pipeline, lesson scoring).
  • Augment Ruby profiling with system stats (pidstat, perf, eBPF) when investigating kernel-level bottlenecks (syscalls, network).

Quick Navigation

Related Topics

Video Tutorial

Watch and learn benchmarking & profiling

Pro Tip: After reading through the content above, watch this video to reinforce your understanding and see the concepts in action!