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