| 1 | |
| 2 | |
| 3 | |
| 4 |
|
| 5 | set -e
|
| 6 |
|
| 7 | shelldir=$(dirname "$0")
|
| 8 | . "${shelldir}"/lib/perf_record.sh
|
| 9 |
|
| 10 |
|
| 11 | |
| 12 | . "${shelldir}"/lib/waiting.sh
|
| 13 |
|
| 14 | |
| 15 | . "${shelldir}"/lib/perf_has_symbol.sh
|
| 16 |
|
| 17 | testsym="test_loop"
|
| 18 | testsym2="brstack"
|
| 19 |
|
| 20 | skip_test_missing_symbol ${testsym}
|
| 21 | skip_test_missing_symbol ${testsym2}
|
| 22 |
|
| 23 | err=0
|
| 24 | perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
|
| 25 | script_output=$(mktemp /tmp/__perf_test.perf.data.XXXXX.script)
|
| 26 | testprog="perf test -w thloop"
|
| 27 | cpu_pmu_dir="/sys/bus/event_source/devices/cpu*"
|
| 28 | br_cntr_file="/caps/branch_counter_nr"
|
| 29 | br_cntr_output="branch stack counters"
|
| 30 | br_cntr_script_output="br_cntr: A"
|
| 31 |
|
| 32 | default_fd_limit=$(ulimit -Sn)
|
| 33 | |
| 34 | |
| 35 | |
| 36 | |
| 37 | |
| 38 | |
| 39 | min_fd_limit=$(($(getconf _NPROCESSORS_ONLN) * 16))
|
| 40 |
|
| 41 | cleanup() {
|
| 42 | rm -f "${perfdata}"
|
| 43 | rm -f "${perfdata}".old
|
| 44 | rm -f "${script_output}"
|
| 45 | perf_record_cleanup
|
| 46 |
|
| 47 | trap - EXIT TERM INT
|
| 48 | }
|
| 49 |
|
| 50 | trap_cleanup() {
|
| 51 | echo "Unexpected signal in ${FUNCNAME[1]}"
|
| 52 | cleanup
|
| 53 | exit 1
|
| 54 | }
|
| 55 | trap trap_cleanup EXIT TERM INT
|
| 56 |
|
| 57 | check_per_thread() {
|
| 58 | perf report -i "${perfdata}" -q | grep -q "${testsym}"
|
| 59 | }
|
| 60 |
|
| 61 | test_per_thread() {
|
| 62 | echo "Basic --per-thread mode test"
|
| 63 | local ret=0
|
| 64 | perf_record_with_retry "${perfdata}" "check_per_thread" "perf test -w thloop" \
|
| 65 | --per-thread || ret=$?
|
| 66 | if [ $ret -eq 2 ]; then
|
| 67 | echo "Per-thread record [Skipped event not supported]"
|
| 68 | return
|
| 69 | elif [ $ret -eq 1 ]; then
|
| 70 | echo "Per-thread record [Failed record or missing output]"
|
| 71 | err=1
|
| 72 | return
|
| 73 | fi
|
| 74 |
|
| 75 | |
| 76 | ${testprog} 30 &
|
| 77 | TESTPID=$!
|
| 78 |
|
| 79 | rm -f "${perfdata}"
|
| 80 |
|
| 81 | wait_for_threads ${TESTPID} 2
|
| 82 | perf record -p "${TESTPID}" --per-thread -o "${perfdata}" sleep 1 2> /dev/null
|
| 83 | kill ${TESTPID}
|
| 84 |
|
| 85 | if [ ! -e "${perfdata}" ]
|
| 86 | then
|
| 87 | echo "Per-thread record [Failed record -p]"
|
| 88 | err=1
|
| 89 | return
|
| 90 | fi
|
| 91 | if ! perf report -i "${perfdata}" -q | grep -q "${testsym}"
|
| 92 | then
|
| 93 | echo "Per-thread record [Failed -p missing output]"
|
| 94 | err=1
|
| 95 | return
|
| 96 | fi
|
| 97 |
|
| 98 | echo "Basic --per-thread mode test [Success]"
|
| 99 | }
|
| 100 |
|
| 101 | check_register_capture() {
|
| 102 | perf script -F ip,sym,iregs -i "${perfdata}" 2>/dev/null | grep -q "DI:"
|
| 103 | }
|
| 104 |
|
| 105 | test_register_capture() {
|
| 106 | echo "Register capture test"
|
| 107 | if ! perf list pmu | grep -q 'br_inst_retired.near_call'
|
| 108 | then
|
| 109 | echo "Register capture test [Skipped missing event]"
|
| 110 | return
|
| 111 | fi
|
| 112 | 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'
|
| 113 | then
|
| 114 | echo "Register capture test [Skipped missing registers]"
|
| 115 | return
|
| 116 | fi
|
| 117 |
|
| 118 | local ret=0
|
| 119 | perf_record_with_retry "${perfdata}" "check_register_capture" "perf test -w thloop" \
|
| 120 | --intr-regs=di,r8,dx,cx -e br_inst_retired.near_call -c 1000 --per-thread || ret=$?
|
| 121 |
|
| 122 | if [ $ret -ne 0 ]; then
|
| 123 | echo "Register capture test [Failed missing output]"
|
| 124 | err=1
|
| 125 | return
|
| 126 | fi
|
| 127 | echo "Register capture test [Success]"
|
| 128 | }
|
| 129 |
|
| 130 | check_system_wide() {
|
| 131 | perf report -i "${perfdata}" -q | grep -q "${testsym}"
|
| 132 | }
|
| 133 |
|
| 134 | test_system_wide() {
|
| 135 | echo "Basic --system-wide mode test"
|
| 136 | local ret=0
|
| 137 | perf_record_with_retry "${perfdata}" "check_system_wide" "perf test -w thloop" \
|
| 138 | -aB --synth=no || ret=$?
|
| 139 | if [ $ret -eq 2 ]; then
|
| 140 | echo "System-wide record [Skipped not supported]"
|
| 141 | return
|
| 142 | elif [ $ret -eq 1 ]; then
|
| 143 | echo "System-wide record [Failed missing output]"
|
| 144 | err=1
|
| 145 | return
|
| 146 | fi
|
| 147 |
|
| 148 | ret=0
|
| 149 | perf_record_with_retry "${perfdata}" "check_system_wide" "perf test -w thloop" \
|
| 150 | -aB --synth=no -e cpu-clock,cs --threads=cpu || ret=$?
|
| 151 | if [ $ret -ne 0 ]; then
|
| 152 | echo "System-wide record [Failed record --threads option or missing output]"
|
| 153 | err=1
|
| 154 | return
|
| 155 | fi
|
| 156 | echo "Basic --system-wide mode test [Success]"
|
| 157 | }
|
| 158 |
|
| 159 | check_workload() {
|
| 160 | perf report -i "${perfdata}" -q | grep -q "${testsym}"
|
| 161 | }
|
| 162 |
|
| 163 | test_workload() {
|
| 164 | echo "Basic target workload test"
|
| 165 | local ret=0
|
| 166 | perf_record_with_retry "${perfdata}" "check_workload" "perf test -w thloop" || ret=$?
|
| 167 | if [ $ret -ne 0 ]; then
|
| 168 | echo "Workload record [Failed record or missing output]"
|
| 169 | err=1
|
| 170 | return
|
| 171 | fi
|
| 172 |
|
| 173 | ret=0
|
| 174 | perf_record_with_retry "${perfdata}" "check_workload" "perf test -w thloop" \
|
| 175 | -e cpu-clock,cs --threads=package || ret=$?
|
| 176 | if [ $ret -ne 0 ]; then
|
| 177 | echo "Workload record [Failed record --threads option or missing output]"
|
| 178 | err=1
|
| 179 | return
|
| 180 | fi
|
| 181 | echo "Basic target workload test [Success]"
|
| 182 | }
|
| 183 |
|
| 184 | check_branch_counter() {
|
| 185 | perf report -i "${perfdata}" -D -q 2>/dev/null | grep -q "$br_cntr_output" && \
|
| 186 | perf script -i "${perfdata}" -F +brstackinsn,+brcntr 2>/dev/null | \
|
| 187 | grep -q "$br_cntr_script_output"
|
| 188 | }
|
| 189 |
|
| 190 | test_branch_counter() {
|
| 191 | echo "Branch counter test"
|
| 192 | |
| 193 | for dir in $cpu_pmu_dir
|
| 194 | do
|
| 195 | if [ ! -e "$dir$br_cntr_file" ]
|
| 196 | then
|
| 197 | echo "branch counter feature not supported on all core PMUs ($dir) [Skipped]"
|
| 198 | return
|
| 199 | fi
|
| 200 | done
|
| 201 | local ret=0
|
| 202 | perf_record_with_retry "${perfdata}" "check_branch_counter" "perf test -w thloop" \
|
| 203 | -e "{branches:p,instructions}" -j any,counter || ret=$?
|
| 204 | if [ $ret -ne 0 ]; then
|
| 205 | echo "Branch counter test [Failed record or missing output]"
|
| 206 | err=1
|
| 207 | return
|
| 208 | fi
|
| 209 | echo "Branch counter test [Success]"
|
| 210 | }
|
| 211 |
|
| 212 | check_cgroup() {
|
| 213 | perf report -i "${perfdata}" -D 2>/dev/null | grep -q "CGROUP" && \
|
| 214 | perf script -i "${perfdata}" -F cgroup 2>/dev/null | grep -q -v "unknown"
|
| 215 | }
|
| 216 |
|
| 217 | test_cgroup() {
|
| 218 | echo "Cgroup sampling test"
|
| 219 | local ret=0
|
| 220 | perf_record_with_retry "${perfdata}" "check_cgroup" "perf test -w thloop" \
|
| 221 | -aB --synth=cgroup --all-cgroups || ret=$?
|
| 222 | if [ $ret -eq 2 ]; then
|
| 223 | echo "Cgroup sampling [Skipped not supported]"
|
| 224 | return
|
| 225 | elif [ $ret -eq 1 ]; then
|
| 226 | echo "Cgroup sampling [Failed missing output]"
|
| 227 | err=1
|
| 228 | return
|
| 229 | fi
|
| 230 | echo "Cgroup sampling test [Success]"
|
| 231 | }
|
| 232 |
|
| 233 | check_uid() {
|
| 234 | perf report -i "${perfdata}" -q | grep -q "${testsym}"
|
| 235 | }
|
| 236 |
|
| 237 | test_uid() {
|
| 238 | echo "Uid sampling test"
|
| 239 | local ret=0
|
| 240 | perf_record_with_retry "${perfdata}" "check_uid" "perf test -w thloop" \
|
| 241 | -aB --synth=no --uid "$(id -u)" || ret=$?
|
| 242 | if [ $ret -eq 2 ]; then
|
| 243 | local logfile="${PERF_RECORD_LOGS[${#PERF_RECORD_LOGS[@]}-1]}"
|
| 244 | if grep -q -E "libbpf.*EPERM|Access to performance monitoring" "$logfile" || \
|
| 245 | grep -q -E "Permission denied|Failure to open any events" "$logfile"
|
| 246 | then
|
| 247 | echo "Uid sampling [Skipped permissions]"
|
| 248 | return
|
| 249 | else
|
| 250 | echo "Uid sampling [Failed to record]"
|
| 251 | err=1
|
| 252 | return
|
| 253 | fi
|
| 254 | elif [ $ret -eq 1 ]; then
|
| 255 | echo "Uid sampling [Failed missing output]"
|
| 256 | err=1
|
| 257 | return
|
| 258 | fi
|
| 259 | echo "Uid sampling test [Success]"
|
| 260 | }
|
| 261 |
|
| 262 | test_leader_sampling() {
|
| 263 | echo "Basic leader sampling test"
|
| 264 | events="{cycles,cycles}:Su"
|
| 265 | [ "$(uname -m)" = "s390x" ] && {
|
| 266 | [ ! -d /sys/devices/cpum_sf ] && {
|
| 267 | echo "No CPUMF [Skipped record]"
|
| 268 | return
|
| 269 | }
|
| 270 | events="{cpum_sf/SF_CYCLES_BASIC/,cycles}:Su"
|
| 271 | perf record -o "${perfdata}" -e "$events" -- perf test -w brstack 2> /dev/null
|
| 272 | |
| 273 | [ "$?" -ne 0 ] && {
|
| 274 | echo "Grouping not support [Skipped record]"
|
| 275 | return
|
| 276 | }
|
| 277 | }
|
| 278 | if ! perf record -o "${perfdata}" -e "$events" -- \
|
| 279 | perf test -w brstack 2> /dev/null
|
| 280 | then
|
| 281 | echo "Leader sampling [Failed record]"
|
| 282 | err=1
|
| 283 | return
|
| 284 | fi
|
| 285 | perf script -i "${perfdata}" | grep brstack > $script_output
|
| 286 | |
| 287 | |
| 288 | |
| 289 | |
| 290 | |
| 291 | index=0
|
| 292 | valid_counts=0
|
| 293 | invalid_counts=0
|
| 294 | tolerance_rate=0.8
|
| 295 | while IFS= read -r line
|
| 296 | do
|
| 297 | cycles=$(echo $line | awk '{for(i=1;i<=NF;i++) if($i=="cycles:") print $(i-1)}')
|
| 298 | if [ $(($index%2)) -ne 0 ] && [ ${cycles}x != ${prev_cycles}x ]
|
| 299 | then
|
| 300 | invalid_counts=$(($invalid_counts+1))
|
| 301 | else
|
| 302 | valid_counts=$(($valid_counts+1))
|
| 303 | fi
|
| 304 | index=$(($index+1))
|
| 305 | prev_cycles=$cycles
|
| 306 | done < "${script_output}"
|
| 307 | total_counts=$(bc <<< "$invalid_counts+$valid_counts")
|
| 308 | if (( $(bc <<< "$total_counts <= 0") ))
|
| 309 | then
|
| 310 | echo "Leader sampling [No sample generated]"
|
| 311 | err=1
|
| 312 | return
|
| 313 | fi
|
| 314 | isok=$(bc <<< "scale=2; if (($invalid_counts/$total_counts) < (1-$tolerance_rate)) { 0 } else { 1 };")
|
| 315 | if [ $isok -eq 1 ]
|
| 316 | then
|
| 317 | echo "Leader sampling [Failed inconsistent cycles count]"
|
| 318 | err=1
|
| 319 | else
|
| 320 | echo "Basic leader sampling test [Success]"
|
| 321 | fi
|
| 322 | }
|
| 323 |
|
| 324 | test_topdown_leader_sampling() {
|
| 325 | echo "Topdown leader sampling test"
|
| 326 | if ! perf stat -e "{slots,topdown-retiring}" true 2> /dev/null
|
| 327 | then
|
| 328 | echo "Topdown leader sampling [Skipped event parsing failed]"
|
| 329 | return
|
| 330 | fi
|
| 331 | if ! perf record -o "${perfdata}" -e "{instructions,slots,topdown-retiring}:S" true 2> /dev/null
|
| 332 | then
|
| 333 | echo "Topdown leader sampling [Failed topdown events not reordered correctly]"
|
| 334 | err=1
|
| 335 | return
|
| 336 | fi
|
| 337 | echo "Topdown leader sampling test [Success]"
|
| 338 | }
|
| 339 |
|
| 340 | test_precise_max() {
|
| 341 | local -i skipped=0
|
| 342 |
|
| 343 | echo "precise_max attribute test"
|
| 344 | |
| 345 | if perf record -o "${perfdata}" -e "cycles" true 2> /dev/null
|
| 346 | then
|
| 347 | if ! perf record -o "${perfdata}" -e "cycles:P" true 2> /dev/null
|
| 348 | then
|
| 349 | echo "precise_max attribute [Failed cycles:P event]"
|
| 350 | err=1
|
| 351 | return
|
| 352 | fi
|
| 353 | else
|
| 354 | echo "precise_max attribute [Skipped no cycles:P event]"
|
| 355 | ((skipped+=1))
|
| 356 | fi
|
| 357 | |
| 358 | if perf record -o "${perfdata}" -e "instructions" true 2> /dev/null
|
| 359 | then
|
| 360 | |
| 361 | if ! perf record -o "${perfdata}" -e "instructions:P" true 2> /dev/null
|
| 362 | then
|
| 363 | echo "precise_max attribute [Failed instructions:P event]"
|
| 364 | err=1
|
| 365 | return
|
| 366 | fi
|
| 367 | else
|
| 368 | echo "precise_max attribute [Skipped no instructions:P event]"
|
| 369 | ((skipped+=1))
|
| 370 | fi
|
| 371 | if [ $skipped -eq 2 ]
|
| 372 | then
|
| 373 | echo "precise_max attribute [Skipped no hardware events]"
|
| 374 | else
|
| 375 | echo "precise_max attribute test [Success]"
|
| 376 | fi
|
| 377 | }
|
| 378 |
|
| 379 | test_callgraph() {
|
| 380 | echo "Callgraph test"
|
| 381 |
|
| 382 | case $(uname -m)
|
| 383 | in s390x)
|
| 384 | cmd_flags="--call-graph dwarf -e cpu-clock";;
|
| 385 | *)
|
| 386 | cmd_flags="-g";;
|
| 387 | esac
|
| 388 |
|
| 389 | if ! perf record -o "${perfdata}" $cmd_flags perf test -w brstack
|
| 390 | then
|
| 391 | echo "Callgraph test [Failed missing output]"
|
| 392 | err=1
|
| 393 | return
|
| 394 | fi
|
| 395 |
|
| 396 | if ! perf report -i "${perfdata}" 2>&1 | grep "${testsym2}"
|
| 397 | then
|
| 398 | echo "Callgraph test [Failed missing symbol]"
|
| 399 | err=1
|
| 400 | return
|
| 401 | fi
|
| 402 |
|
| 403 | echo "Callgraph test [Success]"
|
| 404 | }
|
| 405 |
|
| 406 | test_acr_sampling() {
|
| 407 | events="{instructions/period=40000,acr_mask=0x2/u,cycles/period=20000,acr_mask=0x3/u}"
|
| 408 | pebs_events="{instructions/period=40000,acr_mask=0x2/pu,cycles/period=20000,acr_mask=0x3/u}"
|
| 409 | echo "Auto counter reload (ACR) sampling test"
|
| 410 | if ! perf record -o "${perfdata}" -e "${events}" ${testprog} 2> /dev/null
|
| 411 | then
|
| 412 | echo "Auto counter reload sampling [Skipped not supported]"
|
| 413 | return
|
| 414 | fi
|
| 415 | if ! perf script -i "${perfdata}" -F event | grep -q "instructions"
|
| 416 | then
|
| 417 | echo "Auto counter reload sampling [Failed missing instructions event]"
|
| 418 | err=1
|
| 419 | return
|
| 420 | fi
|
| 421 | if perf script -i "${perfdata}" -F event | grep -q "cycles"
|
| 422 | then
|
| 423 | echo "Auto counter reload sampling [Failed cycles event shouldn't be sampled]"
|
| 424 | err=1
|
| 425 | return
|
| 426 | fi
|
| 427 | if ! perf record -o "${perfdata}" -e "${pebs_events}" ${testprog} 2> /dev/null
|
| 428 | then
|
| 429 | echo "Auto counter reload PEBS sampling [Skipped not supported]"
|
| 430 | echo "Auto counter reload sampling [Success]"
|
| 431 | return
|
| 432 | fi
|
| 433 | if ! perf script -i "${perfdata}" -F event | grep -q "instructions"
|
| 434 | then
|
| 435 | echo "Auto counter reload PEBS sampling [Failed missing instructions event]"
|
| 436 | err=1
|
| 437 | return
|
| 438 | fi
|
| 439 | if perf script -i "${perfdata}" -F event | grep -q "cycles"
|
| 440 | then
|
| 441 | echo "Auto counter reload PEBS sampling [Failed cycles event shouldn't be sampled]"
|
| 442 | err=1
|
| 443 | return
|
| 444 | fi
|
| 445 | echo "Auto counter reload sampling [Success]"
|
| 446 | }
|
| 447 |
|
| 448 | test_ratio_to_prev() {
|
| 449 | echo "ratio-to-prev test"
|
| 450 | if ! perf record -o /dev/null -e "{instructions, cycles/period=100000,ratio-to-prev=0.5/}" \
|
| 451 | true 2> /dev/null
|
| 452 | then
|
| 453 | echo "ratio-to-prev [Skipped not supported]"
|
| 454 | return
|
| 455 | fi
|
| 456 | if ! perf record -o /dev/null -e "instructions, cycles/period=100000,ratio-to-prev=0.5/" \
|
| 457 | true |& grep -q 'Invalid use of ratio-to-prev term without preceding element in group'
|
| 458 | then
|
| 459 | echo "ratio-to-prev test [Failed elements must be in same group]"
|
| 460 | err=1
|
| 461 | return
|
| 462 | fi
|
| 463 | if ! perf record -o /dev/null -e "{instructions,dummy,cycles/period=100000,ratio-to-prev=0.5/}" \
|
| 464 | true |& grep -q 'must have same PMU'
|
| 465 | then
|
| 466 | echo "ratio-to-prev test [Failed elements must have same PMU]"
|
| 467 | err=1
|
| 468 | return
|
| 469 | fi
|
| 470 | if ! perf record -o /dev/null -e "{instructions,cycles/ratio-to-prev=0.5/}" \
|
| 471 | true |& grep -q 'Event period term or count (-c) must be set when using ratio-to-prev term.'
|
| 472 | then
|
| 473 | echo "ratio-to-prev test [Failed period must be set]"
|
| 474 | err=1
|
| 475 | return
|
| 476 | fi
|
| 477 | if ! perf record -o /dev/null -e "{cycles/ratio-to-prev=0.5/}" \
|
| 478 | true |& grep -q 'Invalid use of ratio-to-prev term without preceding element in group'
|
| 479 | then
|
| 480 | echo "ratio-to-prev test [Failed need 2+ events]"
|
| 481 | err=1
|
| 482 | return
|
| 483 | fi
|
| 484 | echo "Basic ratio-to-prev record test [Success]"
|
| 485 | }
|
| 486 |
|
| 487 | |
| 488 | if [[ $default_fd_limit -lt $min_fd_limit ]]; then
|
| 489 | ulimit -Sn $min_fd_limit
|
| 490 | fi
|
| 491 |
|
| 492 | test_per_thread
|
| 493 | test_register_capture
|
| 494 | test_system_wide
|
| 495 | test_workload
|
| 496 | test_branch_counter
|
| 497 | test_cgroup
|
| 498 | test_uid
|
| 499 | test_leader_sampling
|
| 500 | test_topdown_leader_sampling
|
| 501 | test_precise_max
|
| 502 | test_callgraph
|
| 503 | test_acr_sampling
|
| 504 | test_ratio_to_prev
|
| 505 |
|
| 506 | |
| 507 | ulimit -Sn $default_fd_limit
|
| 508 |
|
| 509 | cleanup
|
| 510 | exit $err
|