1#!/bin/bash 2# perf record tests (exclusive) 3# SPDX-License-Identifier: GPL-2.0 4 5set -e 6 7shelldir=$(dirname "$0") 8# shellcheck source=lib/waiting.sh 9. "${shelldir}"/lib/waiting.sh 10 11# shellcheck source=lib/perf_has_symbol.sh 12. "${shelldir}"/lib/perf_has_symbol.sh 13 14testsym="test_loop" 15 16skip_test_missing_symbol ${testsym} 17 18err=0 19perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) 20script_output=$(mktemp /tmp/__perf_test.perf.data.XXXXX.script) 21testprog="perf test -w thloop" 22cpu_pmu_dir="/sys/bus/event_source/devices/cpu*" 23br_cntr_file="/caps/branch_counter_nr" 24br_cntr_output="branch stack counters" 25br_cntr_script_output="br_cntr: A" 26 27default_fd_limit=$(ulimit -Sn) 28# With option --threads=cpu the number of open file descriptors should be 29# equal to sum of: nmb_cpus * nmb_events (2+dummy), 30# nmb_threads for perf.data.n (equal to nmb_cpus) and 31# 2*nmb_cpus of pipes = 4*nmb_cpus (each pipe has 2 ends) 32# All together it needs 8*nmb_cpus file descriptors plus some are also used 33# outside of testing, thus raising the limit to 16*nmb_cpus 34min_fd_limit=$(($(getconf _NPROCESSORS_ONLN) * 16)) 35 36cleanup() { 37 rm -rf "${perfdata}" 38 rm -rf "${perfdata}".old 39 40 trap - EXIT TERM INT 41} 42 43trap_cleanup() { 44 cleanup 45 exit 1 46} 47trap trap_cleanup EXIT TERM INT 48 49test_per_thread() { 50 echo "Basic --per-thread mode test" 51 if ! perf record -o /dev/null --quiet ${testprog} 2> /dev/null 52 then 53 echo "Per-thread record [Skipped event not supported]" 54 return 55 fi 56 if ! perf record --per-thread -o "${perfdata}" ${testprog} 2> /dev/null 57 then 58 echo "Per-thread record [Failed record]" 59 err=1 60 return 61 fi 62 if ! perf report -i "${perfdata}" -q | grep -q "${testsym}" 63 then 64 echo "Per-thread record [Failed missing output]" 65 err=1 66 return 67 fi 68 69 # run the test program in background (for 30 seconds) 70 ${testprog} 30 & 71 TESTPID=$! 72 73 rm -f "${perfdata}" 74 75 wait_for_threads ${TESTPID} 2 76 perf record -p "${TESTPID}" --per-thread -o "${perfdata}" sleep 1 2> /dev/null 77 kill ${TESTPID} 78 79 if [ ! -e "${perfdata}" ] 80 then 81 echo "Per-thread record [Failed record -p]" 82 err=1 83 return 84 fi 85 if ! perf report -i "${perfdata}" -q | grep -q "${testsym}" 86 then 87 echo "Per-thread record [Failed -p missing output]" 88 err=1 89 return 90 fi 91 92 echo "Basic --per-thread mode test [Success]" 93} 94 95test_register_capture() { 96 echo "Register capture test" 97 if ! perf list pmu | grep -q 'br_inst_retired.near_call' 98 then 99 echo "Register capture test [Skipped missing event]" 100 return 101 fi 102 if ! perf record --intr-regs=\? 2>&1 | grep -q 'available registers: AX BX CX DX SI DI BP SP IP FLAGS CS SS R8 R9 R10 R11 R12 R13 R14 R15' 103 then 104 echo "Register capture test [Skipped missing registers]" 105 return 106 fi 107 if ! perf record -o - --intr-regs=di,r8,dx,cx -e br_inst_retired.near_call \ 108 -c 1000 --per-thread ${testprog} 2> /dev/null \ 109 | perf script -F ip,sym,iregs -i - 2> /dev/null \ 110 | grep -q "DI:" 111 then 112 echo "Register capture test [Failed missing output]" 113 err=1 114 return 115 fi 116 echo "Register capture test [Success]" 117} 118 119test_system_wide() { 120 echo "Basic --system-wide mode test" 121 if ! perf record -aB --synth=no -o "${perfdata}" ${testprog} 2> /dev/null 122 then 123 echo "System-wide record [Skipped not supported]" 124 return 125 fi 126 if ! perf report -i "${perfdata}" -q | grep -q "${testsym}" 127 then 128 echo "System-wide record [Failed missing output]" 129 err=1 130 return 131 fi 132 if ! perf record -aB --synth=no -e cpu-clock,cs --threads=cpu \ 133 -o "${perfdata}" ${testprog} 2> /dev/null 134 then 135 echo "System-wide record [Failed record --threads option]" 136 err=1 137 return 138 fi 139 if ! perf report -i "${perfdata}" -q | grep -q "${testsym}" 140 then 141 echo "System-wide record [Failed --threads missing output]" 142 err=1 143 return 144 fi 145 echo "Basic --system-wide mode test [Success]" 146} 147 148test_workload() { 149 echo "Basic target workload test" 150 if ! perf record -o "${perfdata}" ${testprog} 2> /dev/null 151 then 152 echo "Workload record [Failed record]" 153 err=1 154 return 155 fi 156 if ! perf report -i "${perfdata}" -q | grep -q "${testsym}" 157 then 158 echo "Workload record [Failed missing output]" 159 err=1 160 return 161 fi 162 if ! perf record -e cpu-clock,cs --threads=package \ 163 -o "${perfdata}" ${testprog} 2> /dev/null 164 then 165 echo "Workload record [Failed record --threads option]" 166 err=1 167 return 168 fi 169 if ! perf report -i "${perfdata}" -q | grep -q "${testsym}" 170 then 171 echo "Workload record [Failed --threads missing output]" 172 err=1 173 return 174 fi 175 echo "Basic target workload test [Success]" 176} 177 178test_branch_counter() { 179 echo "Branch counter test" 180 # Check if the branch counter feature is supported 181 for dir in $cpu_pmu_dir 182 do 183 if [ ! -e "$dir$br_cntr_file" ] 184 then 185 echo "branch counter feature not supported on all core PMUs ($dir) [Skipped]" 186 return 187 fi 188 done 189 if ! perf record -o "${perfdata}" -e "{branches:p,instructions}" -j any,counter ${testprog} 2> /dev/null 190 then 191 echo "Branch counter record test [Failed record]" 192 err=1 193 return 194 fi 195 if ! perf report -i "${perfdata}" -D -q | grep -q "$br_cntr_output" 196 then 197 echo "Branch counter report test [Failed missing output]" 198 err=1 199 return 200 fi 201 if ! perf script -i "${perfdata}" -F +brstackinsn,+brcntr | grep -q "$br_cntr_script_output" 202 then 203 echo " Branch counter script test [Failed missing output]" 204 err=1 205 return 206 fi 207 echo "Branch counter test [Success]" 208} 209 210test_cgroup() { 211 echo "Cgroup sampling test" 212 if ! perf record -aB --synth=cgroup --all-cgroups -o "${perfdata}" ${testprog} 2> /dev/null 213 then 214 echo "Cgroup sampling [Skipped not supported]" 215 return 216 fi 217 if ! perf report -i "${perfdata}" -D | grep -q "CGROUP" 218 then 219 echo "Cgroup sampling [Failed missing output]" 220 err=1 221 return 222 fi 223 if ! perf script -i "${perfdata}" -F cgroup | grep -q -v "unknown" 224 then 225 echo "Cgroup sampling [Failed cannot resolve cgroup names]" 226 err=1 227 return 228 fi 229 echo "Cgroup sampling test [Success]" 230} 231 232test_leader_sampling() { 233 echo "Basic leader sampling test" 234 if ! perf record -o "${perfdata}" -e "{cycles,cycles}:Su" -- \ 235 perf test -w brstack 2> /dev/null 236 then 237 echo "Leader sampling [Failed record]" 238 err=1 239 return 240 fi 241 index=0 242 perf script -i "${perfdata}" > $script_output 243 while IFS= read -r line 244 do 245 # Check if the two instruction counts are equal in each record 246 cycles=$(echo $line | awk '{for(i=1;i<=NF;i++) if($i=="cycles:") print $(i-1)}') 247 if [ $(($index%2)) -ne 0 ] && [ ${cycles}x != ${prev_cycles}x ] 248 then 249 echo "Leader sampling [Failed inconsistent cycles count]" 250 err=1 251 return 252 fi 253 index=$(($index+1)) 254 prev_cycles=$cycles 255 done < $script_output 256 echo "Basic leader sampling test [Success]" 257} 258 259test_topdown_leader_sampling() { 260 echo "Topdown leader sampling test" 261 if ! perf stat -e "{slots,topdown-retiring}" true 2> /dev/null 262 then 263 echo "Topdown leader sampling [Skipped event parsing failed]" 264 return 265 fi 266 if ! perf record -o "${perfdata}" -e "{instructions,slots,topdown-retiring}:S" true 2> /dev/null 267 then 268 echo "Topdown leader sampling [Failed topdown events not reordered correctly]" 269 err=1 270 return 271 fi 272 echo "Topdown leader sampling test [Success]" 273} 274 275test_precise_max() { 276 local -i skipped=0 277 278 echo "precise_max attribute test" 279 # Just to make sure event cycles is supported for sampling 280 if perf record -o "${perfdata}" -e "cycles" true 2> /dev/null 281 then 282 if ! perf record -o "${perfdata}" -e "cycles:P" true 2> /dev/null 283 then 284 echo "precise_max attribute [Failed cycles:P event]" 285 err=1 286 return 287 fi 288 else 289 echo "precise_max attribute [Skipped no cycles:P event]" 290 ((skipped+=1)) 291 fi 292 # On s390 event instructions is not supported for perf record 293 if perf record -o "${perfdata}" -e "instructions" true 2> /dev/null 294 then 295 # On AMD, cycles and instructions events are treated differently 296 if ! perf record -o "${perfdata}" -e "instructions:P" true 2> /dev/null 297 then 298 echo "precise_max attribute [Failed instructions:P event]" 299 err=1 300 return 301 fi 302 else 303 echo "precise_max attribute [Skipped no instructions:P event]" 304 ((skipped+=1)) 305 fi 306 if [ $skipped -eq 2 ] 307 then 308 echo "precise_max attribute [Skipped no hardware events]" 309 else 310 echo "precise_max attribute test [Success]" 311 fi 312} 313 314# raise the limit of file descriptors to minimum 315if [[ $default_fd_limit -lt $min_fd_limit ]]; then 316 ulimit -Sn $min_fd_limit 317fi 318 319test_per_thread 320test_register_capture 321test_system_wide 322test_workload 323test_branch_counter 324test_cgroup 325test_leader_sampling 326test_topdown_leader_sampling 327test_precise_max 328 329# restore the default value 330ulimit -Sn $default_fd_limit 331 332cleanup 333exit $err 334