Skip to content

Instantly share code, notes, and snippets.

@gburd
Last active October 18, 2021 06:11
Show Gist options
  • Save gburd/4157112 to your computer and use it in GitHub Desktop.
Save gburd/4157112 to your computer and use it in GitHub Desktop.
Shell script to build a debug or valgrind enabled Erlang OTP release and other helpful notes.
#!/usr/bin/env bash
# Note: erlang depends on ncurses, openssl at a minimum
usage ()
{
echo "usage: $0 <release> <type>"
echo " release: R14B01|R14B02|R14B03|R14B04|R15B|R15B01|R15B02|R15B03|R16B|R16B01|R16B02"
echo " type: normal, opt, gcov, gprof, debug, valgrind, or lcnt"
}
CPU=`gcc -c -Q -march=native --help=target | grep march | awk '{print $2}'`
case $2 in
normal|opt|gcov|gprof|debug|valgrind|lcnt)
export ERL_VARIETY=$2
;;
*)
usage;
echo "Unsupported build type: \"$2\""
exit -1
esac
case $1 in
R14B01|R14B02|R14B03|R14B04|R15B|R15B01|R15B02|R15B03|R16B|R16B01|R16B02)
echo "Goal: build a $2 version of Erlang OTP release $1 for $CPU"
export ERL_VERSION=`echo $1 | tr '[A-Z]' '[a-z]'`
export ERL_TAG=$1
echo " installed in /opt/erlang/${ERL_VARIETY}/${ERL_VERSION}"
echo " source /opt/erlang/${ERL_VARIETY}/${ERL_VERSION}/activate to use it."
;;
*)
usage;
echo "Unsupported release $1"
exit -1
esac
export ERL_TOP=`pwd`
do_git ()
{
echo "Cloning Erlang/OTP..."
git clone git://github.com/erlang/otp.git
(shopt -s dotglob nullglob && mv otp/* . && rmdir otp)
git checkout refs/tags/OTP_${ERL_TAG} || exit -1
echo -n "On ref/tags/"
git describe --tags
echo "done"
}
do_clean ()
{
echo -n "Cleaning..."
make -j clean 2>&1 > /dev/null && \
./otp_build remove_prebuilt_files 2>&1 > /dev/null
echo "done"
}
do_configure ()
{
echo "Configuring..."
[ -f configure ] || ./otp_build autoconf 2>&1 > /dev/null
CFLAGS="-Og -g -march=native -mtune=native" ./otp_build configure --disable-hipe --enable-smp-support --enable-thread --enable-kernel-poll --prefix=/opt/erlang/${ERL_VARIETY}/${ERL_VERSION}
echo "done"
}
do_build ()
{
echo "Building..."
if [ ! `wx-config --help`]; then
for lib in odbc wx debugger observer; do touch lib/${lib}/SKIP ; done
fi
make -j
if [ ${ERL_VARIETY} != "normal" ]; then
(cd erts/emulator && make -j ${ERL_VARIETY} FLAVOR=smp)
fi
echo "done"
}
do_install ()
{
echo "Building..."
make install
if [ ${ERL_VARIETY} != "normal" ]; then
export ERL_DEST_BIN=`dirname /opt/erlang/${ERL_VARIETY}/${ERL_VERSION}/lib/erlang/erts-*/bin/beam.smp`
cp $ERL_TOP/bin/x86_64*/beam.${ERL_VARIETY}.smp ${ERL_DEST_BIN}
mv ${ERL_DEST_BIN}/beam.smp ${ERL_DEST_BIN}/beam.smp-normal
ln ${ERL_DEST_BIN}/beam.${ERL_VARIETY}.smp ${ERL_DEST_BIN}/beam.smp
fi
echo "done"
}
[ -d .git ] || do_git;
[ -f Makefile ] && do_clean;
do_configure;
do_build;
do_install;
cat > /opt/erlang/${ERL_VARIETY}/${ERL_VERSION}/activate <<EOF
# credits to virtualenv
kerl_deactivate()
{
if [ -n "\$_KERL_SAVED_PATH" ]; then
PATH="\$_KERL_SAVED_PATH"
export PATH
unset _KERL_SAVED_PATH
fi
if [ -n "\$_KERL_SAVED_MANPATH" ]; then
MANPATH="\$_KERL_SAVED_MANPATH"
export MANPATH
unset _KERL_SAVED_MANPATH
fi
if [ -n "\$_KERL_SAVED_AGNER_BIN" ]; then
AGNER_BIN="\$_KERL_SAVED_AGNER_BIN"
export AGNER_BIN
unset _KERL_SAVED_AGNER_BIN
fi
if [ -n "\$_KERL_SAVED_AGNER_EXACT_PREFIX" ]; then
AGNER_EXACT_PREFIX="\$_KERL_SAVED_AGNER_EXACT_PREFIX"
export AGNER_EXACT_PREFIX
unset _KERL_SAVED_AGNER_EXACT_PREFIX
fi
if [ -n "\$_KERL_SAVED_REBAR_PLT_DIR" ]; then
REBAR_PLT_DIR="\$_KERL_SAVED_REBAR_PLT_DIR"
export REBAR_PLT_DIR
unset _KERL_SAVED_REBAR_PLT_DIR
fi
if [ -n "\$BASH" -o -n "\$ZSH_VERSION" ]; then
hash -r
fi
if [ ! "\$1" = "nondestructive" ]; then
unset -f kerl_deactivate
fi
}
kerl_deactivate nondestructive
_KERL_SAVED_PATH="\$PATH"
export _KERL_SAVED_PATH
_KERL_SAVED_MANPATH="\$MANPATH"
export _KERL_SAVED_MANPATH
_KERL_SAVED_AGNER_BIN="\$AGNER_BIN"
export _KERL_SAVED_AGNER_BIN
_KERL_SAVED_AGNER_EXACT_PREFIX="\$AGNER_EXACT_PREFIX"
export _KERL_SAVED_AGNER_EXACT_PREFIX
_KERL_SAVED_REBAR_PLT_DIR="\$REBAR_PLT_DIR"
export _KERL_SAVED_REBAR_PLT_DIR
PATH="__ROOTDIR__/bin:\$PATH"
export PATH
MANPATH="__ROOTDIR__/man:\$MANPATH"
export MANPATH
AGNER_BIN="__ROOTDIR__/bin"
export AGNER_BIN
AGNER_EXACT_PREFIX="__ROOTDIR__/lib"
export AGNER_EXACT_PREFIX
REBAR_PLT_DIR="__ROOTDIR__"
export REBAR_PLT_DIR
ROOTDIR=__ROOTDIR__/lib/erlang
BINDIR=__BINDIR__
EMU=beam
PROGNAME=erl
export EMU
export ROOTDIR
export BINDIR
export PROGNAME
if [ -n "\$BASH" -o -n "\$ZSH_VERSION" ]; then
hash -r
fi
EOF
perl -pi -e "s^__ROOTDIR__^/opt/erlang/${ERL_VARIETY}/${ERL_VERSION}^" /opt/erlang/${ERL_VARIETY}/${ERL_VERSION}/activate
perl -pi -e "s^__BINDIR__^${ERL_DEST_BIN}^" /opt/erlang/${ERL_VARIETY}/${ERL_VERSION}/activate
#!/bin/bash -x
#
# %CopyrightBegin%
#
# Copyright Ericsson AB 1996-2009. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
# compliance with the License. You should have received a copy of the
# Erlang Public License along with this software. If not, it can be
# retrieved online at http://www.erlang.org/.
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
#
# %CopyrightEnd%
#
export ROOTDIR="/opt/erlang/master/lib/erlang"
export BINDIR=$ROOTDIR/erts-5.11/bin
export EMU=beam
export PROGNAME=`echo $0 | sed 's/.*\///'`
export ERLANG=/opt/erlang/r17
export ERL_FLAGS=+Ktrue
export ERL_MAX_ETS_TABLES=8192
export ERL_ZFLAGS="+zdbbl 16384"
export LANG=en_US.UTF-8
export LC_COLLATE=C
export PATH=$PATH:/$BINDIR
export ERL_TOP=/home/gburd/eng/otp_R15B01
export VALGRIND_MISC_FLAGS="-v --leak-check=full --suppressions=$ERL_TOP/erts/emulator/valgrind/suppress.standard --show-possibly-lost=no"
: ${BEAM_VARIANT:=normal}
ARGS="-- -root $ROOTDIR -progname $PROGNAME -- "
case $BEAM_VARIANT in
eunit-valgrind)
exec valgrind --log-file=/tmp/valgrind-beam.smp.%p $BINDIR/beam.valgrind.smp "$ARGS -pa $PWD/.eunit -pz $PWD/deps/*/ebin -pz $PWD/ebin $@"
;;
valgrind)
exec valgrind --log-file=/tmp/valgrind-beam.smp.%p $BINDIR/beam.${BEAM_VARIANT}.smp $ARGS "$@"
;;
eunit-debug)
exec gdb -f -d /home/gburd/eng/otp_R15B01/erts/emulator --args $BINDIR/beam.debug.smp $ARGS -pa $PWD/.eunit -pz $PWD/deps/*/ebin -pz $PWD/ebin -exec 'cd(".eunit").' "$@"
;;
debug)
exec gdb -f -d /home/gburd/eng/otp_R15B01/erts/emulator --args $BINDIR/beam.${BEAM_VARIANT}.smp $ARGS "$@"
;;
strace)
exec strace $BINDIR/beam.normal.smp $ARGS $@
;;
*)
exec $BINDIR/beam.${BEAM_VARIANT}.smp $ARGS "$@"
esac
exit
ROOTDIR=/opt/erlang/debug/r15b01/lib/erlang
BINDIR=$ROOTDIR/erts-5.9.1/bin
EMU=beam
PROGNAME=`echo $0 | sed 's/.*\///'`
export EMU
export ROOTDIR
export BINDIR
export PROGNAME
exec $BINDIR/erlexec ${1+"$@"}
#!/bin/sh
# Use this to replace your dev/dev1/erts-5.9.1/bin/erl file, then run:
# bash ./erts-*/bin/erl console
# to start valgrind.
# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/ksh is.
if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then
POSIX_SHELL="true"
export POSIX_SHELL
exec /usr/bin/ksh $0 "$@"
fi
unset POSIX_SHELL # clear it so if we invoke other scripts, they run as ksh as well
## This script replaces the default "erl" in erts-VSN/bin. This is necessary
## as escript depends on erl and in turn, erl depends on having access to a
## bootscript (start.boot). Note that this script is ONLY invoked as a side-effect
## of running escript -- the embedded node bypasses erl and uses erlexec directly
## (as it should).
##
## Note that this script makes the assumption that there is a start_clean.boot
## file available in $ROOTDIR/release/VSN.
# Determine the abspath of where this script is executing from.
ERTS_BIN_DIR=$(cd ${0%/*} && pwd)
# Now determine the root directory -- this script runs from erts-VSN/bin,
# so we simply need to strip off two dirs from the end of the ERTS_BIN_DIR
# path.
export ROOTDIR=${ERTS_BIN_DIR%/*/*}
# Parse out release and erts info
START_ERL=`cat $ROOTDIR/releases/start_erl.data`
ERTS_VSN=${START_ERL% *}
APP_VSN=${START_ERL#* }
export BINDIR=${ROOTDIR}/erts-${ERTS_VSN}/bin
export EMU=beam
export PROGNAME=riak
export RIAK_VERSION=1.3.0
export ERL_TOP=${HOME}/eng/otp_R15B01
export VALGRIND_MISC_FLAGS="-v --leak-check=full --show-reachable=yes --track-origins=yes --suppressions=${ERL_TOP}/erts/emulator/valgrind/suppress.standard --show-possibly-lost=no"
export PATH=${PATH}/${BINDIR}
valgrind --log-file=${ROOTDIR}/valgrind_log-beam.smp.%p ${ROOTDIR}/erts-${ERTS_VSN}/bin/beam.smp -K true -A 64 -W w -- -root ${ROOTDIR} -progname riak -- -home ${HOME} -- -boot ${ROOTDIR}/releases/${RIAK_VERSION}/riak -embedded -config ${ROOTDIR}/etc/app.config -pa ${ROOTDIR}/lib/basho-patches -name dev1@127.0.0.1 -setcookie riak -- ${1+"$@"}

First use "build_otp.sh" to create a debug or valgrind installation.

build_otp.sh R15B01 valgrind

To run it:

$ $ERL_TOP/bin/cerl -valgrind

For your test, I just manually copied and pasted the code from the test into the erlang shell at this point. Valgrind did the rest. Note that the output is really messy because of the lack of carriage returns, but you can easily clean that up with perl.

To pass arguments to valgrind, use the VALGRIND_MISC_FLAGS env var:

$ VALGRIND_MISC_FLAGS='-v --leak-check=full' $ERL_TOP/bin/cerl -valgrind

Note also that building a debuggable erl is pretty much the same, as described in the web page.

[1] http://www.erlang.org/doc/installation_guide/INSTALL.html#How-to-Build-a-Debug-Enabled-Erlang-RunTime-System

@jonmeredith
Copy link

Here's my latest version of the wrapper script - update your paths.

https://gist.github.com/26f2c8711da5561696c6

@matthewvon
Copy link

Here is my shortcut for getting valgrind running with standard erlang build:

ROOTDIR=/home/mmaszewski/riak-1.3.0rc3/rel/riak
BINDIR=$ROOTDIR/erts-5.9.1/bin
EMU=beam
PROGNAME=riak
RELEASE=1.3.0rc3
export EMU
export ROOTDIR
export BINDIR
export PROGNAME

valgrind --log-file=$ROOTDIR/beam.smp.%p --leak-check=full $ROOTDIR/erts-5.9.1/bin/beam.smp -K true -A 64 -W w -- -root $ROOTDIR -progname riak -- -home /home/mmaszewski -- -boot $ROOTDIR/releases/1.3.0rc3/riak -embedded -config $ROOTDIR/etc/app.config -pa $ROOTDIR/lib/basho-patches -name riak@127.0.0.1 -setcookie riak -- console

Riak needs this adjustment from Jon to give things time to start:

One change to deps/riak_core/src/riak_core_stat_cache.erl, make L57 look like this.

register_app(App, {M, F, A}, TTL) ->
gen_server:call(?SERVER, {register, App, {M, F, A}, TTL}, infinity).

@matthewvon
Copy link

Note: the above script often fails if epmd is not already started. I typically start riak first without valgrind to get epmd running. Then I use the above script.

@jonmeredith
Copy link

For all you valgrinders our there... this suggestion came in from the erlang mailing list on 3/18- they also alluded to a patch to valgrind they use.

export VALGRIND_MISC_FLAGS="--suppressions=$ERL_TOP/erts/emulator/valgrind/suppress.standard --show-possibly-lost=no"

@gburd
Copy link
Author

gburd commented Apr 9, 2013

Thanks Jon, Matthew for the tips. I've created a shell script (build_otp.sh) that does most of the heavy lifting. I'll add in a bit to generate proper startup scripts in the install for gdb and valgrind at some point to finish it off.

@gburd
Copy link
Author

gburd commented Jun 6, 2013

from Sverker via: http://erlang.org/mailman/listinfo/erlang-questions

Run on debug emulator and hope for a better (earlier) crash.

# cd $ERL_TOP/erts/emulator
# make TYPE=debug smp plain
# $ERL_TOP/bin/cerl -debug

Another approach is to see if valgrind can detect any memory corruptions:

# cd $ERL_TOP/erts/emulator
# make TYPE=valgrind smp plain
# export VALGRIND_LOG_DIR=/write/valgrind/logs/here
# export VALGRIND_MISC_FLAGS="--suppressions=$ERL_TOP/erts/emulator/valgrind/suppress.standard --show-possibly-lost=no"
# $ERL_TOP/bin/cerl -valgrind

@gburd
Copy link
Author

gburd commented Jul 16, 2013

From Andrew:

Port = open_port({spawn_executable, "/usr/bin/valgrind"}, [{args, ["--tool=memcheck", "--leak-check=full", "--log-file=/tmp/valgrind", "./pam-port"]}, {packet, 4}, exit_status]).

@Vagabond
Copy link

The --fair-sched=yes flag really helps with SMP enabled erlang performance, it switches from pipe based communication to futex based communication. Pipes work everywhere, so they are the default:

http://valgrind.org/docs/manual/manual-core.html#manual-core.pthreads_perf_sched

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