1#!/usr/bin/env bash 2# SPDX-License-Identifier: BSD-3-Clause 3# Copyright (C) 2020 Intel Corporation 4# All rights reserved. 5# 6testdir=$(readlink -f "$(dirname "$0")") 7rootdir=$(readlink -f "$testdir/../../") 8 9source "$rootdir/test/common/autotest_common.sh" 10source "$testdir/common.sh" 11 12trap 'killprocess "$spdk_pid" || :; restore_cpufreq' EXIT 13 14restore_cpufreq() { 15 local cpu 16 17 for cpu in "$spdk_main_core" "${cpus[@]}"; do 18 set_cpufreq "$cpu" "$main_core_min_freq" "$main_core_max_freq" 19 set_cpufreq_governor "$cpu" "$initial_main_core_governor" 20 done 21} 22 23update_main_core_cpufreq() { 24 map_cpufreq 25 26 main_core_driver=${cpufreq_drivers[spdk_main_core]} 27 main_core_governor=${cpufreq_governors[spdk_main_core]} 28 main_core_set_min_freq=${cpufreq_min_freqs[spdk_main_core]} 29 main_core_set_cur_freq=${cpufreq_cur_freqs[spdk_main_core]} 30 main_core_set_max_freq=${cpufreq_max_freqs[spdk_main_core]} 31 32 if ((${#main_core_freqs[@]} == 0)); then 33 main_core_freqs=("${!cpufreq_available_freqs[spdk_main_core]}") 34 main_core_max_freq=${main_core_freqs[0]} 35 main_core_min_freq=${main_core_freqs[-1]} 36 fi 37 if ((${#main_core_freqs_map[@]} == 0)); then 38 fold_list_onto_array main_core_freqs_map "${main_core_freqs[@]}" 39 fi 40 41 case "$main_core_driver" in 42 acpi-cpufreq) main_core_setspeed=${cpufreq_setspeed[spdk_main_core]} ;; 43 intel_pstate | intel_cpufreq) main_core_setspeed=$main_core_set_max_freq ;; 44 cppc_cpufreq) main_core_setspeed=${cpufreq_setspeed[spdk_main_core]} ;; 45 esac 46 47 local thread 48 for thread in "${!cpu_siblings[spdk_main_core]}"; do 49 ((thread == spdk_main_core)) && continue # handled by DPDK/scheduler 50 # While assigning cpus to SPDK, we took every thread from given core, 51 # hence the cpufreq governor should already be properly set by the 52 # DPDK. So the only thing we need to take care of is {max,min} freq. 53 # The expectation here is to see actual freq drop on the main cpu in 54 # next iterations. Both, max and min, should be set to the same value. 55 set_cpufreq "$thread" "$main_core_set_min_freq" "$main_core_set_max_freq" 56 done 57} 58 59verify_dpdk_governor() { 60 xtrace_disable 61 62 map_cpus 63 # Run the app and see if DPDK's PM subsystem is doing the proper thing. Aim at the main core. 64 # What we expect to happen is based mainly on what cpufreq driver is in use. The main assumption 65 # is that with all SPDK threads being idle the governor should start lowering the frequency for 66 # the main core. 67 # - acpi-cpufreq: 68 # - governor set to userspace 69 # - lowering setspeed for the main core 70 # - having setspeed at lowest supported frequency 71 # - intel_pstate (active or passive) 72 # - governor set to performance 73 # - lowering max_freq and min_freq for the main core 74 # - having max_freq and min_freq at lowest supported frequency 75 # - cppc_cpufreq: 76 # - governor set to userspace 77 # - lowering setspeed for the main core 78 # - having setspeed at lowest supported frequency 79 80 local -g cpus 81 82 local dir_map 83 dir_map[0]="<" 84 dir_map[1]=">" 85 dir_map[2]="==" 86 87 fold_list_onto_array cpus $(parse_cpu_list <(echo "$spdk_cpus_csv")) 88 # Get rid of the main core 89 unset -v "cpus[spdk_main_core]" 90 91 local samples=0 all_set=0 dir=-1 old_main_core_setspeed=0 92 local old_main_core_set_cur_freq=0 first_main_core_set_cur_freq=0 93 94 exec_under_dynamic_scheduler "${SPDK_APP[@]}" -m "$spdk_cpumask" --main-core "$spdk_main_core" 95 96 while ((all_set == 0 && samples++ <= 50)); do 97 update_main_core_cpufreq 98 99 if [[ $main_core_setspeed == "<unsupported>" ]]; then 100 # governor hasn't taken over yet, skip this sample 101 printf 'Waiting for DPDK governor to take over...\n' 102 continue 103 fi 104 105 if ((main_core_setspeed > old_main_core_setspeed)); then 106 dir=1 107 elif ((main_core_setspeed < old_main_core_setspeed)); then 108 dir=0 109 elif ((main_core_setspeed == old_main_core_setspeed)); then 110 # Frequency didn't change, wait for a bit, but then fall to the main check to 111 # see if cur freq actually changed or not. 112 sleep 0.5s 113 fi 114 115 if ((first_main_core_set_cur_freq == 0)); then 116 first_main_core_set_cur_freq=$main_core_set_cur_freq 117 fi 118 119 case "$main_core_driver" in 120 acpi-cpufreq | cppc_cpufreq) 121 [[ $main_core_governor == userspace ]] \ 122 && [[ -n ${main_core_freqs_map[main_core_setspeed]} ]] \ 123 && ((main_core_setspeed == main_core_freqs[-1])) \ 124 && ((dir == 0)) 125 ;; 126 intel_pstate | intel_cpufreq) 127 [[ $main_core_governor == performance ]] \ 128 && [[ -n ${main_core_freqs_map[main_core_setspeed]} ]] \ 129 && ((main_core_setspeed == main_core_freqs[-1])) \ 130 && ((main_core_set_max_freq == main_core_set_min_freq)) \ 131 && ((dir == 0)) 132 ;; 133 esac && ((main_core_set_cur_freq < old_main_core_set_cur_freq)) && all_set=1 134 135 # Print stats after first sane sample was taken 136 if ((old_main_core_setspeed != 0 && dir != -1)); then 137 printf 'MAIN DPDK cpu%u current frequency at %u KHz (%u-%u KHz), set frequency %u KHz %s %u KHz\n' \ 138 "$spdk_main_core" "$main_core_set_cur_freq" "$main_core_min_freq" "$main_core_max_freq" \ 139 "$main_core_setspeed" "${dir_map[dir]}" "$old_main_core_setspeed" 140 else 141 printf 'Waiting for samples...\n' 142 fi 143 144 old_main_core_setspeed=$main_core_setspeed 145 old_main_core_set_cur_freq=$main_core_set_cur_freq 146 done 147 148 ((all_set == 1)) 149 150 printf 'Main cpu%u frequency dropped by %u%%\n' \ 151 "$spdk_main_core" \ 152 $(((first_main_core_set_cur_freq - main_core_set_cur_freq) * 100 / (first_main_core_set_cur_freq - main_core_min_freq))) 153 154 xtrace_restore 155} 156 157map_cpufreq 158# Save initial scaling governor to restore it later on 159initial_main_core_governor=${cpufreq_governors[spdk_main_core]} 160 161verify_dpdk_governor 162