Skip to content

Instantly share code, notes, and snippets.

@kigster
Last active August 12, 2022 19:41
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save kigster/8ddebf9fddff25620e64d558dd4d56b7 to your computer and use it in GitHub Desktop.
Save kigster/8ddebf9fddff25620e64d558dd4d56b7 to your computer and use it in GitHub Desktop.
Detect if MRI Ruby is built with jemalloc library or not, download with `curl -fSL http://bit.ly/ruby-jemalloc-check > ruby-jemalloc-check.sh`
#!/usr/bin/env bash
# vi: ft=sh
#
# https://gist.github.com/kigster/8ddebf9fddff25620e64d558dd4d56b7
#
# © 2019-2022 Konstantin Gredeskoul, Inc., All rights reserved.
# MIT LICENSE
# ————————————————————————————————————————————————————————————————
# This script verifies that the ruby interpreter (either the one in
# the $PATH, or the one specified by the -r / --ruby option) is linked
# with jemalloc library for efficient memory utilization.
#
# It works well on Linux and Mac OSX.
#
# BACKGROUND
# ————————————————————————————————————————————————————————————————
# Ruby versions 2.5 and earlier had a simpler method, typically
# running the following command and expecting the output to
# contain something like '-ljemalloc -lm ... '
#
# ruby -r rbconfig -e "puts RbConfig.CONFIG['LIBS']"
#
# Unfortunately, this method no longer works with Ruby 2.6
# and later, nor did it ever work with Linux.
#
# For this reason, the following script is provided to verify
# if your Ruby is using jemalloc memory allocator or not.
#
# USAGE:
# curl -fSL http://bit.ly/ruby-jemalloc-check > ruby-jemalloc-check.sh
# chmod 755 ruby-jemalloc-check.sh
#
# ./ruby-jemalloc-check.sh --help
# ./ruby-jemalloc-check.sh -r /usr/bin/ruby
#
# ————————————————————————————————————————————————————————————————
set +e
export jm_option_ruby=$(command -v ruby 2>/dev/null)
export jm_option_quiet=false
export jm_action_detect=false
export jm_action_stats=false
export jm_action_help=false
export color_red="\e[1;31m"
export color_green="\e[1;32m"
export color_yellow="\e[1;33m"
export color_blue="\e[1;34m"
export clr="\e[0m"
function jm.printf() {
if "${jm_option_quiet}"; then
echo >/dev/null
else
printf "$@"
fi
}
# @description prints the info about current version of ruby
function jm.ruby.report() {
jm.printf "${color_blue}Ruby version being tested:\n → ${color_yellow}${jm_option_ruby} ${color_blue}$(jm.ruby.describe)${clr}\n"
}
# @description Prints ruby version under test
function jm.ruby.describe() {
${jm_option_ruby} -e 'puts "#{RUBY_VERSION} (#{RUBY_PLATFORM})"'
${jm_option_ruby} -e 'puts "#{RUBY_VERSION} (#{RUBY_PLATFORM})"'
}
# @description detects jemalloc or exits
function js.jemalloc.detect-or-exit() {
jm.jemalloc.detect-quiet || {
jm.printf "${color_red}ERROR: No jemalloc detected in ruby ${jm_option_ruby}${clr}\n"
exit 1
}
}
# @description prints jemalloc statistics if jemalloc is available
function jm.jemalloc.stats() {
js.jemalloc.detect-or-exit
MALLOC_CONF=stats_print:true ${jm_option_ruby} -e "exit" 2>&1 | less -S
}
# @description returns 0 if jemalloc was detected or 1 otherwise
function jm.jemalloc.detect-quiet() {
MALLOC_CONF=stats_print:true ${jm_option_ruby} -e "exit" 2>&1 | grep -q "jemalloc statistics"
}
# @description detects if jemalloc is linked and if so prints the info to output
function jm.jemalloc.detect-loud() {
jm.printf "${color_blue}Checking if ruby ${color_yellow}${jm_option_ruby}${color_blue} is linked with jemalloc... \n"
jm.printf "${color_yellow}$(jm.ruby.report)${clr}\n\n"
jm.jemalloc.detect-quiet
local code=$?
if [[ ${code} -eq 0 ]]; then
jm.printf " ✅ ${color_green} — jemalloc was detected.\n"
else
jm.printf " 🚫 ${color_red} — jemalloc was not detected.\n"
fi
jm.printf "${clr}\n"
return ${code}
}
# @description Prints the help screen and exits
function usage() {
jm.printf "
${color_green}USAGE:${clr}
${color_yellow}$(basename $0) [ options ]${clr}
${color_green}DESCRIPTION:${clr}
This script verifies that a given ruby binary is linked with jemalloc,
the optimized for defragmentation memory allocator, which is a drop-in
replacement for libc malloc.
The script has several actions:
- check if the ruby binary is linked with jemalloc (-j/--jemalloc)
- print jemalloc statistics if available (-s/--stats)
- print this help screen (-h/--help)
${color_green}ACTIONS:${clr}
-j/--jemalloc Check if the ruby binary is linked with jemalloc
-h/--help This page (also printed when no arguments are provided)
-s/--stats Print the jemalloc stats (when linked with jemalloc)
${color_green}OPTIONS:${clr}
-r/--ruby PATH Path to the ruby binary to check (defaults to the
first ruby found in the \$PATH)
-q/--quiet Do not print output, exit with 1 if no jemalloc, or 0
if jemalloc was found.
"
exit 0
}
if [[ -z $* ]]; then
usage
fi
# Parse additional flags
while :; do
case $1 in
-d | --detect)
shift
export jm_action_detect=true
;;
-s | --stats)
shift
export jm_action_stats=true
;;
-h | -\? | --help)
shift
export jm_action_help=true
;;
-q | --quiet)
shift
export jm_option_quiet=true
;;
-r | --ruby)
shift
if [[ -x $1 && $(basename $1) == "ruby" ]]; then
export jm_option_ruby="$1"
else
jm.printf "${color_red} Invalid ruby interpreter provided: $1${clr}\n"
exit 1
fi
shift
;;
--) # End of all options; anything after will be passed to the action function
shift
break
;;
*)
[[ -n $1 ]] && {
jm.printf "${color_red}ERROR: invalid option: $1${clr}\n"
exit 1
}
break
;;
esac
done
if ${jm_action_help}; then
usage
fi
jm.printf "${color_green}Using Ruby Binary: ${color_yelow}${jm_option_ruby}${clr}\n"
if ${jm_option_quiet}; then
jm.jemalloc.detect-quiet
exit $?
fi
if ${jm_action_detect}; then
jm.jemalloc.detect-loud
exit $?
fi
if ${jm_option_stats}; then
jm.jemalloc.stats
exit $?
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment