Gem Version Build

Require Profiler

Require Profiler is a tool for profiling Ruby's code loading—Kernel#require, Kernel#require_relative, and Kernel#load. It captures the call tree, measures how long each file takes to load, and can export the results as a Speedscope-compatible JSON profile.

It's built on top of Require Hooks, so it works anywhere Require Hooks does (MRI/JRuby/TruffleRuby).

Sponsored by Evil Martians

Installation

Add to your Gemfile:

gem "require-profiler"

Supported Ruby versions

  • Ruby (MRI) >= 3.1

Usage

Wrap the code you want to profile with RequireProfiler.start and RequireProfiler.stop:

require "require_profiler"

RequireProfiler.start(output: "path/to/profile.txt")
require "my_app"
RequireProfiler.stop

Only require/load calls that happen between .start and .stop are captured. Put .start as early as possible (e.g., at the top of config/boot.rb or an entry-point script) to see the full loading tree.

RequireProfiler.stop returns a totals hash: {count: <number of files loaded>, time: <seconds>}.

Scoping via patterns

Use patterns: and exclude_patterns: to limit what gets profiled. Both accept globs as recognized by File.fnmatch and are passed through to Require Hooks:

RequireProfiler.start(
  patterns: ["#{Dir.pwd}/app/**/*.rb", "#{Dir.pwd}/lib/**/*.rb"],
  exclude_patterns: ["*/vendor/*"]
)

Output

RequireProfiler.start accepts the following keyword arguments:

  • output:$stdout (default), any IO-like object, or a file path (string).
  • format::text (default), :call_stack, or :json. When output: is a file path with a .json extension, the JSON format is picked automatically.
  • patterns: / exclude_patterns: — see above.

Output formats

Text (default)

A human-readable indented tree, one line per file, with self+children duration in milliseconds:

lib/my_app.rb — 42.137ms
  lib/my_app/config.rb — 3.211ms
  lib/my_app/router.rb — 12.004ms
    lib/my_app/routes.rb — 9.882ms

Paths are printed relative to Dir.pwd, Gem.dir, or Bundler.bundle_path when they match—so vendored gem loads stay readable.

Collapsed call stacks

RequireProfiler.start(output: "tmp/require-profile.txt", format: :call_stack)

Emits one line per stack in Brendan Gregg's collapsed format with per-frame self time in milliseconds. Pipe it to flamegraph.pl, inferno, or any tool that consumes folded stacks.

JSON / Speedscope

RequireProfiler.start(output: "tmp/require-profile.json")
# or:
RequireProfiler.start(output: io, format: :json)

Emits a profile that conforms to the Speedscope file format schema.

Note: Writing JSON straight to $stdout is not supported.

Using with Speedscope

Speedscope is an interactive flamegraph viewer that runs entirely in your browser (nothing is uploaded—the file is parsed locally).

  1. Generate a JSON profile:
   RequireProfiler.start(output: "tmp/require-profile.json")
   require "my_app"
   RequireProfiler.stop
  1. Open https://www.speedscope.app/ and drag-and-drop tmp/require-profile.json onto the page (or use the "Browse" button).

  2. Switch to the Left Heavy view to see which require chains cost the most time, and use Sandwich view to find individual files that show up repeatedly.

Prefer to stay local? Install the CLI and it will open a local viewer for you:

npm install -g speedscope
speedscope tmp/require-profile.json

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/palkan/require-profiler.

Credits

This gem is generated via newgem template by @palkan.

License

The gem is available as open source under the terms of the MIT License.