Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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

This comment has been minimized.

Copy link

@sirupsen 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