#!/usr/bin/env bash # SPDX-License-Identifier: BSD-3-Clause # Copyright (C) 2020 Intel Corporation # All rights reserved. # testdir=$(readlink -f "$(dirname "$0")") rootdir=$(readlink -f "$testdir/../../") source "$rootdir/test/common/autotest_common.sh" source "$testdir/common.sh" trap 'killprocess "$spdk_pid" || :; restore_cpufreq' EXIT restore_cpufreq() { local cpu for cpu in "$spdk_main_core" "${cpus[@]}"; do set_cpufreq "$cpu" "$main_core_min_freq" "$main_core_max_freq" set_cpufreq_governor "$cpu" "$initial_main_core_governor" done } update_main_core_cpufreq() { map_cpufreq main_core_driver=${cpufreq_drivers[spdk_main_core]} main_core_governor=${cpufreq_governors[spdk_main_core]} main_core_set_min_freq=${cpufreq_min_freqs[spdk_main_core]} main_core_set_cur_freq=${cpufreq_cur_freqs[spdk_main_core]} main_core_set_max_freq=${cpufreq_max_freqs[spdk_main_core]} if ((${#main_core_freqs[@]} == 0)); then main_core_freqs=("${!cpufreq_available_freqs[spdk_main_core]}") main_core_max_freq=${main_core_freqs[0]} main_core_min_freq=${main_core_freqs[-1]} fi if ((${#main_core_freqs_map[@]} == 0)); then fold_list_onto_array main_core_freqs_map "${main_core_freqs[@]}" fi case "$main_core_driver" in acpi-cpufreq) main_core_setspeed=${cpufreq_setspeed[spdk_main_core]} ;; intel_pstate | intel_cpufreq) main_core_setspeed=$main_core_set_max_freq ;; cppc_cpufreq) main_core_setspeed=${cpufreq_setspeed[spdk_main_core]} ;; esac } verify_dpdk_governor() { xtrace_disable # Run the app and see if DPDK's PM subsystem is doing the proper thing. Aim at the main core. # What we expect to happen is based mainly on what cpufreq driver is in use. The main assumption # is that with all SPDK threads being idle the governor should start lowering the frequency for # the main core. # - acpi-cpufreq: # - governor set to userspace # - lowering setspeed for the main core # - having setspeed at lowest supported frequency # - intel_pstate (active or passive) # - governor set to performance # - lowering max_freq and min_freq for the main core # - having max_freq and min_freq at lowest supported frequency # - cppc_cpufreq: # - governor set to userspace # - lowering setspeed for the main core # - having setspeed at lowest supported frequency local -g cpus local dir_map dir_map[0]="<" dir_map[1]=">" dir_map[2]="==" fold_list_onto_array cpus $(parse_cpu_list <(echo "$spdk_cpus_csv")) # Get rid of the main core unset -v "cpus[spdk_main_core]" local samples=0 all_set=0 dir=-1 old_main_core_setspeed=0 exec_under_dynamic_scheduler "${SPDK_APP[@]}" -m "$spdk_cpumask" --main-core "$spdk_main_core" while ((all_set == 0 && samples++ <= 50)); do update_main_core_cpufreq if [[ $main_core_setspeed == "" ]]; then # governor hasn't taken over yet, skip this sample printf 'Waiting for DPDK governor to take over...\n' continue fi if ((main_core_setspeed > old_main_core_setspeed)); then dir=1 elif ((main_core_setspeed < old_main_core_setspeed)); then dir=0 elif ((main_core_setspeed == old_main_core_setspeed)); then # Frequency didn't change, skip and wait for a bit sleep 0.5s continue fi case "$main_core_driver" in acpi-cpufreq) [[ $main_core_governor == userspace ]] \ && [[ -n ${main_core_freqs_map[main_core_setspeed]} ]] \ && ((main_core_setspeed == main_core_freqs[-1])) \ && ((dir == 0)) ;; intel_pstate | intel_cpufreq) [[ $main_core_governor == performance ]] \ && [[ -n ${main_core_freqs_map[main_core_setspeed]} ]] \ && ((main_core_setspeed == main_core_freqs[-1])) \ && ((main_core_set_max_freq == main_core_set_min_freq)) \ && ((dir == 0)) ;; cppc_cpufreq) [[ $main_core_governor == userspace ]] \ && [[ -n ${main_core_freqs_map[main_core_setspeed]} ]] \ && ((main_core_setspeed == main_core_freqs[-1])) \ && ((dir == 0)) ;; esac && all_set=1 # Print stats after first sane sample was taken if ((old_main_core_setspeed != 0 && dir != -1)); then # Currently, we only determine if DPDK set sysfs attributes to min frequency supported by given cpu. # We don't act on actual frequency cpu ends up spinning at. The reason being all sibling threads of # the main cpu would need to be adjusted manually (i.e. their cpufreq attributes) in order for freq # to start going down. This is deemed as not necessary for the moment since the core objective of # the test is to determine if DPDK's governor did its job, within its current scope, not how it # impacts the system overall. printf 'MAIN DPDK cpu%u current frequency at %u KHz (%u-%u KHz), set frequency %u KHz %s %u KHz\n' \ "$spdk_main_core" "$main_core_set_cur_freq" "$main_core_min_freq" "$main_core_max_freq" \ "$main_core_setspeed" "${dir_map[dir]}" "$old_main_core_setspeed" else printf 'Waiting for samples...\n' fi old_main_core_setspeed=$main_core_setspeed done ((all_set == 1)) xtrace_restore } map_cpufreq # Save initial scaling governor to restore it later on initial_main_core_governor=${cpufreq_governors[spdk_main_core]} verify_dpdk_governor