Skip to content

Commit

Permalink
Add isolate-check-environment script
Browse files Browse the repository at this point in the history
This scripts automates the checking or setting of some kernel knobs that
can lead to wider run-time variability.
  • Loading branch information
bblackham committed Aug 2, 2017
1 parent 5965056 commit 44cd236
Show file tree
Hide file tree
Showing 3 changed files with 231 additions and 4 deletions.
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Makefile for Isolate
# (c) 2015--2016 Martin Mares <[email protected]>
# (c) 2017 Bernard Blackham <[email protected]>

all: isolate isolate.1 isolate.1.html
all: isolate isolate.1 isolate.1.html isolate-check-environment

CC=gcc
CFLAGS=-std=gnu99 -Wall -Wextra -Wno-parentheses -Wno-unused-result -Wno-missing-field-initializers -Wstrict-prototypes -Wmissing-prototypes -D_GNU_SOURCE
Expand Down Expand Up @@ -44,8 +45,8 @@ clean:
rm -f isolate isolate.1 isolate.1.html
rm -f docbook-xsl.css

install: isolate
install -D $< $(BINDIR)/$<
install: isolate isolate-check-environment
install -D $^ $(BINDIR)
chmod u+s $(BINDIR)/$<
install -d $(BOXDIR)
install -m 644 -D default.cf $(CONFIG)
Expand Down
225 changes: 225 additions & 0 deletions isolate-check-environment
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
#!/bin/sh
#
# Identifies potential sources issues when using isolate.
#
# (c) 2017 Bernard Blackham <[email protected]>
#

usage() {
cat <<EOT >&2
Usage: $0 [-q|--quiet] [-e|--execute]
Use this script to identify sources of run-time variability and other issues on
Linux machines which may affect isolate. If --execute is not specified, the
recommended actions are written to stdout as an executable shell script,
otherwise, using --execute will attempt to make changes to make the system
behave more deterministically. The changes performed by --execute persist only
until a reboot. To persist across reboots, the standard output from this script
should be added to /etc/rc.local or some other script that is run on each boot.
Alternately, you could add the following line to /etc/rc.local to automatically
apply these changes on boot, but use this with caution as not all issues can
be resolved in this way.
isolate-check-environment --quiet --execute
The exit status of this script will be 0 if all checks pass, or 1 if some
checks have failed.
Note that there are more strategies to reduce run-time variability further.
See the man page of isolate for details under REPRODUCIBILITY.
EOT
exit 2
}

# Parse options.
args=$(getopt -o "ehq" --long "execute,help,quiet" -- "$@") || usage
eval set -- "$args"
quiet=
execute=
while : ; do
case "$1" in
-q|--quiet) quiet=1 ; shift ;;
-e|--execute) execute=1 ; shift ;;
-h|--help) usage ;;
--) shift ; break ;;
*) usage ;;
esac
done
[ -n "$*" ] && usage

# Some helper boilerplate machinery.
exit_status=0
red=$(tput setaf 9)
green=$(tput setaf 10)
yellow=$(tput setaf 11)
normal=$(tput sgr0)

# Return true (0) if we are being quiet.
quiet() {
[ -n "$quiet" ]
}

# Print all arguments to stderr as warning.
warn() {
quiet || echo WARNING: "$*" >&2
}

# Print first argument to stderr as warning, and second argument to stdout as
# the recommended remedial action, or execute if --execute is given.
action() {
quiet || warn "$1"
if [ -n "$execute" ] ; then
quiet || echo "+ $2"
sh -c "$2"
else
quiet || echo $2
fi
}

print_start_check() {
quiet && return
print_check_status=1
echo -n "Checking for $@ ... " >&2
}

print_fail() {
exit_status=1
quiet && return
[ -n "$print_check_status" ] && echo "${red}FAIL${normal}" >&2
print_check_status=
}

print_dubious() {
exit_status=1
quiet && return
[ -n "$print_check_status" ] && echo "${yellow}CAUTION${normal}" >&2
print_check_status=
}

print_skipped() {
quiet && return
[ -n "$print_check_status" ] && echo "SKIPPED (not detected)" >&2
print_check_status=
}

