Spdk/test/scheduler/common.sh
Michal Berger 7347f60bbc autotest: Use rpc_cmd() for rpc plugin-based tests
Also, create a common dir which will hold symlinks to all existing
plugins used in the tests. Location of the actual lib is not changed
so the relation to the given test suite is clearly preserved.

Signed-off-by: Michal Berger <michalx.berger@intel.com>
Change-Id: Icb70bbc61fbfa3325a357d5dd93f554ff132a3b9
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/7146
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: Tomasz Zawadzki <tomasz.zawadzki@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
2021-04-02 08:22:42 +00:00

396 lines
9.3 KiB
Bash

shopt -s nullglob extglob
declare -r sysfs_system=/sys/devices/system
declare -r sysfs_cpu=$sysfs_system/cpu
declare -r sysfs_node=$sysfs_system/node
declare -r scheduler=$rootdir/test/event/scheduler/scheduler
declare -r plugin=scheduler_plugin
fold_list_onto_array() {
local array=$1
local elem
shift || return 0
for elem; do
eval "${array}[elem]=$elem"
done
}
fold_array_onto_string() {
local cpus=("$@")
local IFS=","
echo "${cpus[*]}"
}
parse_cpu_list() {
local list=$1
local elem elems cpus
# 0-2,4,6-9, etc.
IFS="," read -ra elems < "$list"
((${#elems[@]} > 0)) || return 0
for elem in "${elems[@]}"; do
if [[ $elem == *-* ]]; then
local start=${elem%-*} end=${elem#*-}
while ((start <= end)); do
cpus[start++]=$start
done
else
cpus[elem]=$elem
fi
done
printf '%u\n' "${!cpus[@]}"
}
map_cpus_node() {
local node_idx=$1
local -n _cpu_node_map=node_${node_idx}_cpu
local cpu_idx core_idx
for cpu_idx in $(parse_cpu_list "$sysfs_node/node$node_idx/cpulist"); do
if is_cpu_online "$cpu_idx"; then
core_idx=$(< "$sysfs_cpu/cpu$cpu_idx/topology/core_id")
local -n _cpu_core_map=node_${node_idx}_core_${core_idx}
_cpu_core_map+=("$cpu_idx") cpu_core_map[cpu_idx]=$core_idx
fi
_cpu_node_map+=("$cpu_idx") cpu_node_map[cpu_idx]=$node_idx
cpus+=("$cpu_idx")
done
nodes[node_idx]=$node_idx
}
map_cpus() {
local -g cpus=()
local -g nodes=()
local -g cpu_node_map=()
local -g cpu_core_map=()
local -g core_node_map=()
local node
unset -v "${!node_@}"
for node in "$sysfs_node/node"+([0-9]); do
map_cpus_node "${node##*node}"
done
}
get_cpus() {
local node=$1
local core=$2
local _cpus
if [[ -z $node ]]; then
_cpus=("${cpus[@]}")
elif [[ -n $node ]]; then
eval "_cpus=(\${node_${node}_cpu[@]})"
if [[ -n $core ]]; then
eval "_cpus=(\${node_${node}_core_${core}[@]})"
fi
fi
((${#_cpus[@]} > 0)) || return 1
printf '%u\n' "${_cpus[@]}"
}
get_isolated_cpus() {
[[ -e $sysfs_cpu/isolated ]] || return 0
parse_cpu_list "$sysfs_cpu/isolated"
}
get_offline_cpus() {
local offline
[[ -e $sysfs_cpu/offline ]] || return 0
parse_cpu_list "$sysfs_cpu/offline"
}
get_online_cpus() {
[[ -e $sysfs_cpu/online ]] || return 0
parse_cpu_list "$sysfs_cpu/online"
}
is_cpu_online() {
local online
fold_list_onto_array online $(get_online_cpus)
[[ -v online[$1] ]]
}
is_cpu_offline() {
! is_cpu_online "$1"
}
online_cpu() {
is_cpu_offline "$1" || return 0
[[ -e $sysfs_cpu/cpu$1/online ]] && echo 1 > "$sysfs_cpu/cpu$1/online"
}
offline_cpu() {
is_cpu_online "$1" || return 0
[[ -e $sysfs_cpu/cpu$1/online ]] && echo 0 > "$sysfs_cpu/cpu$1/online"
}
mask_cpus() {
local cpu
local mask=0
for cpu; do
((mask |= 1 << cpu))
done
printf '0x%x\n' "$mask"
}
denied_list() {
local -g denied
fold_list_onto_array denied $(get_offline_cpus) "$@"
}
filter_allowed_list() {
local cpu
for cpu in "${!allowed[@]}"; do
if [[ -n ${denied[cpu]} ]]; then
unset -v "allowed[cpu]"
fi
done
}
allowed_list() {
local max=${1:-4}
local node=${2:-0}
local cpu_count=${cpu_count:--1}
local -g allowed
fold_list_onto_array allowed $(get_isolated_cpus)
if ((cpu_count < 0 && ${#allowed[@]} > 0)); then
((max += ${#allowed[@]}))
fi
local -n node_cpu_ref=node_${node}_cpu
while ((${#allowed[@]} < max && ++cpu_count < ${#node_cpu_ref[@]})); do
fold_list_onto_array allowed $(get_cpus "$node" "${cpu_core_map[node_cpu_ref[cpu_count]]}")
done
filter_allowed_list
if ((${#allowed[@]} == max)); then
return 0
elif ((cpu_count == ${#node_cpu_ref[@]})); then
return 0
else
allowed_list "$max" "$node"
fi
}
get_proc_cpu_affinity() {
xtrace_disable
local pid=${1:-$$}
local status val
[[ -e /proc/$pid/status ]] || return 1
while IFS=":"$'\t' read -r status val; do
if [[ $status == Cpus_allowed_list ]]; then
parse_cpu_list <(echo "$val")
return 0
fi
done < "/proc/$pid/status"
xtrace_restore
}
map_cpufreq() {
# This info is used to cross-reference current cpufreq setup with
# what DPDK's governor actually puts in place.
local -g cpufreq_drivers=()
local -g cpufreq_governors=()
local -g cpufreq_base_freqs=()
local -g cpufreq_max_freqs=()
local -g cpufreq_min_freqs=()
local -g cpufreq_cur_freqs=()
local -g cpufreq_is_turbo=()
local -g cpufreq_available_freqs=()
local -g cpufreq_available_governors=()
local -g cpufreq_high_prio=()
local -g cpufreq_non_turbo_ratio=()
local -g cpufreq_setspeed=()
local -g cpuinfo_max_freqs=()
local -g cpuinfo_min_freqs=()
local -g turbo_enabled=0
local cpu cpu_idx
for cpu in "$sysfs_cpu/cpu"+([0-9]); do
cpu_idx=${cpu##*cpu}
[[ -e $cpu/cpufreq ]] || continue
cpufreq_drivers[cpu_idx]=$(< "$cpu/cpufreq/scaling_driver")
cpufreq_governors[cpu_idx]=$(< "$cpu/cpufreq/scaling_governor")
# In case HWP is on
if [[ -e $cpu/cpufreq/base_frequency ]]; then
cpufreq_base_freqs[cpu_idx]=$(< "$cpu/cpufreq/base_frequency")
fi
cpufreq_cur_freqs[cpu_idx]=$(< "$cpu/cpufreq/scaling_cur_freq")
cpufreq_max_freqs[cpu_idx]=$(< "$cpu/cpufreq/scaling_max_freq")
cpufreq_min_freqs[cpu_idx]=$(< "$cpu/cpufreq/scaling_min_freq")
local -n available_governors=available_governors_cpu_${cpu_idx}
cpufreq_available_governors[cpu_idx]="available_governors_cpu_${cpu_idx}[@]"
available_governors=($(< "$cpu/cpufreq/scaling_available_governors"))
local -n available_freqs=available_freqs_cpu_${cpu_idx}
cpufreq_available_freqs[cpu_idx]="available_freqs_cpu_${cpu_idx}[@]"
case "${cpufreq_drivers[cpu_idx]}" in
acpi-cpufreq)
available_freqs=($(< "$cpu/cpufreq/scaling_available_frequencies"))
if ((available_freqs[0] - 1000 == available_freqs[1])); then
cpufreq_is_turbo[cpu_idx]=1
else
cpufreq_is_turbo[cpu_idx]=0
fi
cpufreq_setspeed[cpu_idx]=$(< "$cpu/cpufreq/scaling_setspeed")
;;
intel_pstate | intel_cpufreq) # active or passive
local non_turbo_ratio base_max_freq num_freq freq is_turbo=0
non_turbo_ratio=$("$testdir/rdmsr.pl" "$cpu_idx" 0xce)
cpuinfo_min_freqs[cpu_idx]=$(< "$cpu/cpufreq/cpuinfo_min_freq")
cpuinfo_max_freqs[cpu_idx]=$(< "$cpu/cpufreq/cpuinfo_max_freq")
cpufreq_non_turbo_ratio[cpu_idx]=$(((non_turbo_ratio >> 8) & 0xff))
if ((cpufreq_base_freqs[cpu_idx] / 100000 > cpufreq_non_turbo_ratio[cpu_idx])); then
cpufreq_high_prio[cpu_idx]=1
base_max_freq=${cpufreq_base_freqs[cpu_idx]}
else
cpufreq_high_prio[cpu_idx]=0
base_max_freq=$((cpufreq_non_turbo_ratio[cpu_idx] * 100000))
fi
num_freqs=$(((base_max_freq - cpuinfo_min_freqs[cpu_idx]) / 100000 + 1))
if ((base_max_freq < cpuinfo_max_freqs[cpu_idx])); then
((num_freqs += 1))
cpufreq_is_turbo[cpu_idx]=1
else
cpufreq_is_turbo[cpu_idx]=0
fi
available_freqs=()
for ((freq = 0; freq < num_freqs; freq++)); do
if ((freq == 0 && cpufreq_is_turbo[cpu_idx] == 1)); then
available_freqs[freq]=$((base_max_freq + 1))
else
available_freqs[freq]=$((base_max_freq - (freq - cpufreq_is_turbo[cpu_idx]) * 100000))
fi
done
;;
esac
done
if [[ -e $sysfs_cpu/cpufreq/boost ]]; then
turbo_enabled=$(< "$sysfs_cpu/cpufreq/boost")
elif [[ -e $sysfs_cpu/intel_pstate/no_turbo ]]; then
turbo_enabled=$((!$(< "$sysfs_cpu/intel_pstate/no_turbo")))
fi
}
set_cpufreq() {
local cpu=$1
local min_freq=$2
local max_freq=$3
local cpufreq=$sysfs_cpu/cpu$cpu/cpufreq
# Map the cpufreq info first
[[ -n ${cpufreq_drivers[cpu]} ]] || return 1
[[ -n $min_freq ]] || return 1
case "${cpufreq_drivers[cpu]}" in
acpi-cpufreq)
if [[ ${cpufreq_governors[cpu]} != userspace ]]; then
echo "userspace" > "$cpufreq/scaling_governors"
fi
echo "$min_freq" > "$cpufreq/scaling_setspeed"
;;
intel_pstate | intel_cpufreq)
if ((min_freq <= cpufreq_max_freqs[cpu])); then
echo "$min_freq" > "$cpufreq/scaling_min_freq"
fi
if [[ -n $max_freq ]] && ((max_freq >= min_freq)); then
echo "$max_freq" > "$cpufreq/scaling_max_freq"
fi
;;
esac
}
set_cpufreq_governor() {
local cpu=$1
local governor=$2
local cpufreq=$sysfs_cpu/cpu$cpu/cpufreq
if [[ $(< "$cpufreq/scaling_governor") != "$governor" ]]; then
echo "$governor" > "$cpufreq/scaling_governor"
fi
}
exec_under_dynamic_scheduler() {
"$@" --wait-for-rpc &
spdk_pid=$!
# Give some time for the app to init itself
waitforlisten "$spdk_pid"
"$rootdir/scripts/rpc.py" framework_set_scheduler dynamic
"$rootdir/scripts/rpc.py" framework_start_init
}
get_thread_stats() {
xtrace_disable
_get_thread_stats busy idle
xtrace_restore
}
_get_thread_stats() {
local list_busy=$1
local list_idle=$2
local thread threads stats
stats=$(rpc_cmd thread_get_stats | jq -r '.threads[]')
threads=($(jq -r '.id' <<< "$stats"))
for thread in "${threads[@]}"; do
eval "${list_busy}[$thread]=\$(jq -r \"select(.id == $thread) | .busy\" <<< \$stats)"
eval "${list_idle}[$thread]=\$(jq -r \"select(.id == $thread) | .idle\" <<< \$stats)"
thread_map[thread]=$(jq -r "select(.id == $thread) | .name" <<< "$stats")
done
}
get_cpu_stat() {
local cpu_idx=$1
local stat=$2 stats
while read -r cpu stats; do
[[ $cpu == "cpu$cpu_idx" ]] && stats=($stats)
done < /proc/stat
case "$stat" in
idle) echo "${stats[3]}" ;;
*) ;;
esac
}
create_thread() {
rpc_cmd --plugin "$plugin" scheduler_thread_create "$@"
}
destroy_thread() {
rpc_cmd --plugin "$plugin" scheduler_thread_delete "$@"
}
active_thread() {
rpc_cmd --plugin "$plugin" scheduler_thread_set_active "$@"
}