Signed-off-by: Michal Berger <michal.berger@intel.com> Change-Id: If75aeca0c44667ef02b72f2e4a9141da4057d291 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15459 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Karol Latecki <karol.latecki@intel.com> Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Kamil Godzwon <kamilx.godzwon@intel.com>
258 lines
6.2 KiB
Bash
258 lines
6.2 KiB
Bash
# SPDX-License-Identifier: BSD-3-Clause
|
|
# Copyright (C) 2022 Intel Corporation.
|
|
# All rights reserved.
|
|
|
|
source "$rootdir/test/scheduler/common.sh"
|
|
|
|
declare -a irqs_counters=()
|
|
declare -a irqs_devices=()
|
|
declare -a irqs_types=()
|
|
declare -a cpus=()
|
|
|
|
_get_cpus() {
|
|
local state=${1:-online}
|
|
|
|
_get_override_cpus || "_get_${state}_cpus"
|
|
}
|
|
|
|
_get_override_cpus() {
|
|
((${#cpus_override[@]} > 0)) || return 1
|
|
fold_list_onto_array cpus "${cpus_override[@]}"
|
|
}
|
|
|
|
_get_online_cpus() {
|
|
fold_list_onto_array cpus $(get_online_cpus)
|
|
}
|
|
|
|
_get_offline_cpus() {
|
|
fold_list_onto_array cpus $(get_offline_cpus)
|
|
}
|
|
|
|
get_all_irqs() {
|
|
local irqs=() s_irqs=()
|
|
|
|
irqs=(/proc/irq/+([0-9]))
|
|
irqs=("${irqs[@]##*/}")
|
|
|
|
# Sort it
|
|
fold_list_onto_array s_irqs "${irqs[@]}"
|
|
|
|
printf '%u\n' "${s_irqs[@]}"
|
|
}
|
|
|
|
check_this_irq() {
|
|
local irq=${1:-0}
|
|
|
|
((${#irqs_to_lookup[@]} > 0)) || return 0
|
|
|
|
[[ -n ${irqs_to_lookup[irq]} ]]
|
|
}
|
|
|
|
update_irqs_sysfs() {
|
|
local sysroot=${1:-}
|
|
local input=$sysroot/sys/kernel/irq
|
|
|
|
[[ -e $input ]] || return 1
|
|
|
|
# per_cpu_count holds a list of all cpus, regardless of their state
|
|
_get_cpus online
|
|
_get_cpus offline
|
|
|
|
local irq_path
|
|
for irq_path in "$input/"*; do
|
|
irq=${irq_path##*/}
|
|
check_this_irq "$irq" || continue
|
|
IFS="," read -ra cpu_counters < "$irq_path/per_cpu_count"
|
|
for cpu in "${cpus[@]}"; do
|
|
eval "_irq${irq}_cpu${cpu}+=(${cpu_counters[cpu]})"
|
|
eval "_irq${irq}_counter[cpu]=_irq${irq}_cpu${cpu}[@]"
|
|
done
|
|
irqs_counters[irq]="_irq${irq}_counter[@]"
|
|
irqs_devices[irq]=$(< "$irq_path/actions")
|
|
irqs_types[irq]="$(< "$irq_path/chip_name") $(< "$irq_path/hwirq")-$(< "$irq_path/name")"
|
|
done
|
|
}
|
|
|
|
update_irqs_procfs() {
|
|
local input=${1:-/proc/interrupts}
|
|
|
|
[[ -e $input ]] || return 1
|
|
|
|
# /proc/interrupts shows only online CPUs. Use get_cpus() to get readings for
|
|
# proper CPUs rather than parsing the actual header of the file.
|
|
_get_cpus online
|
|
|
|
local counter_idx
|
|
while read -ra irqs; do
|
|
irq=${irqs[0]%:*}
|
|
[[ $irq == +([0-9]) ]] || continue
|
|
check_this_irq "$irq" || continue
|
|
cpu_counters=("${irqs[@]:1:${#cpus[@]}}") counter_idx=0
|
|
for cpu in "${cpus[@]}"; do
|
|
eval "_irq${irq}_cpu${cpu}+=(${cpu_counters[counter_idx++]})"
|
|
eval "_irq${irq}_counter[cpu]=_irq${irq}_cpu${cpu}[@]"
|
|
done
|
|
irqs_counters[irq]="_irq${irq}_counter[@]"
|
|
irqs_devices[irq]=${irqs[*]:${#cpus[@]}+1:2}
|
|
irqs_types[irq]=${irqs[*]:${#cpus[@]}+3}
|
|
done < "$input"
|
|
}
|
|
|
|
update_irqs() {
|
|
local irqs irq
|
|
local cpu cpu_counters=()
|
|
local irqs_to_lookup=()
|
|
|
|
fold_list_onto_array irqs_to_lookup "$@"
|
|
|
|
update_irqs_sysfs || update_irqs_procfs
|
|
}
|
|
|
|
get_irqs() {
|
|
local irqs=("$@") irq cpu
|
|
local _counters counters counter delta total
|
|
|
|
# If cpus[@] are not init, update was not run so nothing to check
|
|
((${#cpus[@]} > 0)) || return 1
|
|
|
|
if ((${#irqs[@]} == 0)); then
|
|
irqs=($(get_all_irqs))
|
|
fi
|
|
|
|
for irq in "${irqs[@]}"; do
|
|
for cpu in "${cpus[@]}"; do
|
|
[[ -v "_irq${irq}_cpu${cpu}[@]" ]] || continue
|
|
local -n counters="_irq${irq}_cpu${cpu}"
|
|
# keep a separate copy to not touch the main _irq*[]
|
|
_counters=("${counters[@]}") total=0
|
|
|
|
if ((${#counters[@]} > 1)); then
|
|
# Enhance output with calculating deltas between each reading
|
|
for ((counter = 0; counter < ${#counters[@]} - 1; counter++)); do
|
|
delta=$((counters[counter + 1] - counters[counter]))
|
|
_counters[counter + 1]="${counters[counter + 1]} (+$delta)"
|
|
: $((total += delta))
|
|
done
|
|
fi
|
|
_counters+=("==$total")
|
|
# Ignore idle irqs unless request from the env tells otherwise
|
|
if [[ -n $SHOW_ALL_IRQS ]] || ((total > 0)); then
|
|
echo "irq$irq->$(get_irq_type "$irq")->$(get_irq_device "$irq")@cpu$cpu:"
|
|
printf ' %s\n' "${_counters[@]}"
|
|
fi
|
|
done
|
|
done
|
|
}
|
|
|
|
get_irq_type() {
|
|
[[ -n ${irqs_types[$1]} ]] || return 1
|
|
echo "${irqs_types[$1]}"
|
|
}
|
|
|
|
get_irq_device() {
|
|
[[ -n ${irqs_devices[$1]} ]] || return 1
|
|
echo "${irqs_devices[$1]}"
|
|
}
|
|
|
|
reset_irqs() {
|
|
irqs_counters=() irqs_devices=() irqs_types=() cpus=()
|
|
|
|
unset -v "${!_irq@}"
|
|
}
|
|
|
|
read_irq_cpu_mask() {
|
|
local irq=$1 mask=$2
|
|
|
|
[[ -n $irq && -e /proc/irq/$irq || -n $mask ]] || return 1
|
|
|
|
# smp_affinity holds a string of comma-separated 32-bit values. Iterate
|
|
# over each dWORD and extract cpus bit by bit. Iterate from the end of
|
|
# the array as that's where the first dWORD is located.
|
|
local smp_affinity
|
|
local bit dword dword_l=32 dword_idx
|
|
local cpus=()
|
|
|
|
if [[ -n $mask ]]; then
|
|
IFS="," read -ra smp_affinity <<< "$mask"
|
|
else
|
|
IFS="," read -ra smp_affinity < "/proc/irq/$irq/smp_affinity"
|
|
fi
|
|
|
|
smp_affinity=("${smp_affinity[@]/#/0x}")
|
|
|
|
for ((dword = ${#smp_affinity[@]} - 1, dword_idx = 0; dword >= 0; dword--, dword_idx++)); do
|
|
bit=-1
|
|
while ((++bit < dword_l)); do
|
|
if ((smp_affinity[dword] & 1 << bit)); then
|
|
cpus[bit + dword_l * dword_idx]=$bit
|
|
fi
|
|
done
|
|
done
|
|
|
|
printf '%u\n' "${!cpus[@]}"
|
|
}
|
|
|
|
read_irq_cpu_list() {
|
|
local irq=$1 effective=${2:-0}
|
|
|
|
[[ -n $irq && -e /proc/irq/$irq ]] || return 1
|
|
|
|
if ((effective)); then
|
|
parse_cpu_list "/proc/irq/$irq/effective_affinity_list"
|
|
else
|
|
parse_cpu_list "/proc/irq/$irq/smp_affinity_list"
|
|
fi
|
|
}
|
|
|
|
build_irq_cpu_mask() {
|
|
local cpu dword_l=32 dword_idx dword idxs
|
|
local _mask=() mask=""
|
|
|
|
for cpu; do
|
|
dword_idx=$((cpu / dword_l))
|
|
((_mask[dword_idx] |= 1 << (cpu - dword_l * dword_idx)))
|
|
done
|
|
|
|
# Store sorted list of dword indexes that we got
|
|
idxs=("${!_mask[@]}")
|
|
|
|
# Fill out all dWORDs starting from the highest (last) dword index
|
|
for ((dword = idxs[-1]; dword >= 0; dword--)); do
|
|
_mask[dword]=$(printf '%08x' "${_mask[dword]}")
|
|
mask=${mask:+$mask,}${_mask[dword]}
|
|
done
|
|
|
|
echo "$mask"
|
|
}
|
|
|
|
squash_irq_cpu_mask() {
|
|
local mask
|
|
|
|
mask=$(build_irq_cpu_mask "$@")
|
|
# E.g.: 1,32,64,65,77,88,127 -> 0x80000000010020030000000100000002
|
|
# Valid under DPDK
|
|
echo "0x${mask//,/}"
|
|
}
|
|
|
|
unsquash_irq_cpu_mask() {
|
|
# E.g.: 0x80000000010020030000000100000002 -> 80000000,01002003,00000001,00000002
|
|
# 8 is a max number of chars in a dWORD represented in hex.
|
|
|
|
local smask=$1 _smask="" smask_l _smask_l
|
|
|
|
smask=${smask/0x/} smask_l=$((${#smask} / 8)) _smask_l=$smask_l
|
|
|
|
((smask_l == 0)) && echo "$smask" && return 0
|
|
|
|
# Put comma at a right index
|
|
while ((_smask_l)); do
|
|
_smask+=,${smask:${#smask}-_smask_l--*8:8}
|
|
done
|
|
|
|
# Add remaining chars if any
|
|
_smask=${smask::${#smask}-8*smask_l}${_smask}
|
|
|
|
# If there were no chars left, drop the ',' from the beginning of the string
|
|
echo "${_smask#,}"
|
|
}
|