Have you ever wanted to know what functions your Ruby program is calling? rbspy
can tell you!
rbspy
lets you profile running Ruby processes. It's the only Ruby profiler that can profile
arbitrary Ruby processes that are already running.
It's currently alpha software, and is being actively developed. Please report bugs!
rbspy only runs on Linux*. Mac support is planned.
* kernel version 3.2+ required. For Ubuntu, this means Ubuntu 12.04 or newer.- Download recent release of
rbspy
from the github releases page - Unpack it
- Move the
rbspy
binary to/usr/local/bin
rbspy currently has 2 features: snapshot and record.
Snapshot
Snapshot takes a single stack trace from the specified process, prints it, and exits. This is useful if you have a stuck Ruby program and just want to know what it's doing right now. Must be run as root.
sudo rbspy snapshot --pid $PID
Record
Record records stack traces from your process and generates a flamegraph. You can either give it the PID of an already-running process to record, or ask it to execute and record a new Ruby process.
This is useful when you want to know what functions your program is spending most of its time in.
sudo rbspy record --pid $PID
# recording a subprocess doesn't require root access
rbspy record ruby myprogram.rb
When recording, rbspy will by default save data to ~/.cache/rbspy/records
. You can also specify an
output file with --file
.
rbspy uses Brendan Gregg's flamegraph script to generate flamegraphs!
A flamegraph is a way to visualize profiling data from a process. Here's a flamegraph of
Jekyll building a blog recorded with rbspy record jekyll build
.
You can see it spends about 50% of its time building the site (on the left, above execute
) and
about 50% of its time loading requires (on the right, above require
).
rbspy does not stop your Ruby processes to collect information about what it's doing. This is for both performance reasons and general production-safety reasons -- only reading from your Ruby processes and not altering them in any way means that rbspy is safer to run on production Ruby applications. rbspy does not use ptrace or signals.
This means that sometimes rbspy will try to read a stack trace out of a Ruby process, there will be
a race, and the memory of that process will temporarily be in an invalid state which means rbspy
can't collect its stack. rbspy record
handles this by just dropping that stack trace and trying
again later, and reports the total number of dropped stack traces when it's done.
A typical error message here is something like "Dropped 13/3700 stack traces because of errors". If you're seeing high error rates (more than 1/100 or so), please create an issue.
Contributions in any of these areas would be very welcome.
- Mac support
- BSD/Windows support
- Profile multiple threads
- Profile C extensions (rbspy will simply ignore any calls into C extensions)
- Profile processes running in containers
A major goal for this project is to get more maintainers and contributors. Pull requests that improve usability, fix bugs, or help rbspy support more operating systems are very welcome. If you have questions about contributing come chat on gitter.
If you're not a very experienced Rust programmer, you're very welcome to contribute. A major reason rbspy is written in Rust is that Rust is more approachable than C/C++. https://www.rust-lang.org/en-US/ has great resources for learning Rust.
- Install cargo from crates.io
cargo build
to buildcargo test
to test
The build artifacts will end up in target/debug
- Julia Evans
- Kamal Marhubi