1eb53c232Spaul luse# SPDX-License-Identifier: BSD-3-Clause 2eb53c232Spaul luse# Copyright (C) 2020 Intel Corporation 3eb53c232Spaul luse# All rights reserved. 4eb53c232Spaul luse# 5eb53c232Spaul luse 6c1318c5bSMichal Bergerdeclare -r sysfs_system=/sys/devices/system 7c1318c5bSMichal Bergerdeclare -r sysfs_cpu=$sysfs_system/cpu 8c1318c5bSMichal Bergerdeclare -r sysfs_node=$sysfs_system/node 9c1318c5bSMichal Berger 10049d587eSMichal Bergerdeclare -r scheduler=$rootdir/test/event/scheduler/scheduler 11af24a874SMichal Bergerdeclare plugin=scheduler_plugin 12049d587eSMichal Berger 136872c67eSMichal Bergersource "$rootdir/test/scheduler/cgroups.sh" 141fd9dccfSMichal Berger 15c1318c5bSMichal Bergerfold_list_onto_array() { 16c1318c5bSMichal Berger local array=$1 17c1318c5bSMichal Berger local elem 18c1318c5bSMichal Berger 19c1318c5bSMichal Berger shift || return 0 20c1318c5bSMichal Berger 21c1318c5bSMichal Berger for elem; do 22c1318c5bSMichal Berger eval "${array}[elem]=$elem" 23c1318c5bSMichal Berger done 24c1318c5bSMichal Berger} 25c1318c5bSMichal Berger 26c1318c5bSMichal Bergerfold_array_onto_string() { 27c1318c5bSMichal Berger local cpus=("$@") 28c1318c5bSMichal Berger 29c1318c5bSMichal Berger local IFS="," 30c1318c5bSMichal Berger echo "${cpus[*]}" 31c1318c5bSMichal Berger} 32c1318c5bSMichal Berger 33c1318c5bSMichal Bergerparse_cpu_list() { 34c1318c5bSMichal Berger local list=$1 35c1318c5bSMichal Berger local elem elems cpus 36c1318c5bSMichal Berger 37c1318c5bSMichal Berger # 0-2,4,6-9, etc. 38c1318c5bSMichal Berger IFS="," read -ra elems < "$list" 39c1318c5bSMichal Berger 40c1318c5bSMichal Berger ((${#elems[@]} > 0)) || return 0 41c1318c5bSMichal Berger 42c1318c5bSMichal Berger for elem in "${elems[@]}"; do 43c1318c5bSMichal Berger if [[ $elem == *-* ]]; then 44c1318c5bSMichal Berger local start=${elem%-*} end=${elem#*-} 45c1318c5bSMichal Berger while ((start <= end)); do 46c1318c5bSMichal Berger cpus[start++]=$start 47c1318c5bSMichal Berger done 48c1318c5bSMichal Berger else 49c1318c5bSMichal Berger cpus[elem]=$elem 50c1318c5bSMichal Berger fi 51c1318c5bSMichal Berger done 52c1318c5bSMichal Berger printf '%u\n' "${!cpus[@]}" 53c1318c5bSMichal Berger} 54c1318c5bSMichal Berger 55c1318c5bSMichal Bergermap_cpus_node() { 56c1318c5bSMichal Berger local node_idx=$1 57c1318c5bSMichal Berger local -n _cpu_node_map=node_${node_idx}_cpu 58c1318c5bSMichal Berger local cpu_idx core_idx 59c1318c5bSMichal Berger 60c1318c5bSMichal Berger for cpu_idx in $(parse_cpu_list "$sysfs_node/node$node_idx/cpulist"); do 610a4a5235SMichal Berger if is_cpu_online_f "$cpu_idx"; then 62c1318c5bSMichal Berger core_idx=$(< "$sysfs_cpu/cpu$cpu_idx/topology/core_id") 63c1318c5bSMichal Berger local -n _cpu_core_map=node_${node_idx}_core_${core_idx} 64c1318c5bSMichal Berger _cpu_core_map+=("$cpu_idx") cpu_core_map[cpu_idx]=$core_idx 657832b34fSMichal Berger local -n _cpu_siblings=node_${node_idx}_core_${core_idx}_thread_${cpu_idx} 667832b34fSMichal Berger _cpu_siblings=($(parse_cpu_list "$sysfs_cpu/cpu$cpu_idx/topology/thread_siblings_list")) 677832b34fSMichal Berger cpu_siblings[cpu_idx]="node_${node_idx}_core_${core_idx}_thread_${cpu_idx}[@]" 68c1318c5bSMichal Berger fi 69c1e9ed6dSMichal Berger _cpu_node_map[cpu_idx]=$cpu_idx cpu_node_map[cpu_idx]=$node_idx 70c1318c5bSMichal Berger cpus+=("$cpu_idx") 71c1318c5bSMichal Berger done 72c1318c5bSMichal Berger 73c1318c5bSMichal Berger nodes[node_idx]=$node_idx 74c1318c5bSMichal Berger} 75c1318c5bSMichal Berger 76c1318c5bSMichal Bergermap_cpus() { 77c1318c5bSMichal Berger local -g cpus=() 787832b34fSMichal Berger local -g cpu_siblings=() 79c1318c5bSMichal Berger local -g nodes=() 80c1318c5bSMichal Berger local -g cpu_node_map=() 81c1318c5bSMichal Berger local -g cpu_core_map=() 82c1318c5bSMichal Berger local -g core_node_map=() 83c1318c5bSMichal Berger local node 84c1318c5bSMichal Berger 85c1318c5bSMichal Berger unset -v "${!node_@}" 86c1318c5bSMichal Berger 87c1318c5bSMichal Berger for node in "$sysfs_node/node"+([0-9]); do 88c1318c5bSMichal Berger map_cpus_node "${node##*node}" 89c1318c5bSMichal Berger done 90c1318c5bSMichal Berger} 91c1318c5bSMichal Berger 92c1318c5bSMichal Bergerget_cpus() { 93c1318c5bSMichal Berger local node=$1 94c1318c5bSMichal Berger local core=$2 95c1318c5bSMichal Berger local _cpus 96c1318c5bSMichal Berger 97c1318c5bSMichal Berger if [[ -z $node ]]; then 98c1318c5bSMichal Berger _cpus=("${cpus[@]}") 99c1318c5bSMichal Berger elif [[ -n $node ]]; then 100c1318c5bSMichal Berger eval "_cpus=(\${node_${node}_cpu[@]})" 101c1318c5bSMichal Berger if [[ -n $core ]]; then 102c1318c5bSMichal Berger eval "_cpus=(\${node_${node}_core_${core}[@]})" 103c1318c5bSMichal Berger fi 104c1318c5bSMichal Berger fi 105c1318c5bSMichal Berger ((${#_cpus[@]} > 0)) || return 1 106c1318c5bSMichal Berger printf '%u\n' "${_cpus[@]}" 107c1318c5bSMichal Berger} 108c1318c5bSMichal Berger 109c1318c5bSMichal Bergerget_isolated_cpus() { 110c1318c5bSMichal Berger [[ -e $sysfs_cpu/isolated ]] || return 0 111c1318c5bSMichal Berger parse_cpu_list "$sysfs_cpu/isolated" 112c1318c5bSMichal Berger} 113c1318c5bSMichal Berger 114c1318c5bSMichal Bergerget_offline_cpus() { 115c1318c5bSMichal Berger local offline 116c1318c5bSMichal Berger 117c1318c5bSMichal Berger [[ -e $sysfs_cpu/offline ]] || return 0 118c1318c5bSMichal Berger parse_cpu_list "$sysfs_cpu/offline" 119c1318c5bSMichal Berger} 120c1318c5bSMichal Berger 121c1318c5bSMichal Bergerget_online_cpus() { 122c1318c5bSMichal Berger [[ -e $sysfs_cpu/online ]] || return 0 123c1318c5bSMichal Berger parse_cpu_list "$sysfs_cpu/online" 124c1318c5bSMichal Berger} 125c1318c5bSMichal Berger 126c1318c5bSMichal Bergeris_cpu_online() { 127c1318c5bSMichal Berger local online 128c1318c5bSMichal Berger 129c1318c5bSMichal Berger fold_list_onto_array online $(get_online_cpus) 130c1318c5bSMichal Berger [[ -v online[$1] ]] 131c1318c5bSMichal Berger} 132c1318c5bSMichal Berger 133c1318c5bSMichal Bergeris_cpu_offline() { 134c1318c5bSMichal Berger ! is_cpu_online "$1" 135c1318c5bSMichal Berger} 136c1318c5bSMichal Berger 1370a4a5235SMichal Bergeris_cpu_online_f() { 1380a4a5235SMichal Berger local cpu=$1 1390a4a5235SMichal Berger 1400a4a5235SMichal Berger if ((cpu == 0)); then 1410a4a5235SMichal Berger # cpu0 is special as it requires proper support in the kernel to be hot pluggable. 1420a4a5235SMichal Berger # As such, it usually does not have its own online attribute so always check the 1430a4a5235SMichal Berger # online list instead. 1440a4a5235SMichal Berger is_cpu_online "$cpu" 1450a4a5235SMichal Berger else 1460a4a5235SMichal Berger [[ -e $sysfs_cpu/cpu$cpu/online ]] || return 1 1470a4a5235SMichal Berger (($(< "$sysfs_cpu/cpu$cpu/online") == 1)) 1480a4a5235SMichal Berger fi 1490a4a5235SMichal Berger} 1500a4a5235SMichal Berger 1510a4a5235SMichal Bergeris_cpu_offline_f() { 1520a4a5235SMichal Berger ! is_cpu_online_f "$1" 1530a4a5235SMichal Berger} 1540a4a5235SMichal Berger 1550070858eSMichal Bergeris_numa() { 1560070858eSMichal Berger local nodes=("$sysfs_node/node"+([0-9])) 1570070858eSMichal Berger 1580070858eSMichal Berger ((${#nodes[@]} > 1)) 1590070858eSMichal Berger} 1600070858eSMichal Berger 161c1318c5bSMichal Bergeronline_cpu() { 1620a4a5235SMichal Berger is_cpu_offline_f "$1" || return 0 1630a4a5235SMichal Berger echo 1 > "$sysfs_cpu/cpu$1/online" 164c1318c5bSMichal Berger} 165c1318c5bSMichal Berger 166c1318c5bSMichal Bergeroffline_cpu() { 1670a4a5235SMichal Berger is_cpu_online_f "$1" || return 0 1680a4a5235SMichal Berger echo 0 > "$sysfs_cpu/cpu$1/online" 169c1318c5bSMichal Berger} 170c1318c5bSMichal Berger 171c1318c5bSMichal Bergermask_cpus() { 1725ad2877dSMichal Berger printf '[%s]\n' "$(fold_array_onto_string "$@")" 173c1318c5bSMichal Berger} 174c1318c5bSMichal Berger 175c1318c5bSMichal Bergerdenied_list() { 176c1318c5bSMichal Berger local -g denied 177c1318c5bSMichal Berger 178c1318c5bSMichal Berger fold_list_onto_array denied $(get_offline_cpus) "$@" 179c1318c5bSMichal Berger} 180c1318c5bSMichal Berger 181c1318c5bSMichal Bergerfilter_allowed_list() { 182c1318c5bSMichal Berger local cpu 183c1318c5bSMichal Berger 184c1318c5bSMichal Berger for cpu in "${!allowed[@]}"; do 1855ad2877dSMichal Berger if [[ -n ${denied[cpu]} ]] || ((cpu > 127)); then 186c1318c5bSMichal Berger unset -v "allowed[cpu]" 187c1318c5bSMichal Berger fi 188c1318c5bSMichal Berger done 189c1318c5bSMichal Berger} 190c1318c5bSMichal Berger 191c1318c5bSMichal Bergerallowed_list() { 192c1318c5bSMichal Berger local max=${1:-4} 193c1318c5bSMichal Berger local node=${2:-0} 194c1318c5bSMichal Berger local cpu_count=${cpu_count:--1} 195c1318c5bSMichal Berger 196c1318c5bSMichal Berger local -g allowed 197c1318c5bSMichal Berger 198c1318c5bSMichal Berger fold_list_onto_array allowed $(get_isolated_cpus) 199c1318c5bSMichal Berger 200c1318c5bSMichal Berger if ((cpu_count < 0 && ${#allowed[@]} > 0)); then 201c1318c5bSMichal Berger ((max += ${#allowed[@]})) 202c1318c5bSMichal Berger fi 203c1318c5bSMichal Berger 204c1318c5bSMichal Berger local -n node_cpu_ref=node_${node}_cpu 205c1318c5bSMichal Berger 206c1318c5bSMichal Berger while ((${#allowed[@]} < max && ++cpu_count < ${#node_cpu_ref[@]})); do 207c1318c5bSMichal Berger fold_list_onto_array allowed $(get_cpus "$node" "${cpu_core_map[node_cpu_ref[cpu_count]]}") 208c1318c5bSMichal Berger done 209c1318c5bSMichal Berger 210c1318c5bSMichal Berger filter_allowed_list 211c1318c5bSMichal Berger 212c1318c5bSMichal Berger if ((${#allowed[@]} == max)); then 213c1318c5bSMichal Berger return 0 214c1318c5bSMichal Berger elif ((cpu_count == ${#node_cpu_ref[@]})); then 215c1318c5bSMichal Berger return 0 216c1318c5bSMichal Berger else 217c1318c5bSMichal Berger allowed_list "$max" "$node" 218c1318c5bSMichal Berger fi 219c1318c5bSMichal Berger} 220c1318c5bSMichal Berger 221c1318c5bSMichal Bergerget_proc_cpu_affinity() { 222c1318c5bSMichal Berger xtrace_disable 223c1318c5bSMichal Berger 224c1318c5bSMichal Berger local pid=${1:-$$} 2257b52e4c1SMichal Berger local status val status_file 226c1318c5bSMichal Berger 2277b52e4c1SMichal Berger if [[ -e $pid ]]; then 2287b52e4c1SMichal Berger status_file=$pid 2297b52e4c1SMichal Berger elif [[ -e /proc/$pid/status ]]; then 2307b52e4c1SMichal Berger status_file=/proc/$pid/status 2317b52e4c1SMichal Berger else 2327b52e4c1SMichal Berger return 1 2337b52e4c1SMichal Berger fi 2347b52e4c1SMichal Berger 235*7bc1134dSMichal Berger # shellcheck disable=SC2188 236c1318c5bSMichal Berger while IFS=":"$'\t' read -r status val; do 237c1318c5bSMichal Berger if [[ $status == Cpus_allowed_list ]]; then 238c1318c5bSMichal Berger parse_cpu_list <(echo "$val") 239c1318c5bSMichal Berger return 0 240c1318c5bSMichal Berger fi 241*7bc1134dSMichal Berger done < <(< "$status_file") 242c1318c5bSMichal Berger 243c1318c5bSMichal Berger xtrace_restore 244c1318c5bSMichal Berger} 245c1318c5bSMichal Berger 246c1318c5bSMichal Bergermap_cpufreq() { 247c1318c5bSMichal Berger # This info is used to cross-reference current cpufreq setup with 248c1318c5bSMichal Berger # what DPDK's governor actually puts in place. 249c1318c5bSMichal Berger 250c1318c5bSMichal Berger local -g cpufreq_drivers=() 251c1318c5bSMichal Berger local -g cpufreq_governors=() 252c1318c5bSMichal Berger local -g cpufreq_base_freqs=() 253c1318c5bSMichal Berger local -g cpufreq_max_freqs=() 254c1318c5bSMichal Berger local -g cpufreq_min_freqs=() 255c1318c5bSMichal Berger local -g cpufreq_cur_freqs=() 256c1318c5bSMichal Berger local -g cpufreq_is_turbo=() 257c1318c5bSMichal Berger local -g cpufreq_available_freqs=() 258c1318c5bSMichal Berger local -g cpufreq_available_governors=() 259c1318c5bSMichal Berger local -g cpufreq_high_prio=() 260c1318c5bSMichal Berger local -g cpufreq_non_turbo_ratio=() 261c1318c5bSMichal Berger local -g cpufreq_setspeed=() 262c1318c5bSMichal Berger local -g cpuinfo_max_freqs=() 263c1318c5bSMichal Berger local -g cpuinfo_min_freqs=() 264c1318c5bSMichal Berger local -g turbo_enabled=0 265c1318c5bSMichal Berger local cpu cpu_idx 266c1318c5bSMichal Berger 267c1318c5bSMichal Berger for cpu in "$sysfs_cpu/cpu"+([0-9]); do 268c1318c5bSMichal Berger cpu_idx=${cpu##*cpu} 269c1318c5bSMichal Berger [[ -e $cpu/cpufreq ]] || continue 270c1318c5bSMichal Berger cpufreq_drivers[cpu_idx]=$(< "$cpu/cpufreq/scaling_driver") 271c1318c5bSMichal Berger cpufreq_governors[cpu_idx]=$(< "$cpu/cpufreq/scaling_governor") 272c1318c5bSMichal Berger 273c1318c5bSMichal Berger # In case HWP is on 274c1318c5bSMichal Berger if [[ -e $cpu/cpufreq/base_frequency ]]; then 275c1318c5bSMichal Berger cpufreq_base_freqs[cpu_idx]=$(< "$cpu/cpufreq/base_frequency") 276c1318c5bSMichal Berger fi 277c1318c5bSMichal Berger 278c1318c5bSMichal Berger cpufreq_cur_freqs[cpu_idx]=$(< "$cpu/cpufreq/scaling_cur_freq") 279c1318c5bSMichal Berger cpufreq_max_freqs[cpu_idx]=$(< "$cpu/cpufreq/scaling_max_freq") 280c1318c5bSMichal Berger cpufreq_min_freqs[cpu_idx]=$(< "$cpu/cpufreq/scaling_min_freq") 281c1318c5bSMichal Berger 282c1318c5bSMichal Berger local -n available_governors=available_governors_cpu_${cpu_idx} 283c1318c5bSMichal Berger cpufreq_available_governors[cpu_idx]="available_governors_cpu_${cpu_idx}[@]" 284c1318c5bSMichal Berger available_governors=($(< "$cpu/cpufreq/scaling_available_governors")) 285c1318c5bSMichal Berger 286c1318c5bSMichal Berger local -n available_freqs=available_freqs_cpu_${cpu_idx} 287c1318c5bSMichal Berger cpufreq_available_freqs[cpu_idx]="available_freqs_cpu_${cpu_idx}[@]" 288c1318c5bSMichal Berger 289c1318c5bSMichal Berger case "${cpufreq_drivers[cpu_idx]}" in 290c1318c5bSMichal Berger acpi-cpufreq) 291c1318c5bSMichal Berger available_freqs=($(< "$cpu/cpufreq/scaling_available_frequencies")) 292c1318c5bSMichal Berger if ((available_freqs[0] - 1000 == available_freqs[1])); then 293c1318c5bSMichal Berger cpufreq_is_turbo[cpu_idx]=1 294c1318c5bSMichal Berger else 295c1318c5bSMichal Berger cpufreq_is_turbo[cpu_idx]=0 296c1318c5bSMichal Berger fi 297c1318c5bSMichal Berger cpufreq_setspeed[cpu_idx]=$(< "$cpu/cpufreq/scaling_setspeed") 298c1318c5bSMichal Berger ;; 299c1318c5bSMichal Berger intel_pstate | intel_cpufreq) # active or passive 300c1318c5bSMichal Berger local non_turbo_ratio base_max_freq num_freq freq is_turbo=0 301c1318c5bSMichal Berger 302c1318c5bSMichal Berger non_turbo_ratio=$("$testdir/rdmsr.pl" "$cpu_idx" 0xce) 303c1318c5bSMichal Berger cpuinfo_min_freqs[cpu_idx]=$(< "$cpu/cpufreq/cpuinfo_min_freq") 304c1318c5bSMichal Berger cpuinfo_max_freqs[cpu_idx]=$(< "$cpu/cpufreq/cpuinfo_max_freq") 305c1318c5bSMichal Berger cpufreq_non_turbo_ratio[cpu_idx]=$(((non_turbo_ratio >> 8) & 0xff)) 306c1318c5bSMichal Berger if ((cpufreq_base_freqs[cpu_idx] / 100000 > cpufreq_non_turbo_ratio[cpu_idx])); then 307c1318c5bSMichal Berger cpufreq_high_prio[cpu_idx]=1 308c1318c5bSMichal Berger base_max_freq=${cpufreq_base_freqs[cpu_idx]} 309c1318c5bSMichal Berger else 310c1318c5bSMichal Berger cpufreq_high_prio[cpu_idx]=0 311c1318c5bSMichal Berger base_max_freq=$((cpufreq_non_turbo_ratio[cpu_idx] * 100000)) 312c1318c5bSMichal Berger fi 313c1318c5bSMichal Berger num_freqs=$(((base_max_freq - cpuinfo_min_freqs[cpu_idx]) / 100000 + 1)) 314c1318c5bSMichal Berger if ((base_max_freq < cpuinfo_max_freqs[cpu_idx])); then 315c1318c5bSMichal Berger ((num_freqs += 1)) 316c1318c5bSMichal Berger cpufreq_is_turbo[cpu_idx]=1 317c1318c5bSMichal Berger else 318c1318c5bSMichal Berger cpufreq_is_turbo[cpu_idx]=0 319c1318c5bSMichal Berger fi 320c1318c5bSMichal Berger available_freqs=() 321c1318c5bSMichal Berger for ((freq = 0; freq < num_freqs; freq++)); do 322c1318c5bSMichal Berger if ((freq == 0 && cpufreq_is_turbo[cpu_idx] == 1)); then 323c1318c5bSMichal Berger available_freqs[freq]=$((base_max_freq + 1)) 324c1318c5bSMichal Berger else 325c1318c5bSMichal Berger available_freqs[freq]=$((base_max_freq - (freq - cpufreq_is_turbo[cpu_idx]) * 100000)) 326c1318c5bSMichal Berger fi 327c1318c5bSMichal Berger done 328c1318c5bSMichal Berger ;; 329454561bfSRichael Zhuang cppc_cpufreq) 330454561bfSRichael Zhuang cpufreq_setspeed[cpu_idx]=$(< "$cpu/cpufreq/scaling_setspeed") 331454561bfSRichael Zhuang scaling_min_freqs[cpu_idx]=$(< "$cpu/cpufreq/scaling_min_freq") 332454561bfSRichael Zhuang scaling_max_freqs[cpu_idx]=$(< "$cpu/cpufreq/scaling_max_freq") 333454561bfSRichael Zhuang cpuinfo_max_freqs[cpu_idx]=$(< "$cpu/cpufreq/cpuinfo_max_freq") 334454561bfSRichael Zhuang nominal_perf[cpu_idx]=$(< "$cpu/acpi_cppc/nominal_perf") 335454561bfSRichael Zhuang highest_perf[cpu_idx]=$(< "$cpu/acpi_cppc/highest_perf") 336454561bfSRichael Zhuang 337454561bfSRichael Zhuang #the unit of highest_perf and nominal_perf differs on different arm platforms. 338454561bfSRichael Zhuang #For highest_perf, it maybe 300 or 3000000, both means 3.0GHz. 339454561bfSRichael Zhuang if ((highest_perf[cpu_idx] > nominal_perf[cpu_idx] && (\ 340454561bfSRichael Zhuang highest_perf[cpu_idx] == cpuinfo_max_freqs[cpu_idx] || \ 341454561bfSRichael Zhuang highest_perf[cpu_idx] * 10000 == cpuinfo_max_freqs[cpu_idx]))); then 342454561bfSRichael Zhuang cpufreq_is_turbo[cpu_idx]=1 343454561bfSRichael Zhuang else 344454561bfSRichael Zhuang cpufreq_is_turbo[cpu_idx]=0 345454561bfSRichael Zhuang fi 346454561bfSRichael Zhuang 347454561bfSRichael Zhuang if ((nominal_perf[cpu_idx] < 10000)); then 348454561bfSRichael Zhuang nominal_perf[cpu_idx]=$((nominal_perf[cpu_idx] * 10000)) 349454561bfSRichael Zhuang fi 350454561bfSRichael Zhuang 351454561bfSRichael Zhuang num_freqs=$(((nominal_perf[cpu_idx] - scaling_min_freqs[cpu_idx]) / 100000 + 1 + \ 352454561bfSRichael Zhuang cpufreq_is_turbo[cpu_idx])) 353454561bfSRichael Zhuang 354454561bfSRichael Zhuang available_freqs=() 355454561bfSRichael Zhuang for ((freq = 0; freq < num_freqs; freq++)); do 356454561bfSRichael Zhuang if ((freq == 0 && cpufreq_is_turbo[cpu_idx] == 1)); then 357454561bfSRichael Zhuang available_freqs[freq]=$((scaling_max_freqs[cpu_idx])) 358454561bfSRichael Zhuang else 359454561bfSRichael Zhuang available_freqs[freq]=$((nominal_perf[cpu_idx] - (\ 360454561bfSRichael Zhuang freq - cpufreq_is_turbo[cpu_idx]) * 100000)) 361454561bfSRichael Zhuang fi 362454561bfSRichael Zhuang done 363454561bfSRichael Zhuang ;; 364c1318c5bSMichal Berger esac 365c1318c5bSMichal Berger done 366c1318c5bSMichal Berger if [[ -e $sysfs_cpu/cpufreq/boost ]]; then 367c1318c5bSMichal Berger turbo_enabled=$(< "$sysfs_cpu/cpufreq/boost") 368c1318c5bSMichal Berger elif [[ -e $sysfs_cpu/intel_pstate/no_turbo ]]; then 369c1318c5bSMichal Berger turbo_enabled=$((!$(< "$sysfs_cpu/intel_pstate/no_turbo"))) 370c1318c5bSMichal Berger fi 371c1318c5bSMichal Berger} 372c1318c5bSMichal Berger 373c1318c5bSMichal Bergerset_cpufreq() { 374c1318c5bSMichal Berger local cpu=$1 375c1318c5bSMichal Berger local min_freq=$2 376c1318c5bSMichal Berger local max_freq=$3 377c1318c5bSMichal Berger local cpufreq=$sysfs_cpu/cpu$cpu/cpufreq 378c1318c5bSMichal Berger 379c1318c5bSMichal Berger # Map the cpufreq info first 380c1318c5bSMichal Berger [[ -n ${cpufreq_drivers[cpu]} ]] || return 1 381c1318c5bSMichal Berger [[ -n $min_freq ]] || return 1 382c1318c5bSMichal Berger 383c1318c5bSMichal Berger case "${cpufreq_drivers[cpu]}" in 3845971ef1dSRichael Zhuang acpi-cpufreq | cppc_cpufreq) 385dc32e1baSRichael Zhuang if [[ $(< "$cpufreq/scaling_governor") != userspace ]]; then 386dc32e1baSRichael Zhuang echo "userspace" > "$cpufreq/scaling_governor" 387c1318c5bSMichal Berger fi 388c1318c5bSMichal Berger echo "$min_freq" > "$cpufreq/scaling_setspeed" 389c1318c5bSMichal Berger ;; 390c1318c5bSMichal Berger intel_pstate | intel_cpufreq) 391c1318c5bSMichal Berger if [[ -n $max_freq ]] && ((max_freq >= min_freq)); then 392c1318c5bSMichal Berger echo "$max_freq" > "$cpufreq/scaling_max_freq" 393c1318c5bSMichal Berger fi 3947832b34fSMichal Berger if ((min_freq <= cpufreq_max_freqs[cpu])); then 3957832b34fSMichal Berger echo "$min_freq" > "$cpufreq/scaling_min_freq" 3967832b34fSMichal Berger fi 397c1318c5bSMichal Berger ;; 398c1318c5bSMichal Berger esac 399c1318c5bSMichal Berger} 400c313f1b2SMichal Berger 4011194f6ccSMichal Bergerset_cpufreq_governor() { 4021194f6ccSMichal Berger local cpu=$1 4031194f6ccSMichal Berger local governor=$2 4041194f6ccSMichal Berger local cpufreq=$sysfs_cpu/cpu$cpu/cpufreq 4051194f6ccSMichal Berger 4061194f6ccSMichal Berger if [[ $(< "$cpufreq/scaling_governor") != "$governor" ]]; then 4071194f6ccSMichal Berger echo "$governor" > "$cpufreq/scaling_governor" 4081194f6ccSMichal Berger fi 4091194f6ccSMichal Berger} 4101194f6ccSMichal Berger 411c313f1b2SMichal Bergerexec_under_dynamic_scheduler() { 412d841e24bSMichal Berger if [[ -e /proc/$spdk_pid/status ]]; then 413d841e24bSMichal Berger killprocess "$spdk_pid" 414d841e24bSMichal Berger fi 4158571999dSMichal Berger "$@" --wait-for-rpc & 416c313f1b2SMichal Berger spdk_pid=$! 417c313f1b2SMichal Berger # Give some time for the app to init itself 418c313f1b2SMichal Berger waitforlisten "$spdk_pid" 419c313f1b2SMichal Berger "$rootdir/scripts/rpc.py" framework_set_scheduler dynamic 420c313f1b2SMichal Berger "$rootdir/scripts/rpc.py" framework_start_init 421c313f1b2SMichal Berger} 422c313f1b2SMichal Berger 4234e4b993aSSeungYeon Shinexec_under_static_scheduler() { 4244e4b993aSSeungYeon Shin if [[ -e /proc/$spdk_pid/status ]]; then 4254e4b993aSSeungYeon Shin killprocess "$spdk_pid" 4264e4b993aSSeungYeon Shin fi 4274e4b993aSSeungYeon Shin "$@" --wait-for-rpc & 4284e4b993aSSeungYeon Shin spdk_pid=$! 4294e4b993aSSeungYeon Shin # Give some time for the app to init itself 4304e4b993aSSeungYeon Shin waitforlisten "$spdk_pid" 4314e4b993aSSeungYeon Shin} 4324e4b993aSSeungYeon Shin 43319377d66STomasz Zawadzki# Gather busy/idle stats since this function was last called 43419377d66STomasz Zawadzkiget_thread_stats_current() { 43519377d66STomasz Zawadzki xtrace_disable 43619377d66STomasz Zawadzki 43719377d66STomasz Zawadzki local total_busy total_idle 43819377d66STomasz Zawadzki 43919377d66STomasz Zawadzki _get_thread_stats total_busy total_idle 44019377d66STomasz Zawadzki 44119377d66STomasz Zawadzki for thread in "${!thread_map[@]}"; do 44219377d66STomasz Zawadzki : $((busy[thread] = total_busy[thread] - past_busy[thread], past_busy[thread] = total_busy[thread])) 44319377d66STomasz Zawadzki : $((idle[thread] = total_idle[thread] - past_idle[thread], past_idle[thread] = total_idle[thread])) 44419377d66STomasz Zawadzki done 44519377d66STomasz Zawadzki xtrace_restore 44619377d66STomasz Zawadzki} 44719377d66STomasz Zawadzki 44819377d66STomasz Zawadzki# Gather busy/idle stats since application start 449c313f1b2SMichal Bergerget_thread_stats() { 450c313f1b2SMichal Berger xtrace_disable 451c313f1b2SMichal Berger _get_thread_stats busy idle 452c313f1b2SMichal Berger xtrace_restore 453c313f1b2SMichal Berger} 454c313f1b2SMichal Berger 455c313f1b2SMichal Berger_get_thread_stats() { 456c313f1b2SMichal Berger local list_busy=$1 457c313f1b2SMichal Berger local list_idle=$2 458c313f1b2SMichal Berger local thread threads stats 459c313f1b2SMichal Berger 460c313f1b2SMichal Berger stats=$(rpc_cmd thread_get_stats | jq -r '.threads[]') 461c313f1b2SMichal Berger threads=($(jq -r '.id' <<< "$stats")) 462c313f1b2SMichal Berger 463c313f1b2SMichal Berger for thread in "${threads[@]}"; do 464c313f1b2SMichal Berger eval "${list_busy}[$thread]=\$(jq -r \"select(.id == $thread) | .busy\" <<< \$stats)" 465c313f1b2SMichal Berger eval "${list_idle}[$thread]=\$(jq -r \"select(.id == $thread) | .idle\" <<< \$stats)" 466c313f1b2SMichal Berger thread_map[thread]=$(jq -r "select(.id == $thread) | .name" <<< "$stats") 467c313f1b2SMichal Berger done 468c313f1b2SMichal Berger} 469049d587eSMichal Berger 470049d587eSMichal Bergerget_cpu_stat() { 471049d587eSMichal Berger local cpu_idx=$1 4720ea89560SMichal Berger local stat=$2 stats astats 473049d587eSMichal Berger 47459c811f0SMichal Berger # cpu0 0 0 0 0 0 0 0 0 0 -> _cpu0=(0 0 0 0 0 0 0 0 0) 47559c811f0SMichal Berger source <(grep '^cpu[0-9]' /proc/stat | sed 's/\([^ ]*\) \(.*\)/_\1=(\2)/') 47659c811f0SMichal Berger 47759c811f0SMichal Berger # If we were called with valid cpu id return requested time 47859c811f0SMichal Berger [[ -v _cpu$cpu_idx ]] || return 0 47959c811f0SMichal Berger local -n cpu_stat=_cpu$cpu_idx 480049d587eSMichal Berger 481049d587eSMichal Berger case "$stat" in 48259c811f0SMichal Berger idle) echo "${cpu_stat[3]}" ;; 48359c811f0SMichal Berger *) printf '%u\n' "${cpu_stat[@]}" ;; 484049d587eSMichal Berger esac 485049d587eSMichal Berger} 486049d587eSMichal Berger 487049d587eSMichal Bergercreate_thread() { 4887347f60bSMichal Berger rpc_cmd --plugin "$plugin" scheduler_thread_create "$@" 489049d587eSMichal Berger} 490049d587eSMichal Berger 491049d587eSMichal Bergerdestroy_thread() { 4927347f60bSMichal Berger rpc_cmd --plugin "$plugin" scheduler_thread_delete "$@" 493049d587eSMichal Berger} 494049d587eSMichal Berger 495049d587eSMichal Bergeractive_thread() { 4967347f60bSMichal Berger rpc_cmd --plugin "$plugin" scheduler_thread_set_active "$@" 497049d587eSMichal Berger} 4980ea89560SMichal Berger 4990ea89560SMichal Bergerget_cpu_time() { 5000ea89560SMichal Berger xtrace_disable 5010ea89560SMichal Berger 50236eea926SMichal Berger local interval=$1 cpu_time=${2:-idle} print=${3:-0} wait=${4:-1} interval_count 50336eea926SMichal Berger shift 4 5040ea89560SMichal Berger local cpus=("$@") cpu 5050ea89560SMichal Berger local stats stat old_stats avg_load 5060ea89560SMichal Berger local total_sample 50759c811f0SMichal Berger local keep_going=0 5080ea89560SMichal Berger 5090ea89560SMichal Berger # Exposed for the caller 5100ea89560SMichal Berger local -g cpu_times=() 5110ea89560SMichal Berger local -g avg_cpu_time=() 5120ea89560SMichal Berger 5130ea89560SMichal Berger # cpu_time: 5140ea89560SMichal Berger # 0 - user (time spent in user mode) 5150ea89560SMichal Berger # 1 - nice (Time spent in user mode with low priority) 5160ea89560SMichal Berger # 2 - system (Time spent in system mode) 5170ea89560SMichal Berger # 3 - idle (Time spent in the idle task) 5180ea89560SMichal Berger # 4 - iowait (Time waiting for I/O to complete) 5190ea89560SMichal Berger # 5 - irq (Time servicing interrupts) 5200ea89560SMichal Berger # 6 - softirq (Time servicing softirqs) 5210ea89560SMichal Berger # 7 - steal (Stolen time) 5220ea89560SMichal Berger # 8 - guest (Time spent running a virtual CPU) 5230ea89560SMichal Berger # 9 - guest_nice (Time spent running a niced guest) 5240ea89560SMichal Berger 5259b893966SMichal Berger local -gA cpu_time_map 5260ea89560SMichal Berger cpu_time_map["user"]=0 5270ea89560SMichal Berger cpu_time_map["nice"]=1 5280ea89560SMichal Berger cpu_time_map["system"]=2 5290ea89560SMichal Berger cpu_time_map["idle"]=3 5300ea89560SMichal Berger cpu_time_map["iowait"]=4 5310ea89560SMichal Berger cpu_time_map["irq"]=5 5320ea89560SMichal Berger cpu_time_map["softirq"]=6 5330ea89560SMichal Berger cpu_time_map["steal"]=7 5340ea89560SMichal Berger cpu_time_map["guest"]=8 5350ea89560SMichal Berger cpu_time_map["guest_nice"]=9 5360ea89560SMichal Berger 5370ea89560SMichal Berger # Clear up the env 5380ea89560SMichal Berger unset -v ${!stat_@} 5390ea89560SMichal Berger unset -v ${!old_stat_@} 5400ea89560SMichal Berger unset -v ${!avg_stat@} 5410ea89560SMichal Berger unset -v ${!avg_load@} 5429b893966SMichal Berger unset -v ${!raw_samples@} 5430ea89560SMichal Berger 5447d080339SMichal Berger cpu_time=${cpu_time_map["$cpu_time"]} 54559c811f0SMichal Berger interval_count=0 54659c811f0SMichal Berger if ((interval <= 0)); then 54759c811f0SMichal Berger keep_going=1 54859c811f0SMichal Berger else 549c9c7c281SJosh Soref # We skip first sample to have min 2 for stat comparison 55059c811f0SMichal Berger interval=$((interval + 1)) 55159c811f0SMichal Berger fi 55259c811f0SMichal Berger while ((interval_count++, keep_going ? 1 : --interval >= 0)); do 55359c811f0SMichal Berger ((interval_count > 1 && print == 1)) && print_cpu_time_header 55459c811f0SMichal Berger get_cpu_stat all 5550ea89560SMichal Berger for cpu in "${cpus[@]}"; do 5560ea89560SMichal Berger local -n old_stats=old_stats_$cpu 5570ea89560SMichal Berger local -n avg_load=avg_load_$cpu 5589b893966SMichal Berger local -n raw_samples=raw_samples_$cpu 55959c811f0SMichal Berger local -n stats=_cpu$cpu 5600ea89560SMichal Berger sample_stats=() total_sample=0 5610ea89560SMichal Berger 5620ea89560SMichal Berger if ((interval_count == 1)); then 5630ea89560SMichal Berger # Skip first sample 5640ea89560SMichal Berger old_stats=("${stats[@]}") 5650ea89560SMichal Berger continue 5660ea89560SMichal Berger fi 5670ea89560SMichal Berger for stat in "${!stats[@]}"; do 5680ea89560SMichal Berger avg_load[stat]="stat_${stat}_${cpu}[@]" 5690ea89560SMichal Berger sample_stats[stat]=$((stats[stat] - old_stats[stat])) 5700ea89560SMichal Berger : $((total_sample += sample_stats[stat])) 5710ea89560SMichal Berger done 5720ea89560SMichal Berger for stat in "${!stats[@]}"; do 5730ea89560SMichal Berger local -n avg_stat=stat_${stat}_${cpu} 5749b893966SMichal Berger local -n raw_samples_ref=raw_samples_${stat}_${cpu} 5759b893966SMichal Berger raw_samples[stat]="raw_samples_${stat}_${cpu}[@]" 5769b893966SMichal Berger raw_samples_ref+=("${stats[stat]}") 5770ea89560SMichal Berger avg_stat+=($((sample_stats[stat] * 100 / (total_sample == 0 ? 1 : total_sample)))) 5780ea89560SMichal Berger done 5790ea89560SMichal Berger old_stats=("${stats[@]}") 58059c811f0SMichal Berger ((print == 1)) && print_cpu_time "$cpu" 5810ea89560SMichal Berger done 58236eea926SMichal Berger sleep "${wait}s" 5830ea89560SMichal Berger done 5840ea89560SMichal Berger 5850ea89560SMichal Berger # We collected % for each time. Now determine the avg % for requested time. 5860ea89560SMichal Berger local load stat_load 5870ea89560SMichal Berger for cpu in "${cpus[@]}"; do 5880ea89560SMichal Berger load=0 5890ea89560SMichal Berger local -n avg_load_cpu=avg_load_$cpu 5900ea89560SMichal Berger stat_load=("${!avg_load_cpu[cpu_time]}") 5910ea89560SMichal Berger for stat in "${stat_load[@]}"; do 5920ea89560SMichal Berger : $((load += stat)) 5930ea89560SMichal Berger done 5940ea89560SMichal Berger cpu_times[cpu]=${stat_load[*]} 5950ea89560SMichal Berger avg_cpu_time[cpu]=$((load / ${#stat_load[@]})) 5960ea89560SMichal Berger done 5970ea89560SMichal Berger 5980ea89560SMichal Berger xtrace_restore 5990ea89560SMichal Berger} 600330e9f77SMichal Berger 60159c811f0SMichal Bergerprint_cpu_time_header() { 60259c811f0SMichal Berger local ts 60399bebaceSMichal Berger ts=$(date "+%R:%S %Z") 60459c811f0SMichal Berger 6058d588fbcSMichal Berger printf '(%s) %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s %8s (test:%s)\n' \ 60659c811f0SMichal Berger "$ts" \ 60759c811f0SMichal Berger "CPU" "%usr" "%nice" "%sys" "%iowait" "%irq" "%soft" "%steal" \ 6088d588fbcSMichal Berger "%guest" "%gnice" "%idle" "${TEST_TAG:-N/A}" 60959c811f0SMichal Berger} 61059c811f0SMichal Berger 61159c811f0SMichal Bergerprint_cpu_time() { 61259c811f0SMichal Berger local cpu=$1 61359c811f0SMichal Berger 61459c811f0SMichal Berger local -n _cpu_ref=avg_load_$cpu 61559c811f0SMichal Berger ((${#_cpu_ref[@]} > 0)) || return 0 61659c811f0SMichal Berger 61759c811f0SMichal Berger usr=("${!_cpu_ref[0]}") 61859c811f0SMichal Berger nice=("${!_cpu_ref[1]}") 61959c811f0SMichal Berger system=("${!_cpu_ref[2]}") 62059c811f0SMichal Berger idle=("${!_cpu_ref[3]}") 62159c811f0SMichal Berger iowait=("${!_cpu_ref[4]}") 62259c811f0SMichal Berger irq=("${!_cpu_ref[5]}") 62359c811f0SMichal Berger soft=("${!_cpu_ref[6]}") 62459c811f0SMichal Berger steal=("${!_cpu_ref[7]}") 62559c811f0SMichal Berger guest=("${!_cpu_ref[8]}") 62659c811f0SMichal Berger gnice=("${!_cpu_ref[9]}") 62759c811f0SMichal Berger 62899bebaceSMichal Berger printf '%23u %8u %8u %8u %8u %8u %8u %8u %8u %8u %8u\n' \ 62959c811f0SMichal Berger "$cpu" \ 63059c811f0SMichal Berger "${usr[-1]}" \ 63159c811f0SMichal Berger "${nice[-1]}" \ 63259c811f0SMichal Berger "${system[-1]}" \ 63359c811f0SMichal Berger "${iowait[-1]}" \ 63459c811f0SMichal Berger "${irq[-1]}" \ 63559c811f0SMichal Berger "${soft[-1]}" \ 63659c811f0SMichal Berger "${steal[-1]}" \ 63759c811f0SMichal Berger "${guest[-1]}" \ 63859c811f0SMichal Berger "${gnice[-1]}" \ 63959c811f0SMichal Berger "${idle[-1]}" 64059c811f0SMichal Berger} 64159c811f0SMichal Berger 642330e9f77SMichal Bergercollect_cpu_idle() { 643330e9f77SMichal Berger ((${#cpus_to_collect[@]} > 0)) || return 1 644330e9f77SMichal Berger 645330e9f77SMichal Berger local time=${1:-5} 646330e9f77SMichal Berger local cpu 647330e9f77SMichal Berger local samples 648330e9f77SMichal Berger local -g is_idle=() 649330e9f77SMichal Berger 650330e9f77SMichal Berger printf 'Collecting cpu idle stats (cpus: %s) for %u seconds...\n' \ 651330e9f77SMichal Berger "${cpus_to_collect[*]}" "$time" 652330e9f77SMichal Berger 65336eea926SMichal Berger get_cpu_time "$time" idle 0 1 "${cpus_to_collect[@]}" 654330e9f77SMichal Berger 6557b52e4c1SMichal Berger local user_load load_median user_spdk_load 656330e9f77SMichal Berger for cpu in "${cpus_to_collect[@]}"; do 657330e9f77SMichal Berger samples=(${cpu_times[cpu]}) 6581dc06520SMichal Berger load_median=$(calc_median "${samples[@]}") 6591dc06520SMichal Berger printf '* cpu%u idle samples: %s (avg: %u%%, median: %u%%)\n' \ 6601dc06520SMichal Berger "$cpu" "${samples[*]}" "${avg_cpu_time[cpu]}" "$load_median" 661330e9f77SMichal Berger # Cores with polling reactors have 0% idle time, 662330e9f77SMichal Berger # while the ones in interrupt mode won't have 100% idle. 6639b893966SMichal Berger # During the tests, polling reactors spend the major portion 6649b893966SMichal Berger # of their cpu time in user mode. With that in mind, if the 6659b893966SMichal Berger # general check for cpus's idleness fails, check what portion 6669b893966SMichal Berger # of the cpu load falls into user mode. For the idle check 6679b893966SMichal Berger # use the last sample. For the cpu load, compare user's raw 6689b893966SMichal Berger # samples in SC_CLK_TCK context for a more detailed view. 6699b893966SMichal Berger user_load=$(cpu_usage_clk_tck "$cpu" user) 670330e9f77SMichal Berger if ((samples[-1] >= 70)); then 671330e9f77SMichal Berger printf '* cpu%u is idle\n' "$cpu" 672330e9f77SMichal Berger is_idle[cpu]=1 6739b893966SMichal Berger elif ((user_load <= 15)); then 6749b893966SMichal Berger printf '* cpu%u not fully idle, but user load is low so passing\n' "$cpu" 6759b893966SMichal Berger is_idle[cpu]=1 676330e9f77SMichal Berger else 677330e9f77SMichal Berger printf '* cpu%u is not idle\n' "$cpu" 678330e9f77SMichal Berger is_idle[cpu]=0 6797b52e4c1SMichal Berger # HACK: Since we verify this in context of business of particular SPDK threads, make 6807b52e4c1SMichal Berger # the last check against their {u,s}time to determine if we are really busy or not. This 6817b52e4c1SMichal Berger # is meant to null and void potential jitter on the cpu. 6827b52e4c1SMichal Berger # See https://github.com/spdk/spdk/issues/3362. 6837b52e4c1SMichal Berger user_spdk_load=$(get_spdk_proc_time "$time" "$cpu") 6847b52e4c1SMichal Berger if ((user_spdk_load <= 15)); then 6857b52e4c1SMichal Berger printf '* SPDK thread pinned to cpu%u seems to be idle regardless (%u%%)\n' \ 6867b52e4c1SMichal Berger "$cpu" \ 6877b52e4c1SMichal Berger "$user_spdk_load" 6887b52e4c1SMichal Berger is_idle[cpu]=1 6897b52e4c1SMichal Berger fi 690330e9f77SMichal Berger fi 691330e9f77SMichal Berger done 692330e9f77SMichal Berger} 693d841e24bSMichal Berger 6949b893966SMichal Bergercpu_usage_clk_tck() { 6959b893966SMichal Berger local cpu=$1 time=${2:-all} 6969b893966SMichal Berger local user nice system usage clk_delta 6979b893966SMichal Berger 6989b893966SMichal Berger # We should be called in get_cpu_time()'s environment. 6999b893966SMichal Berger [[ -v raw_samples_$cpu ]] || return 1 7009b893966SMichal Berger 7019b893966SMichal Berger local -n raw_samples=raw_samples_$cpu 7029b893966SMichal Berger user=("${!raw_samples[cpu_time_map["user"]]}") 7039b893966SMichal Berger nice=("${!raw_samples[cpu_time_map["nice"]]}") 7049b893966SMichal Berger system=("${!raw_samples[cpu_time_map["system"]]}") 7059b893966SMichal Berger 7069b893966SMichal Berger # Construct delta based on last two samples of a given time. 7079b893966SMichal Berger case "$time" in 708b24df7cfSMichal Berger user | all) : $((clk_delta += (user[-1] - user[-2]))) ;;& 709b24df7cfSMichal Berger nice | all) : $((clk_delta += (nice[-1] - nice[-2]))) ;;& 710b24df7cfSMichal Berger system | all) : $((clk_delta += (system[-1] - system[-2]))) ;; 7119b893966SMichal Berger *) ;; 7129b893966SMichal Berger esac 7139b893966SMichal Berger # We assume 1s between each sample. See get_cpu_time(). 7149b893966SMichal Berger usage=$((100 * clk_delta / $(getconf CLK_TCK))) 7159b893966SMichal Berger usage=$((usage > 100 ? 100 : usage)) 7169b893966SMichal Berger 7179b893966SMichal Berger printf '%u' "$usage" 7189b893966SMichal Berger printf '* cpu%u %s usage: %u\n' "$cpu" "$time" "$usage" >&2 7199b893966SMichal Berger printf '* cpu%u user samples: %s\n' "$cpu" "${user[*]}" >&2 7209b893966SMichal Berger printf '* cpu%u nice samples: %s\n' "$cpu" "${nice[*]}" >&2 7219b893966SMichal Berger printf '* cpu%u system samples: %s\n' "$cpu" "${system[*]}" >&2 7229b893966SMichal Berger} 7239b893966SMichal Berger 724d841e24bSMichal Bergerupdate_thread_cpus_map() { 725d841e24bSMichal Berger local cpu 726d841e24bSMichal Berger local -g thread_cpus=() 727d841e24bSMichal Berger local reactor_framework 728d841e24bSMichal Berger 729d841e24bSMichal Berger ((${#cpus[@]} > 0)) || return 1 730d841e24bSMichal Berger 731d841e24bSMichal Berger get_thread_stats 732d841e24bSMichal Berger 733d841e24bSMichal Berger reactor_framework=$(rpc_cmd framework_get_reactors | jq -r '.reactors[]') 734d841e24bSMichal Berger for cpu in "${cpus[@]}"; do 735d841e24bSMichal Berger for thread in $(jq -r "select(.lcore == $cpu) | .lw_threads[].id" <<< "$reactor_framework"); do 736d841e24bSMichal Berger printf '* Thread %u (%s) on cpu%u\n' "$thread" "${thread_map[thread]}" "$cpu" 737d841e24bSMichal Berger thread_cpus[thread]=$cpu 738d841e24bSMichal Berger done 739d841e24bSMichal Berger done 740d841e24bSMichal Berger ((${#thread_cpus[@]} > 0)) 741d841e24bSMichal Berger} 7421dc06520SMichal Berger 7431dc06520SMichal Bergercalc_median() { 7441dc06520SMichal Berger local samples=("$@") samples_sorted 7451dc06520SMichal Berger local middle median sample 7461dc06520SMichal Berger 7471dc06520SMichal Berger samples_sorted=($(printf '%s\n' "${samples[@]}" | sort -n)) 7481dc06520SMichal Berger 7491dc06520SMichal Berger middle=$((${#samples_sorted[@]} / 2)) 7501dc06520SMichal Berger if ((${#samples_sorted[@]} % 2 == 0)); then 7511dc06520SMichal Berger median=$(((samples_sorted[middle - 1] + samples_sorted[middle]) / 2)) 7521dc06520SMichal Berger else 7531dc06520SMichal Berger median=${samples_sorted[middle]} 7541dc06520SMichal Berger fi 7551dc06520SMichal Berger 7561dc06520SMichal Berger echo "$median" 7571dc06520SMichal Berger 7581dc06520SMichal Berger} 7597b52e4c1SMichal Berger 7607b52e4c1SMichal Bergerget_spdk_proc_time() { 7617b52e4c1SMichal Berger # Similar to cpu_usage_clk_tck() but the values we are working here, per process, are already 7627b52e4c1SMichal Berger # divided by SC_CLK_TCK. See proc(5). 7637b52e4c1SMichal Berger 7647b52e4c1SMichal Berger xtrace_disable 7657b52e4c1SMichal Berger 7667b52e4c1SMichal Berger local interval=$1 cpu=$2 7677b52e4c1SMichal Berger local thread thread_to_time stats 7687b52e4c1SMichal Berger local _time time _stime stime _utime utime 7690b65bb47SMichal Berger local thread_cpu_list 7707b52e4c1SMichal Berger 7717b52e4c1SMichal Berger [[ -e /proc/$spdk_pid/status ]] || return 1 7727b52e4c1SMichal Berger 7737b52e4c1SMichal Berger # Find SPDK thread pinned to given cpu 7747b52e4c1SMichal Berger for thread in "/proc/$spdk_pid/task/"*; do 7750b65bb47SMichal Berger thread_cpu_list=($(get_proc_cpu_affinity "$thread/status")) 7760b65bb47SMichal Berger # we aim at reactor threads and these should be bound to a single cpu 7770b65bb47SMichal Berger ((${#thread_cpu_list[@]} > 1)) && continue 7780b65bb47SMichal Berger ((thread_cpu_list[0] == cpu)) && thread_to_time=$thread && break 7797b52e4c1SMichal Berger done 7807b52e4c1SMichal Berger 7817b52e4c1SMichal Berger [[ -e $thread_to_time/stat ]] || return 1 7827b52e4c1SMichal Berger interval=$((interval <= 1 ? 2 : interval)) 7837b52e4c1SMichal Berger 7847b52e4c1SMichal Berger while ((--interval >= 0)); do 7857b52e4c1SMichal Berger # See cgroups.sh -> id_proc() 7867b52e4c1SMichal Berger stats=$(< "$thread_to_time/stat") stats=(${stats/*) /}) 7877b52e4c1SMichal Berger _utime[interval]=${stats[11]} # Amount of time spent in user mode 7887b52e4c1SMichal Berger _stime[interval]=${stats[12]} # Amount of time spent in kernel mode 7897b52e4c1SMichal Berger _time[interval]=$((_utime[interval] + _stime[interval])) 7907b52e4c1SMichal Berger ((${#_time[@]} == 1)) && continue 7917b52e4c1SMichal Berger utime+=($((_utime[interval] - _utime[interval + 1]))) 7927b52e4c1SMichal Berger stime+=($((_stime[interval] - _stime[interval + 1]))) 7937b52e4c1SMichal Berger time+=($((_time[interval] - _time[interval + 1]))) 7947b52e4c1SMichal Berger sleep 1 7957b52e4c1SMichal Berger done 7967b52e4c1SMichal Berger 7977b52e4c1SMichal Berger echo "stime samples: ${stime[*]}" >&2 7987b52e4c1SMichal Berger echo "utime samples: ${utime[*]}" >&2 7997b52e4c1SMichal Berger 8007b52e4c1SMichal Berger calc_median "${time[@]}" 8017b52e4c1SMichal Berger 8027b52e4c1SMichal Berger xtrace_restore 8037b52e4c1SMichal Berger} 804