1#!/bin/bash 2# perf stat CSV output linter 3# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 4# Tests various perf stat CSV output commands for the 5# correct number of fields and the CSV separator set to ','. 6 7set -e 8 9skip_test=0 10csv_sep=@ 11 12stat_output=$(mktemp /tmp/__perf_test.stat_output.csv.XXXXX) 13 14cleanup() { 15 rm -f "${stat_output}" 16 17 trap - EXIT TERM INT 18} 19 20trap_cleanup() { 21 cleanup 22 exit 1 23} 24trap trap_cleanup EXIT TERM INT 25 26function commachecker() 27{ 28 local -i cnt=0 29 local exp=0 30 31 case "$1" 32 in "--no-args") exp=6 33 ;; "--system-wide") exp=6 34 ;; "--event") exp=6 35 ;; "--interval") exp=7 36 ;; "--per-thread") exp=7 37 ;; "--system-wide-no-aggr") exp=7 38 [ $(uname -m) = "s390x" ] && exp='^[6-7]$' 39 ;; "--per-core") exp=8 40 ;; "--per-socket") exp=8 41 ;; "--per-node") exp=8 42 ;; "--per-die") exp=8 43 esac 44 45 while read line 46 do 47 # Ignore initial "started on" comment. 48 x=${line:0:1} 49 [ "$x" = "#" ] && continue 50 # Ignore initial blank line. 51 [ "$line" = "" ] && continue 52 53 # Count the number of commas 54 x=$(echo $line | tr -d -c $csv_sep) 55 cnt="${#x}" 56 # echo $line $cnt 57 [[ ! "$cnt" =~ $exp ]] && { 58 echo "wrong number of fields. expected $exp in $line" 1>&2 59 exit 1; 60 } 61 done < "${stat_output}" 62 return 0 63} 64 65# Return true if perf_event_paranoid is > $1 and not running as root. 66function ParanoidAndNotRoot() 67{ 68 [ $(id -u) != 0 ] && [ $(cat /proc/sys/kernel/perf_event_paranoid) -gt $1 ] 69} 70 71check_no_args() 72{ 73 echo -n "Checking CSV output: no args " 74 perf stat -x$csv_sep -o "${stat_output}" true 75 commachecker --no-args 76 echo "[Success]" 77} 78 79check_system_wide() 80{ 81 echo -n "Checking CSV output: system wide " 82 if ParanoidAndNotRoot 0 83 then 84 echo "[Skip] paranoid and not root" 85 return 86 fi 87 perf stat -x$csv_sep -a -o "${stat_output}" true 88 commachecker --system-wide 89 echo "[Success]" 90} 91 92check_system_wide_no_aggr() 93{ 94 echo -n "Checking CSV output: system wide no aggregation " 95 if ParanoidAndNotRoot 0 96 then 97 echo "[Skip] paranoid and not root" 98 return 99 fi 100 perf stat -x$csv_sep -A -a --no-merge -o "${stat_output}" true 101 commachecker --system-wide-no-aggr 102 echo "[Success]" 103} 104 105check_interval() 106{ 107 echo -n "Checking CSV output: interval " 108 perf stat -x$csv_sep -I 1000 -o "${stat_output}" true 109 commachecker --interval 110 echo "[Success]" 111} 112 113 114check_event() 115{ 116 echo -n "Checking CSV output: event " 117 perf stat -x$csv_sep -e cpu-clock -o "${stat_output}" true 118 commachecker --event 119 echo "[Success]" 120} 121 122check_per_core() 123{ 124 echo -n "Checking CSV output: per core " 125 if ParanoidAndNotRoot 0 126 then 127 echo "[Skip] paranoid and not root" 128 return 129 fi 130 perf stat -x$csv_sep --per-core -a -o "${stat_output}" true 131 commachecker --per-core 132 echo "[Success]" 133} 134 135check_per_thread() 136{ 137 echo -n "Checking CSV output: per thread " 138 if ParanoidAndNotRoot 0 139 then 140 echo "[Skip] paranoid and not root" 141 return 142 fi 143 perf stat -x$csv_sep --per-thread -a -o "${stat_output}" true 144 commachecker --per-thread 145 echo "[Success]" 146} 147 148check_per_die() 149{ 150 echo -n "Checking CSV output: per die " 151 if ParanoidAndNotRoot 0 152 then 153 echo "[Skip] paranoid and not root" 154 return 155 fi 156 perf stat -x$csv_sep --per-die -a -o "${stat_output}" true 157 commachecker --per-die 158 echo "[Success]" 159} 160 161check_per_node() 162{ 163 echo -n "Checking CSV output: per node " 164 if ParanoidAndNotRoot 0 165 then 166 echo "[Skip] paranoid and not root" 167 return 168 fi 169 perf stat -x$csv_sep --per-node -a -o "${stat_output}" true 170 commachecker --per-node 171 echo "[Success]" 172} 173 174check_per_socket() 175{ 176 echo -n "Checking CSV output: per socket " 177 if ParanoidAndNotRoot 0 178 then 179 echo "[Skip] paranoid and not root" 180 return 181 fi 182 perf stat -x$csv_sep --per-socket -a -o "${stat_output}" true 183 commachecker --per-socket 184 echo "[Success]" 185} 186 187# The perf stat options for per-socket, per-core, per-die 188# and -A ( no_aggr mode ) uses the info fetched from this 189# directory: "/sys/devices/system/cpu/cpu*/topology". For 190# example, socket value is fetched from "physical_package_id" 191# file in topology directory. 192# Reference: cpu__get_topology_int in util/cpumap.c 193# If the platform doesn't expose topology information, values 194# will be set to -1. For example, incase of pSeries platform 195# of powerpc, value for "physical_package_id" is restricted 196# and set to -1. Check here validates the socket-id read from 197# topology file before proceeding further 198 199FILE_LOC="/sys/devices/system/cpu/cpu*/topology/" 200FILE_NAME="physical_package_id" 201 202check_for_topology() 203{ 204 if ! ParanoidAndNotRoot 0 205 then 206 socket_file=`ls $FILE_LOC/$FILE_NAME | head -n 1` 207 [ -z $socket_file ] && return 0 208 socket_id=`cat $socket_file` 209 [ $socket_id == -1 ] && skip_test=1 210 return 0 211 fi 212} 213 214check_for_topology 215check_no_args 216check_system_wide 217check_interval 218check_event 219check_per_thread 220check_per_node 221if [ $skip_test -ne 1 ] 222then 223 check_system_wide_no_aggr 224 check_per_core 225 check_per_die 226 check_per_socket 227else 228 echo "[Skip] Skipping tests for system_wide_no_aggr, per_core, per_die and per_socket since socket id exposed via topology is invalid" 229fi 230cleanup 231exit 0 232