new file mode 100644
@@ -0,0 +1,22 @@
+Helper scripts to check and set CPU isolation and execution of application in
+isolated CPU(s)
+
+Files:
+isolate-cpu.sh isolates desired CPUs
+isolate-task.sh uses isolate-cpu.sh to isolate CPUs before running
+ the desired task. It also provides the possibility
+ to trace kernel disturbance on the isolated CPUs.
+
+isolate-cpu.sh checks the kernel configuration and the kernel cmdline to
+ determine if one or several CPUs are isolated, i.e. it checks for;
+ CONFIG_NO_HZ_FULL_ALL=y", and CONFIG_RCU_NOCB_CPU_ALL=y" in the kernel config
+ and rcu_nocbs,nohz_full in the kernel cmdline.
+ If the desired CPU(s) are not inte the above configuration, it warns but continues
+ to isolate the CPU(s) as much as possibe. The isolation is accomplished by
+ - Redirecting all IRQ's away from desired isolated cores
+ - Using cset (cpuset) to move all running processes and kernel threads
+ away from desired isolated cores
+
+isolate-task.sh uses isolate-cpu.sh to isolate desired CPU(s). In addition
+ it starts the supplied application on isolated CPU(s) and optionally traces
+ the isolated CPU(s) for kernel interaction.
new file mode 100755
@@ -0,0 +1,301 @@
+#!/bin/bash
+#
+# Copyright (c) 2017, Linaro Limited
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Script that passes command line arguments to odp_scheduling after,
+# optionally, isolating CPU
+#
+# This script isolates desired CPUS, i.e.
+# - Checks kernel cmdline and kernel config to determine
+# if the environment is optimised for isolated task execution;
+# - Moves CPU interrupts, kernel threads, tasks etc. away from the
+# targeted CPU.
+# *Note* CPU 0 cannot be isolated, i.e minimum 2 CPU's are required.
+
+
+print_usage() {
+cat <<-EOF
+$0 [-h] [-a] [-c <cpu list>] [-l] [-r] [-d]
+
+ Isolate CPU(s) from other tasks, kernel threads and IRQs
+ Args:
+ -h Print this message
+ -a Isolate all CPUs (except CPU 0)
+ -c List of CPUs to be isolated.
+ -l Show isolation proporties
+ -r Reset isolation
+ -d Show debug printouts
+
+ Examples:
+ Isolate all CPU(s) (except 0)
+ $0 -a
+
+ Isolate CPUs 1-3
+ $0 -c 1-3
+
+ Isolate CPUs 1 and 4
+ $0 -c 1,4
+EOF
+}
+
+dlog() {
+ [ $DEBUG ] && echo "$*"|| return 0
+}
+
+warn() {
+ printf "Warning: $*\n" >&2
+}
+
+die() {
+ printf "Error: $*\n" >&2
+ exit 1
+}
+
+get_cpu_array() {
+ [ $1 ] || die "$FUNCNAME internal error!"
+
+ local cpus=""
+ local oifs="$IFS"
+ local a=$1;
+
+ IFS=,
+ a=$a;
+ IFS="$oifs"
+
+ for str in $a; do
+ if [[ $str == *[\-]* ]]; then
+ str=$(echo $str| sed 's/-/../g')
+ str=$(eval echo {$str})
+ fi
+
+ if [ "$cpus" != "" ]; then
+ cpus="$cpus $str"
+ else
+ cpus=$str
+ fi
+ done
+
+ echo $cpus
+}
+
+##
+# Check kernel config and kernel cmdline for rcu callbacs and no_hz
+# *Note* isolcpu= kernel cmdline option isolates CPUs from SMP balancing
+# If needed, this can be done via
+# cpusets/user/cpuset.sched_load_balance
+##
+check_kernel_config() {
+
+ eval $(grep -o 'nohz_full=[^ ]*' /proc/cmdline)
+
+ local configs="/proc/config.gz /boot/config-$(uname -r) /boot/config "
+ dlog "Looking for Kernel configs; $configs "
+ for config in $configs; do
+ if [ -e $config ]; then
+ dlog "Kenel configuration found:$config"
+ break
+ fi
+ done
+
+ local all_except_0="1-$(($(getconf _NPROCESSORS_ONLN) - 1))"
+ if [ -r $config ]; then
+ nohz_full=$(zgrep "CONFIG_NO_HZ_FULL_ALL=y" $config 2>/dev/null) \
+ && nohz_full=$all_except_0
+ else
+ warn "Kernel config not found, only checking /proc/cmdline for"\
+ " isolation features."
+ fi
+
+ if ! [ "$nohz_full" ]; then
+ eval $(grep -o 'nohz_full=[^ ]*' /proc/cmdline)
+ fi
+
+ eval $(grep -o 'isolcpus=[^ ]*' /proc/cmdline)
+ if [ -z "$isolcpus" ]; then
+ warn "No CPU is isolated from kernel/user threads, isolcpus= is "\
+ "not set in kernel cmdline."
+ else
+ gbl_isolated_cpus=$isolcpus
+ export gbl_isolated_cpus
+ fi
+
+ if [ -z "$nohz_full" ]; then
+ warn "No CPU is isolated from kernel ticks, CONFIG_NO_HZ_FULL_ALL=y" \
+ " not set in kernel, nor nohz_full= set in kernel cmdline."
+ fi
+
+ for i in `pgrep rcu` ; do taskset -pc 0 $i >/dev/null; done
+
+ dlog "isolcpus:$isolcpus"
+ dlog "nohz_full:$nohz_full"
+ #dlog "rcu_nocbs:$rcu_nocbs"
+
+ return 0
+}
+
+cpus_valid() {
+ local cpus="$1"
+ local isolated=$2
+ local iarray=$(get_cpu_array $isolated)
+ local carray=$(get_cpu_array $cpus)
+
+ for c in $carray; do
+ for i in $iarray; do
+ if [ $i = $c ]; then
+ yah=$i
+ fi
+ done
+ [ -z "$yah" ] && return 1
+ done
+
+ return 0
+}
+
+check_prequesties() {
+ dlog "Checking prequesties; user is root, kernel has cpuset support,"\
+ " and commads; set, zgrep, getconf are available"
+ [ $UID -eq 0 ] || die "You need to be root!"
+ grep -q -s cpuset /proc/filesystems || die "Kernel does not support cpuset!"
+ which getconf > /dev/null 2>&1 || die "getconf command not found, please "\
+ "install getconf"
+ which cset > /dev/null 2>&1 || die "cset command not found, please "\
+ "install cpuset"
+ which zgrep > /dev/null 2>&1 || die "zgrep command not found, please "\
+ "install gzip"
+}
+
+shield_reset() {
+ cset shield -r >/dev/null 2>&1
+ sleep 0.1
+}
+
+shield_list() {
+ sets="/cpusets/*/"
+ for i in $sets ; do
+ if ! [ -e $i ]; then
+ continue
+ fi
+ printf "Domain %s cpus %s, running %d tasks\n" \
+ $(basename $i) $(cat $i/cpuset.cpus) $(cat $i/tasks | wc -l)
+ done
+}
+
+shield_cpus() {
+ local cpus="$1"
+
+ dlog "shielding CPU:s $cpus"
+
+ #Reset and create new shield
+ shield_reset
+ out=$(cset shield -c $cpus -k on 2>&1) || die "cset failed; $out"
+ # Delay the annoying vmstat timer far away
+ sysctl vm.stat_interval=120 >/dev/null
+
+ # Shutdown nmi watchdog as it uses perf events
+ sysctl -w kernel.watchdog=0 >/dev/null
+
+ # Pin the writeback workqueue to CPU0
+ #Fixme, check that /sys/bus is mounted?
+ echo 1 > /sys/bus/workqueue/devices/writeback/cpumask
+
+ # Disable load balancer.
+ echo 0 > /cpusets/user/cpuset.sched_load_balance
+
+ #Fixme, for now just send all irqs to core 0
+ for affinity in /proc/irq/*/smp_affinity; do
+ dlog "redirecting $affinity"
+ echo 1 > $affinity 2>/dev/null || dlog "$affinity redirection failed."
+ done
+
+
+ #Fixme, not implemented.
+ if [ $false ]; then
+ for affinity in /proc/irq/*/smp_affinity; do
+ local old_mask=$(cat $affinity)
+ local new_mask=$((oldmask ^ cpus ))
+ echo $new_mask > $affinity
+ done
+ fi
+}
+
+isolate_cpus() {
+
+ local cpus="$1"
+ local carray=$(get_cpu_array $cpus)
+
+ #cset allows CPU 0 to be isolated, we don't, since
+ #IRQs are routed to core 0
+ for c in $carray; do
+ if [ $c = 0 ]; then
+ die "Selected CPU 0 is not a valid CPU!"
+ fi
+ done
+ check_kernel_config
+
+ if [ "$gbl_isolated_cpus" ]; then
+ cpus_valid $cpus $gbl_isolated_cpus ||
+ warn "Selected CPU '$cpus' is not inside isolated cpus "\
+ "array:$gbl_isolated_cpus"
+ fi
+
+ dlog "Isolating CPUs $cpus"
+
+ shield_cpus $cpus
+
+ # Verify cores empty
+ for c in $(get_cpu_array $cpus); do
+ running=$(ps ax -o pid,psr,comm | \
+ awk -v cpu="$c" '{if($2==cpu){print $3}}')
+ if [ "$running" != "" ]; then
+ warn "Core $c not empty!"
+ dlog "; running tasks:\n$running\n"
+ fi
+ done
+}
+
+##
+# Script entry point
+##
+while getopts hdarlc: arguments
+do
+ case $arguments in
+ h)
+ print_usage
+ exit 0
+ ;;
+ d)
+ DEBUG=1
+ ;;
+ a)
+ ISOL_CPUS="1-$(($(getconf _NPROCESSORS_ONLN) - 1))"
+ ;;
+ r)
+ shield_reset
+ exit 0
+ ;;
+ l)
+ shield_list
+ exit 0
+ ;;
+ c)
+ [ "$ISOL_CPUS" ] || ISOL_CPUS=$OPTARG
+ ;;
+ *)
+ print_usage
+ exit 1
+ ;;
+ esac
+done
+#Remove all flags
+shift $((OPTIND-1))
+
+if ! [ $ISOL_CPUS ]; then
+ print_usage
+ exit 1
+fi
+
+check_prequesties
+isolate_cpus $ISOL_CPUS || die "isolate_cpus failed."
new file mode 100755
@@ -0,0 +1,162 @@
+#!/bin/bash
+#
+# Copyright (c) 2017, Linaro Limited
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+# Script that passes command line arguments to odp_scheduling after,
+# optionally, isolating CPU
+#
+# This script isolates a task on desired CPUs and
+# optionally creates background noise.
+
+print_usage() {
+ cat <<-EOF
+$0 [-c <cpu list>] [-d] [-h] [-n] <application arg1, arg2, ...>
+
+ Isolate CPU(s) from other tasks, kernel threads and IRQs
+ and run an application on isolated CPUs
+ Args:
+ -c List of CPUs to be isolated
+ -d Show debug printouts
+ -h Print this message
+ -n Create background noise (stress)
+
+All CPU's, except CPU 0, are isolated unless '-c' specified
+ Examples:
+ Isolate CPU 1,2 and run application in the same.
+ $0 -n -c 1,2 /some/path/application
+
+ Isolate all possible CPUs and run applicatipon
+ $0 /path/application
+EOF
+}
+
+dlog() {
+ [ $DEBUG ] && echo "$*"
+}
+
+die() {
+ printf "Error: $*\n" >&2
+ exit 1
+}
+
+trap cleanup INT EXIT
+
+cleanup(){
+ local pids=$(pgrep $MY_STRESS 2>/dev/null)
+ local base=$(dirname $0)
+
+ $base/isolate-cpu.sh -r
+ [ "$pids" != "" ] && kill -9 $pids >/dev/null 2>&1
+ kill -9 $CHILD >/dev/null 2>&1
+ rm -f $MY_STRESS_PATH
+}
+
+wait_app_started () {
+ local child=$1
+ local ltasks=0
+
+ while true; do
+ sleep 0.01
+ kill -0 $child 2>/dev/null || break
+ tasks=$(ls /proc/$child/task | wc -l)
+ [ $tasks -eq $ltasks ] && break
+ ltasks=$tasks
+ done
+ dlog "app started, # threads:$ltasks"
+}
+
+create_noise() {
+ local mpath=$1
+ local nr=$(grep processor /proc/cpuinfo | wc -l)
+
+ ln -sf $(which stress) $mpath || die "ln failed"
+ $mpath -c $nr 2>&1 >/dev/null &
+ disown $!
+}
+
+isolate_cpu(){
+ local cpus=$1
+ local base=$(dirname $0)
+ $base/isolate-cpu.sh -c $cpus || die "$0 failed"
+}
+
+run_application() {
+ local app="$1"
+
+ dlog "Starting application: $app"
+ $app&
+ child=$!
+ CHILD=$child
+
+ echo $child >> /cpusets/user/tasks
+ if [ $? -ne 0 ]; then
+ kill -9 $child
+ die "Failed to isolate task..."
+ fi
+
+ wait_app_started $child
+ wait $child
+}
+
+check_prequesties() {
+ local base=$(dirname $0)
+
+ [ -e $base/isolate-cpu.sh ] || die "$base/isolate-cpu.sh not found!"
+ [ $UID -eq 0 ] || die "You need to be root!"
+ which stress > /dev/null 2>&1 || die "stress command not found, "\
+ "please install stress"
+}
+
+##
+# Script entry point
+##
+
+ISOL_CPUS="1-$(($(getconf _NPROCESSORS_ONLN) - 1))"
+
+while getopts hdnc: arguments
+do
+ case $arguments in
+ h)
+ print_usage
+ exit 0
+ ;;
+ d)
+ DEBUG=1
+ ;;
+ n)
+ NOISE=1
+ ;;
+ c)
+ ISOL_CPUS=$OPTARG
+ ;;
+ *)
+ print_usage
+ exit 1
+ ;;
+ esac
+done
+# Remove all flags
+shift $((OPTIND-1))
+
+if ! [ "$1" ]; then
+ print_usage
+ exit 1
+fi
+
+#Isolate and optionally create noise
+command="$*"
+set -- $command
+
+check_prequesties
+
+MY_STRESS=stress-by-$$
+MY_STRESS_PATH=/tmp/$MY_STRESS
+
+isolate_cpu $ISOL_CPUS || die "isolate cpu failed!"
+[ -z $NOISE ] || create_noise $MY_STRESS_PATH
+run_application "$command"
+
+exit $?
new file mode 100755
@@ -0,0 +1,106 @@
+#!/bin/sh
+#
+# Copyright (c) 2017, Linaro Limited
+# All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+
+TEST_DIR="${TEST_DIR:-$(dirname $0)}"
+PERFORMANCE="$TEST_DIR/../../common_plat/performance"
+ISOL_DIR="${TEST_DIR}/../../../scripts/task-isolation"
+APPLICATION="${PERFORMANCE}/odp_pktio_perf${EXEEXT}"
+APPLICATION_ARGS=""
+APPLICATION_BASE="$(basename ${APPLICATION})"
+
+cleanup(){
+ pids=$(pgrep stress 2>/dev/null)
+ [ "$pids" != "" ] && kill -9 $pids
+}
+
+print_usage() {
+ cat <<-EOF
+$0 [-i] [-n] [-h] [<application> <application args>]
+
+ Run an application with or without isolation and background noise
+ Flags:
+ -h Print this message
+ -i Isolate CPU prior to running application.
+ -n Create background noise (stress)
+
+ <application> targeted application
+ <args> targeted application arguments
+ *Note* Default application is ${APPLICATION_BASE}
+
+ Example:
+ Isolate CPU, create background noise and run ${APPLICATION_BASE}:
+ $0 -i -n
+
+ Run ${APPLICATION_BASE}, w/o isolation but with background noise:
+ $0 -n
+
+ Run Myapp, without isolation but with background noise:
+ $0 -n Myapp -s ome args
+EOF
+}
+
+run() {
+ local isolate=$1
+ local noise=$2
+ if [ ${isolate} -eq 1 ]; then
+ [ ${noise} -eq 1 ] && noise_par="-n"
+ echo Running ${APPLICATION_BASE} with isolation and background noise
+ echo =====================================================
+ $ISOL_DIR/isolate-task.sh ${noise_par} ${APPLICATION} \
+ ${APPLICATION_ARGS} || exit 1
+ #reset isolation
+ $ISOL_DIR/isolate-cpu.sh -r
+ else
+ echo Running ${APPLICATION_BASE} without isolation
+ echo =====================================================
+ if [ ${noise} -eq 1 ]; then
+ local nr=$(grep processor /proc/cpuinfo | wc -l)
+ echo " Creating background noise..."
+ stress -c $nr 2>&1 >/dev/null &
+ fi
+ ${APPLICATION} ${APPLICATION_ARGS} || exit 2
+ fi
+}
+
+trap cleanup INT EXIT
+ISOLATE=0
+NOISE=0
+while getopts hni arguments
+do
+ case $arguments in
+ h)
+ print_usage
+ exit 0
+ ;;
+ n)
+ NOISE=1
+ if [ $(which stress > /dev/null 2>&1) ]; then
+ echo "'stress' not found, bailing" >&2
+ exit 3
+ fi
+ ;;
+ i)
+ ISOLATE=1
+ ;;
+ *)
+ print_usage
+ exit 1
+ ;;
+ esac
+done
+#Remove flags
+shift $((OPTIND-1))
+
+if [ $# -gt 0 ]; then
+ APPLICATION="$1"
+ shift
+fi
+[ $# -gt 0 ] && APPLICATION_ARGS=$*
+
+run ${ISOLATE} ${NOISE}
The wrapper script; odp_run_app_isolated.sh can be used to run ODP testcases in a isolated environment. Background noise can also be generated. Signed-off-by: Ravineet Singh <ravineet.singh@linaro.org> v2: moved task-isolation dir to odp/scripts, requested my Maxim Uvarov v3: fixed checkpatch.pl warnings v4: updated after review --- scripts/task-isolation/README | 22 ++ scripts/task-isolation/isolate-cpu.sh | 301 +++++++++++++++++++++ scripts/task-isolation/isolate-task.sh | 162 +++++++++++ .../performance/odp_run_app_isolated.sh | 106 ++++++++ 4 files changed, 591 insertions(+) create mode 100644 scripts/task-isolation/README create mode 100755 scripts/task-isolation/isolate-cpu.sh create mode 100755 scripts/task-isolation/isolate-task.sh create mode 100755 test/linux-generic/performance/odp_run_app_isolated.sh -- 2.7.4