1# SPDX-License-Identifier: BSD-3-Clause 2# Copyright (C) 2022 Intel Corporation. 3# All rights reserved. 4 5source "$rootdir/test/scheduler/common.sh" 6 7declare -a irqs_counters=() 8declare -a irqs_devices=() 9declare -a irqs_types=() 10declare -a cpus=() 11 12_get_cpus() { 13 local state=${1:-online} 14 15 _get_override_cpus || "_get_${state}_cpus" 16} 17 18_get_override_cpus() { 19 ((${#cpus_override[@]} > 0)) || return 1 20 fold_list_onto_array cpus "${cpus_override[@]}" 21} 22 23_get_online_cpus() { 24 fold_list_onto_array cpus $(get_online_cpus) 25} 26 27_get_offline_cpus() { 28 fold_list_onto_array cpus $(get_offline_cpus) 29} 30 31get_all_irqs() { 32 local irqs=() s_irqs=() 33 34 irqs=(/proc/irq/+([0-9])) 35 irqs=("${irqs[@]##*/}") 36 37 # Sort it 38 fold_list_onto_array s_irqs "${irqs[@]}" 39 40 printf '%u\n' "${s_irqs[@]}" 41} 42 43check_this_irq() { 44 local irq=${1:-0} 45 46 ((${#irqs_to_lookup[@]} > 0)) || return 0 47 48 [[ -n ${irqs_to_lookup[irq]} ]] 49} 50 51update_irqs_sysfs() { 52 local sysroot=${1:-} 53 local input=$sysroot/sys/kernel/irq 54 55 [[ -e $input ]] || return 1 56 57 # per_cpu_count holds a list of all cpus, regardless of their state 58 _get_cpus online 59 _get_cpus offline 60 61 local irq_path 62 for irq_path in "$input/"*; do 63 irq=${irq_path##*/} 64 check_this_irq "$irq" || continue 65 IFS="," read -ra cpu_counters < "$irq_path/per_cpu_count" 66 for cpu in "${cpus[@]}"; do 67 eval "_irq${irq}_cpu${cpu}+=(${cpu_counters[cpu]})" 68 eval "_irq${irq}_counter[cpu]=_irq${irq}_cpu${cpu}[@]" 69 done 70 irqs_counters[irq]="_irq${irq}_counter[@]" 71 irqs_devices[irq]=$(< "$irq_path/actions") 72 irqs_types[irq]="$(< "$irq_path/chip_name") $(< "$irq_path/hwirq")-$(< "$irq_path/name")" 73 done 74} 75 76update_irqs_procfs() { 77 local input=${1:-/proc/interrupts} 78 79 [[ -e $input ]] || return 1 80 81 # /proc/interrupts shows only online CPUs. Use get_cpus() to get readings for 82 # proper CPUs rather than parsing the actual header of the file. 83 _get_cpus online 84 85 local counter_idx 86 while read -ra irqs; do 87 irq=${irqs[0]%:*} 88 [[ $irq == +([0-9]) ]] || continue 89 check_this_irq "$irq" || continue 90 cpu_counters=("${irqs[@]:1:${#cpus[@]}}") counter_idx=0 91 for cpu in "${cpus[@]}"; do 92 eval "_irq${irq}_cpu${cpu}+=(${cpu_counters[counter_idx++]})" 93 eval "_irq${irq}_counter[cpu]=_irq${irq}_cpu${cpu}[@]" 94 done 95 irqs_counters[irq]="_irq${irq}_counter[@]" 96 irqs_devices[irq]=${irqs[*]:${#cpus[@]}+1:2} 97 irqs_types[irq]=${irqs[*]:${#cpus[@]}+3} 98 done < "$input" 99} 100 101update_irqs() { 102 local irqs irq 103 local cpu cpu_counters=() 104 local irqs_to_lookup=() 105 106 fold_list_onto_array irqs_to_lookup "$@" 107 108 update_irqs_sysfs || update_irqs_procfs 109} 110 111get_irqs() { 112 local irqs=("$@") irq cpu 113 local _counters counters counter delta total 114 115 # If cpus[@] are not init, update was not run so nothing to check 116 ((${#cpus[@]} > 0)) || return 1 117 118 if ((${#irqs[@]} == 0)); then 119 irqs=($(get_all_irqs)) 120 fi 121 122 for irq in "${irqs[@]}"; do 123 for cpu in "${cpus[@]}"; do 124 [[ -v "_irq${irq}_cpu${cpu}[@]" ]] || continue 125 local -n counters="_irq${irq}_cpu${cpu}" 126 # keep a separate copy to not touch the main _irq*[] 127 _counters=("${counters[@]}") total=0 128 129 if ((${#counters[@]} > 1)); then 130 # Enhance output with calculating deltas between each reading 131 for ((counter = 0; counter < ${#counters[@]} - 1; counter++)); do 132 delta=$((counters[counter + 1] - counters[counter])) 133 _counters[counter + 1]="${counters[counter + 1]} (+$delta)" 134 : $((total += delta)) 135 done 136 fi 137 _counters+=("==$total") 138 # Ignore idle irqs unless request from the env tells otherwise 139 if [[ -n $SHOW_ALL_IRQS ]] || ((total > 0)); then 140 echo "irq$irq->$(get_irq_type "$irq")->$(get_irq_device "$irq")@cpu$cpu:" 141 printf ' %s\n' "${_counters[@]}" 142 fi 143 done 144 done 145} 146 147get_irq_type() { 148 [[ -n ${irqs_types[$1]} ]] || return 1 149 echo "${irqs_types[$1]}" 150} 151 152get_irq_device() { 153 [[ -n ${irqs_devices[$1]} ]] || return 1 154 echo "${irqs_devices[$1]}" 155} 156 157reset_irqs() { 158 irqs_counters=() irqs_devices=() irqs_types=() cpus=() 159 160 unset -v "${!_irq@}" 161} 162 163read_irq_cpu_mask() { 164 local irq=$1 mask=$2 165 166 [[ -n $irq && -e /proc/irq/$irq || -n $mask ]] || return 1 167 168 # smp_affinity holds a string of comma-separated 32-bit values. Iterate 169 # over each dWORD and extract cpus bit by bit. Iterate from the end of 170 # the array as that's where the first dWORD is located. 171 local smp_affinity 172 local bit dword dword_l=32 dword_idx 173 local cpus=() 174 175 if [[ -n $mask ]]; then 176 IFS="," read -ra smp_affinity <<< "$mask" 177 else 178 IFS="," read -ra smp_affinity < "/proc/irq/$irq/smp_affinity" 179 fi 180 181 smp_affinity=("${smp_affinity[@]/#/0x}") 182 183 for ((dword = ${#smp_affinity[@]} - 1, dword_idx = 0; dword >= 0; dword--, dword_idx++)); do 184 bit=-1 185 while ((++bit < dword_l)); do 186 if ((smp_affinity[dword] & 1 << bit)); then 187 cpus[bit + dword_l * dword_idx]=$bit 188 fi 189 done 190 done 191 192 printf '%u\n' "${!cpus[@]}" 193} 194 195read_irq_cpu_list() { 196 local irq=$1 effective=${2:-0} 197 198 [[ -n $irq && -e /proc/irq/$irq ]] || return 1 199 200 if ((effective)); then 201 parse_cpu_list "/proc/irq/$irq/effective_affinity_list" 202 else 203 parse_cpu_list "/proc/irq/$irq/smp_affinity_list" 204 fi 205} 206 207build_irq_cpu_mask() { 208 local cpu dword_l=32 dword_idx dword idxs 209 local _mask=() mask="" 210 211 for cpu; do 212 dword_idx=$((cpu / dword_l)) 213 ((_mask[dword_idx] |= 1 << (cpu - dword_l * dword_idx))) 214 done 215 216 # Store sorted list of dword indexes that we got 217 idxs=("${!_mask[@]}") 218 219 # Fill out all dWORDs starting from the highest (last) dword index 220 for ((dword = idxs[-1]; dword >= 0; dword--)); do 221 _mask[dword]=$(printf '%08x' "${_mask[dword]}") 222 mask=${mask:+$mask,}${_mask[dword]} 223 done 224 225 echo "$mask" 226} 227 228squash_irq_cpu_mask() { 229 local mask 230 231 mask=$(build_irq_cpu_mask "$@") 232 # E.g.: 1,32,64,65,77,88,127 -> 0x80000000010020030000000100000002 233 # Valid under DPDK 234 echo "0x${mask//,/}" 235} 236 237unsquash_irq_cpu_mask() { 238 # E.g.: 0x80000000010020030000000100000002 -> 80000000,01002003,00000001,00000002 239 # 8 is a max number of chars in a dWORD represented in hex. 240 241 local smask=$1 _smask="" smask_l _smask_l 242 243 smask=${smask/0x/} smask_l=$((${#smask} / 8)) _smask_l=$smask_l 244 245 ((smask_l == 0)) && echo "$smask" && return 0 246 247 # Put comma at a right index 248 while ((_smask_l)); do 249 _smask+=,${smask:${#smask}-_smask_l--*8:8} 250 done 251 252 # Add remaining chars if any 253 _smask=${smask::${#smask}-8*smask_l}${_smask} 254 255 # If there were no chars left, drop the ',' from the beginning of the string 256 echo "${_smask#,}" 257} 258