print_finish() {
quiet && return
[ -n "$print_check_status" ] && echo "${green}PASS${normal}" >&2
print_check_status=
}

# Check that cgroups are enabled.
cgroup_check() {
local cgroup=$1
print_start_check "cgroup support for $cgroup"
if ! test -f "/sys/fs/cgroup/$cgroup/tasks" ; then
print_dubious
warn "the $cgroup is not present. isolate --cg cannot be used."
fi
print_finish
}
cgroup_check memory
cgroup_check cpuacct
cgroup_check cpuset

# Check that swap is either disabled or accounted for.
swap_check() {
print_start_check "swap"
# If swap is disabled, there is nothing to worry about.
local swaps
swaps=$(swapon --noheadings)
if [ -n "$swaps" ] ; then
# Swap is enabled. We had better have the memsw support in the memory
# cgroup.
if ! test -f "/sys/fs/cgroup/memory/memory.memsw.usage_in_bytes" ; then
print_fail
action \
"swap is enabled, but swap accounting is not. isolate will not be able to enforce memory limits." \
"swapoff -a"
else
print_dubious
warn "swap is enabled, and although accounted for, may still give run-time variability under memory pressure."
fi
fi
print_finish
}
swap_check

# Check that CPU frequency scaling is disabled.
cpufreq_check() {
print_start_check "CPU frequency scaling"
local any policy
anycpus=
# Ensure cpufreq governor is set to performance on all CPUs
find /sys/devices/system/cpu/cpufreq/ -name scaling_governor |
while read cpufreq_file ; do
policy=$(cat $i)
if [ "$policy" != "performance" ] ; then
print_fail
action \
"cpufreq governor set to '$policy', but 'performance' would be better" \
"echo performance > $cpufreq_file"
fi
anycpus=1
done
[ -z "$anycpus" ] && print_skipped
print_finish
}
cpufreq_check

# Check that address space layout randomisation is disabled.
aslr_check() {
print_start_check "kernel address space randomisation"
local val
if val=$(cat /proc/sys/kernel/randomize_va_space 2>/dev/null) ; then
if [ "$val" -ne 0 ] ; then
print_fail
action \
"address space randomisation is enabled." \
"echo 0 > /proc/sys/kernel/randomize_va_space"
fi
else
print_skipped
fi
print_finish
}
aslr_check

# Check that transparent huge-pages are disabled, as this leads to
# non-determinism depending on whether the kernel can allocate 2 MiB pages or
# not.
thp_check() {
print_start_check "transparent hugepage support"
local val
if val=$(cat /sys/kernel/mm/transparent_hugepage/enabled 2>/dev/null) ; then
case $val in
*'[never]'*) ;;
*) print_fail
action \
"transparent hugepages are enabled." \
"echo never > /sys/kernel/mm/transparent_hugepage/enabled" ;;
esac
fi
if val=$(cat /sys/kernel/mm/transparent_hugepage/defrag 2>/dev/null) ; then
case $val in
*'[never]'*) ;;
*) print_fail
action \
"transparent hugepage defrag is enabled." \
"echo never > /sys/kernel/mm/transparent_hugepage/defrag" ;;
esac
fi
if val=$(cat /sys/kernel/mm/transparent_hugepage/khugepaged/defrag 2>/dev/null) ; then
if [ "$val" -ne 0 ] ; then
print_fail
action \
"khugepaged defrag is enabled." \
"echo 0 > /sys/kernel/mm/transparent_hugepage/khugepaged/defrag"
fi
fi
print_finish
}
thp_check


exit $exit_status
3 changes: 2 additions & 1 deletion isolate.1.txt
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,8 @@ REPRODUCIBILITY
---------------

The reproducibility of results can be improved by tuning some kernel
parameters:
parameters, listed below. Some of these parameters can be checked using the
program isolate-check-environment.

* Disable address space randomization: +sysctl kernel.randomize_va_space=0+.
Address space randomization can affect timing, memory usage, and program
Expand Down

0 comments on commit 44cd236

Please sign in to comment.