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