Skip to content

Instantly share code, notes, and snippets.

@csfrancis
Last active May 24, 2016 17:15
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save csfrancis/5d088da436c987a3d61c to your computer and use it in GitHub Desktop.
Save csfrancis/5d088da436c987a3d61c to your computer and use it in GitHub Desktop.
Trace MRI method cache hit rate
#!/bin/bash
#
# Uses ftrace user probes to collect and display method cache statistics from a given
# MRI binary. The script sleeps for a specified amount of time to collect data from
# any MRI process that is running on the system.
#
# Usage: trace_rb_method_cache.sh <ruby_binary> <sleep_time>
#
# Caveats: Linux only, must be run as root, requires ftrace, only tested on Ruby 2.1.
#
TRACE_DIR=/sys/kernel/debug/tracing
[[ $(id -u) != "0" ]] && echo "this script must be run as root" && exit 1
[[ -z $1 || -z $2 || ! -f $1 ]] && echo "usage: $0 <ruby_binary> <sleep_time>" && exit 1
[[ ! -d $TRACE_DIR ]] && echo "$TRACE_DIR does not exist - do you have ftrace enabled?" && exit 1
RUBY_BIN=$1
SLEEP_TIME=$2
# attempt to find the hit and miss addresses
readarray MISS_HIT_ADDR < <(\
gdb --batch -ex 'disas rb_method_entry' $RUBY_BIN | \
awk '/rb_method_entry_get_without_cache/ && $3 == "jmpq" { miss_addr=$1 } /retq/ { hit_addr=$1 } END { if (hit_addr && miss_addr) printf "%s\n%s\n", miss_addr, hit_addr }' \
)
[ -z $MISS_HIT_ADDR] && echo "unable to determine cache hit/miss addresses from $RUBY_BIN" && exit 1
cd /sys/kernel/debug/tracing
# clear current tracer
echo 0 > tracing_on
echo > uprobe_events
# set up
echo nop > current_tracer
echo "p:rb_method_entry_miss $RUBY_BIN:${MISS_HIT_ADDR[0]}" >> uprobe_events
echo "p:rb_method_entry_hit $RUBY_BIN:${MISS_HIT_ADDR[1]}" >> uprobe_events
echo 1 > events/uprobes/enable
echo 1 > tracing_on
sleep $SLEEP_TIME
# report
echo 0 > tracing_on
echo 0 > events/uprobes/enable
cat uprobe_profile | awk '/miss/ { miss=$3; printf "%-10s %8d\n", "misses:", $3 } /hit/ { hit=$3; printf "%-10s %8d\n", "hits:", $3 } END { if (hit + miss > 0) printf "%-10s %7.2f%%\n", "hit rate:", (hit / (hit + miss)) * 100 }'
@sirupsen
Copy link

sirupsen commented Mar 6, 2015

There's a bug in this script. If write(2) fails to write to the ftrace VFS bash's echo won't fail, you should use /bin/echo instead. docs You should also use set -e, so it'll bail in that case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment