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 "{instructions,instructions}: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 instructions=$(echo $line | awk '{for(i=1;i<=NF;i++) if($i=="instructions:") print $(i-1)}') 247 if [ $(($index%2)) -ne 0 ] && [ ${instructions}x != ${prev_instructions}x ] 248 then 249 echo "Leader sampling [Failed inconsistent instructions count]" 250 err=1 251 return 252 fi 253 index=$(($index+1)) 254 prev_instructions=$instructions 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 echo "precise_max attribute test" 277 if ! perf stat -e "cycles,instructions" true 2> /dev/null 278 then 279 echo "precise_max attribute [Skipped no hardware events]" 280 return 281 fi 282 # Just to make sure it doesn't fail 283 if ! perf record -o "${perfdata}" -e "cycles:P" true 2> /dev/null 284 then 285 echo "precise_max attribute [Failed cycles:P event]" 286 err=1 287 return 288 fi 289 # On AMD, cycles and instructions events are treated differently 290 if ! perf record -o "${perfdata}" -e "instructions:P" true 2> /dev/null 291 then 292 echo "precise_max attribute [Failed instructions:P event]" 293 err=1 294 return 295 fi 296 echo "precise_max attribute test [Success]" 297} 298 299# raise the limit of file descriptors to minimum 300if [[ $default_fd_limit -lt $min_fd_limit ]]; then 301 ulimit -Sn $min_fd_limit 302fi 303 304test_per_thread 305test_register_capture 306test_system_wide 307test_workload 308test_branch_counter 309test_cgroup 310test_leader_sampling 311test_topdown_leader_sampling 312test_precise_max 313 314# restore the default value 315ulimit -Sn $default_fd_limit 316 317cleanup 318exit $err 319