| #!/bin/bash |
| # SPDX-License-Identifier: GPL-2.0 |
| |
| # protect against multiple inclusion |
| if [ $FILE_MAIN ]; then |
| return 0 |
| else |
| FILE_MAIN=DONE |
| fi |
| |
| SCRIPTDIR=`dirname "$0"` |
| TRACER=$SCRIPTDIR/../../../power/x86/amd_pstate_tracer/amd_pstate_trace.py |
| |
| source $SCRIPTDIR/basic.sh |
| source $SCRIPTDIR/tbench.sh |
| source $SCRIPTDIR/gitsource.sh |
| |
| # amd-pstate-ut only run on x86/x86_64 AMD systems. |
| ARCH=$(uname -m 2>/dev/null | sed -e 's/i.86/x86/' -e 's/x86_64/x86/') |
| VENDOR=$(cat /proc/cpuinfo | grep -m 1 'vendor_id' | awk '{print $NF}') |
| |
| msg="Skip all tests:" |
| FUNC=all |
| OUTFILE=selftest |
| OUTFILE_TBENCH="$OUTFILE.tbench" |
| OUTFILE_GIT="$OUTFILE.gitsource" |
| |
| PERF=/usr/bin/perf |
| SYSFS= |
| CPUROOT= |
| CPUFREQROOT= |
| MAKE_CPUS= |
| |
| TIME_LIMIT=100 |
| PROCESS_NUM=128 |
| LOOP_TIMES=3 |
| TRACER_INTERVAL=10 |
| CURRENT_TEST=amd-pstate |
| COMPARATIVE_TEST= |
| |
| # Kselftest framework requirement - SKIP code is 4. |
| ksft_skip=4 |
| all_scaling_names=("acpi-cpufreq" "amd-pstate") |
| |
| # Get current cpufreq scaling driver name |
| scaling_name() |
| { |
| if [ "$COMPARATIVE_TEST" = "" ]; then |
| echo "$CURRENT_TEST" |
| else |
| echo "$COMPARATIVE_TEST" |
| fi |
| } |
| |
| # Counts CPUs with cpufreq directories |
| count_cpus() |
| { |
| count=0; |
| |
| for cpu in `ls $CPUROOT | grep "cpu[0-9].*"`; do |
| if [ -d $CPUROOT/$cpu/cpufreq ]; then |
| let count=count+1; |
| fi |
| done |
| |
| echo $count; |
| } |
| |
| # $1: policy |
| find_current_governor() |
| { |
| cat $CPUFREQROOT/$1/scaling_governor |
| } |
| |
| backup_governor() |
| { |
| policies=$(ls $CPUFREQROOT| grep "policy[0-9].*") |
| for policy in $policies; do |
| cur_gov=$(find_current_governor $policy) |
| echo "$policy $cur_gov" >> $OUTFILE.backup_governor.log |
| done |
| |
| printf "Governor $cur_gov backup done.\n" |
| } |
| |
| restore_governor() |
| { |
| i=0; |
| |
| policies=$(awk '{print $1}' $OUTFILE.backup_governor.log) |
| for policy in $policies; do |
| let i++; |
| governor=$(sed -n ''$i'p' $OUTFILE.backup_governor.log | awk '{print $2}') |
| |
| # switch governor |
| echo $governor > $CPUFREQROOT/$policy/scaling_governor |
| done |
| |
| printf "Governor restored to $governor.\n" |
| } |
| |
| # $1: governor |
| switch_governor() |
| { |
| policies=$(ls $CPUFREQROOT| grep "policy[0-9].*") |
| for policy in $policies; do |
| filepath=$CPUFREQROOT/$policy/scaling_available_governors |
| |
| # Exit if cpu isn't managed by cpufreq core |
| if [ ! -f $filepath ]; then |
| return; |
| fi |
| |
| echo $1 > $CPUFREQROOT/$policy/scaling_governor |
| done |
| |
| printf "Switched governor to $1.\n" |
| } |
| |
| # All amd-pstate tests |
| amd_pstate_all() |
| { |
| printf "\n=============================================\n" |
| printf "***** Running AMD P-state Sanity Tests *****\n" |
| printf "=============================================\n\n" |
| |
| count=$(count_cpus) |
| if [ $count = 0 ]; then |
| printf "No cpu is managed by cpufreq core, exiting\n" |
| exit; |
| else |
| printf "AMD P-state manages: $count CPUs\n" |
| fi |
| |
| # unit test for amd-pstate kernel driver |
| amd_pstate_basic |
| |
| # tbench |
| amd_pstate_tbench |
| |
| # gitsource |
| amd_pstate_gitsource |
| } |
| |
| help() |
| { |
| printf "Usage: $0 [OPTION...] |
| [-h <help>] |
| [-o <output-file-for-dump>] |
| [-c <all: All testing, |
| basic: Basic testing, |
| tbench: Tbench testing, |
| gitsource: Gitsource testing.>] |
| [-t <tbench time limit>] |
| [-p <tbench process number>] |
| [-l <loop times for tbench>] |
| [-i <amd tracer interval>] |
| [-b <perf binary>] |
| [-m <comparative test: acpi-cpufreq>] |
| \n" |
| exit 2 |
| } |
| |
| parse_arguments() |
| { |
| while getopts ho:c:t:p:l:i:b:m: arg |
| do |
| case $arg in |
| h) # --help |
| help |
| ;; |
| |
| c) # --func_type (Function to perform: basic, tbench, gitsource (default: all)) |
| FUNC=$OPTARG |
| ;; |
| |
| o) # --output-file (Output file to store dumps) |
| OUTFILE=$OPTARG |
| ;; |
| |
| t) # --tbench-time-limit |
| TIME_LIMIT=$OPTARG |
| ;; |
| |
| p) # --tbench-process-number |
| PROCESS_NUM=$OPTARG |
| ;; |
| |
| l) # --tbench/gitsource-loop-times |
| LOOP_TIMES=$OPTARG |
| ;; |
| |
| i) # --amd-tracer-interval |
| TRACER_INTERVAL=$OPTARG |
| ;; |
| |
| b) # --perf-binary |
| PERF=`realpath $OPTARG` |
| ;; |
| |
| m) # --comparative-test |
| COMPARATIVE_TEST=$OPTARG |
| ;; |
| |
| *) |
| help |
| ;; |
| esac |
| done |
| } |
| |
| command_perf() |
| { |
| if ! $PERF -v; then |
| echo $msg please install perf or provide perf binary path as argument >&2 |
| exit $ksft_skip |
| fi |
| } |
| |
| command_tbench() |
| { |
| if ! command -v tbench > /dev/null; then |
| if apt policy dbench > /dev/null 2>&1; then |
| echo $msg apt install dbench >&2 |
| exit $ksft_skip |
| elif yum list available | grep dbench > /dev/null 2>&1; then |
| echo $msg yum install dbench >&2 |
| exit $ksft_skip |
| fi |
| fi |
| |
| if ! command -v tbench > /dev/null; then |
| echo $msg please install tbench. >&2 |
| exit $ksft_skip |
| fi |
| } |
| |
| prerequisite() |
| { |
| if ! echo "$ARCH" | grep -q x86; then |
| echo "$0 # Skipped: Test can only run on x86 architectures." |
| exit $ksft_skip |
| fi |
| |
| if ! echo "$VENDOR" | grep -iq amd; then |
| echo "$0 # Skipped: Test can only run on AMD CPU." |
| echo "$0 # Current cpu vendor is $VENDOR." |
| exit $ksft_skip |
| fi |
| |
| scaling_driver=$(cat /sys/devices/system/cpu/cpufreq/policy0/scaling_driver) |
| if [ "$COMPARATIVE_TEST" = "" ]; then |
| if [ "$scaling_driver" != "$CURRENT_TEST" ]; then |
| echo "$0 # Skipped: Test can only run on $CURRENT_TEST driver or run comparative test." |
| echo "$0 # Please set X86_AMD_PSTATE enabled or run comparative test." |
| echo "$0 # Current cpufreq scaling driver is $scaling_driver." |
| exit $ksft_skip |
| fi |
| else |
| case "$FUNC" in |
| "tbench" | "gitsource") |
| if [ "$scaling_driver" != "$COMPARATIVE_TEST" ]; then |
| echo "$0 # Skipped: Comparison test can only run on $COMPARISON_TEST driver." |
| echo "$0 # Current cpufreq scaling driver is $scaling_driver." |
| exit $ksft_skip |
| fi |
| ;; |
| |
| *) |
| echo "$0 # Skipped: Comparison test are only for tbench or gitsource." |
| echo "$0 # Current comparative test is for $FUNC." |
| exit $ksft_skip |
| ;; |
| esac |
| fi |
| |
| if [ ! -w /dev ]; then |
| echo $msg please run this as root >&2 |
| exit $ksft_skip |
| fi |
| |
| case "$FUNC" in |
| "all") |
| command_perf |
| command_tbench |
| ;; |
| |
| "tbench") |
| command_perf |
| command_tbench |
| ;; |
| |
| "gitsource") |
| command_perf |
| ;; |
| esac |
| |
| SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'` |
| |
| if [ ! -d "$SYSFS" ]; then |
| echo $msg sysfs is not mounted >&2 |
| exit 2 |
| fi |
| |
| CPUROOT=$SYSFS/devices/system/cpu |
| CPUFREQROOT="$CPUROOT/cpufreq" |
| |
| if ! ls $CPUROOT/cpu* > /dev/null 2>&1; then |
| echo $msg cpus not available in sysfs >&2 |
| exit 2 |
| fi |
| |
| if ! ls $CPUROOT/cpufreq > /dev/null 2>&1; then |
| echo $msg cpufreq directory not available in sysfs >&2 |
| exit 2 |
| fi |
| } |
| |
| do_test() |
| { |
| # Check if CPUs are managed by cpufreq or not |
| count=$(count_cpus) |
| MAKE_CPUS=$((count*2)) |
| |
| if [ $count = 0 ]; then |
| echo "No cpu is managed by cpufreq core, exiting" |
| exit 2; |
| fi |
| |
| case "$FUNC" in |
| "all") |
| amd_pstate_all |
| ;; |
| |
| "basic") |
| amd_pstate_basic |
| ;; |
| |
| "tbench") |
| amd_pstate_tbench |
| ;; |
| |
| "gitsource") |
| amd_pstate_gitsource |
| ;; |
| |
| *) |
| echo "Invalid [-f] function type" |
| help |
| ;; |
| esac |
| } |
| |
| # clear dumps |
| pre_clear_dumps() |
| { |
| case "$FUNC" in |
| "all") |
| rm -rf $OUTFILE.log |
| rm -rf $OUTFILE.backup_governor.log |
| rm -rf *.png |
| ;; |
| |
| "tbench") |
| rm -rf $OUTFILE.log |
| rm -rf $OUTFILE.backup_governor.log |
| rm -rf tbench_*.png |
| ;; |
| |
| "gitsource") |
| rm -rf $OUTFILE.log |
| rm -rf $OUTFILE.backup_governor.log |
| rm -rf gitsource_*.png |
| ;; |
| |
| *) |
| ;; |
| esac |
| } |
| |
| post_clear_dumps() |
| { |
| rm -rf $OUTFILE.log |
| rm -rf $OUTFILE.backup_governor.log |
| } |
| |
| # Parse arguments |
| parse_arguments $@ |
| |
| # Make sure all requirements are met |
| prerequisite |
| |
| # Run requested functions |
| pre_clear_dumps |
| do_test | tee -a $OUTFILE.log |
| post_clear_dumps |