1#!/bin/bash 2# kernel lock contention analysis test 3# SPDX-License-Identifier: GPL-2.0 4 5set -e 6 7err=0 8perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX) 9result=$(mktemp /tmp/__perf_test.result.XXXXX) 10errout=$(mktemp /tmp/__perf_test.errout.XXXXX) 11 12cleanup() { 13 rm -f ${perfdata} 14 rm -f ${result} 15 rm -f ${errout} 16 trap - EXIT TERM INT 17} 18 19trap_cleanup() { 20 echo "Unexpected signal in ${FUNCNAME[1]}" 21 cleanup 22 exit ${err} 23} 24trap trap_cleanup EXIT TERM INT 25 26check() { 27 if [ "$(id -u)" != 0 ]; then 28 echo "[Skip] No root permission" 29 err=2 30 exit 31 fi 32 33 if ! perf list tracepoint | grep -q lock:contention_begin; then 34 echo "[Skip] No lock contention tracepoints" 35 err=2 36 exit 37 fi 38 39 # shellcheck disable=SC2046 40 if [ `nproc` -lt 4 ]; then 41 echo "[Skip] Low number of CPUs (`nproc`), lock event cannot be triggered certainly" 42 err=2 43 exit 44 fi 45} 46 47test_record() 48{ 49 echo "Testing perf lock record and perf lock contention" 50 perf lock record -o ${perfdata} -- perf bench sched messaging -p > /dev/null 2>&1 51 # the output goes to the stderr and we expect only 1 output (-E 1) 52 perf lock contention -i ${perfdata} -E 1 -q 2> ${result} 53 if [ "$(cat "${result}" | wc -l)" != "1" ]; then 54 echo "[Fail] Recorded result count is not 1:" "$(cat "${result}" | wc -l)" 55 err=1 56 exit 57 fi 58} 59 60test_bpf() 61{ 62 echo "Testing perf lock contention --use-bpf" 63 64 if ! perf lock con -b true > /dev/null 2>&1 ; then 65 echo "[Skip] No BPF support" 66 return 67 fi 68 69 # the perf lock contention output goes to the stderr 70 perf lock con -a -b -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} 71 if [ "$(cat "${result}" | wc -l)" != "1" ]; then 72 echo "[Fail] BPF result count is not 1:" "$(cat "${result}" | wc -l)" 73 err=1 74 exit 75 fi 76} 77 78test_record_concurrent() 79{ 80 echo "Testing perf lock record and perf lock contention at the same time" 81 perf lock record -o- -- perf bench sched messaging -p 2> ${errout} | \ 82 perf lock contention -i- -E 1 -q 2> ${result} 83 if [ "$(cat "${result}" | wc -l)" != "1" ]; then 84 echo "[Fail] Recorded result count is not 1:" "$(cat "${result}" | wc -l)" 85 cat ${errout} 86 cat ${result} 87 err=1 88 exit 89 fi 90} 91 92test_aggr_task() 93{ 94 echo "Testing perf lock contention --threads" 95 perf lock contention -i ${perfdata} -t -E 1 -q 2> ${result} 96 if [ "$(cat "${result}" | wc -l)" != "1" ]; then 97 echo "[Fail] Recorded result count is not 1:" "$(cat "${result}" | wc -l)" 98 err=1 99 exit 100 fi 101 102 if ! perf lock con -b true > /dev/null 2>&1 ; then 103 return 104 fi 105 106 # the perf lock contention output goes to the stderr 107 perf lock con -a -b -t -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} 108 if [ "$(cat "${result}" | wc -l)" != "1" ]; then 109 echo "[Fail] BPF result count is not 1:" "$(cat "${result}" | wc -l)" 110 err=1 111 exit 112 fi 113} 114 115test_aggr_addr() 116{ 117 echo "Testing perf lock contention --lock-addr" 118 perf lock contention -i ${perfdata} -l -E 1 -q 2> ${result} 119 if [ "$(cat "${result}" | wc -l)" != "1" ]; then 120 echo "[Fail] Recorded result count is not 1:" "$(cat "${result}" | wc -l)" 121 err=1 122 exit 123 fi 124 125 if ! perf lock con -b true > /dev/null 2>&1 ; then 126 return 127 fi 128 129 # the perf lock contention output goes to the stderr 130 perf lock con -a -b -l -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} 131 if [ "$(cat "${result}" | wc -l)" != "1" ]; then 132 echo "[Fail] BPF result count is not 1:" "$(cat "${result}" | wc -l)" 133 err=1 134 exit 135 fi 136} 137 138test_aggr_cgroup() 139{ 140 echo "Testing perf lock contention --lock-cgroup" 141 142 if ! perf lock con -b true > /dev/null 2>&1 ; then 143 echo "[Skip] No BPF support" 144 return 145 fi 146 147 # the perf lock contention output goes to the stderr 148 perf lock con -a -b -g -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} 149 if [ "$(cat "${result}" | wc -l)" != "1" ]; then 150 echo "[Fail] BPF result count is not 1:" "$(cat "${result}" | wc -l)" 151 err=1 152 exit 153 fi 154} 155 156test_type_filter() 157{ 158 echo "Testing perf lock contention --type-filter (w/ spinlock)" 159 perf lock contention -i ${perfdata} -Y spinlock -q 2> ${result} 160 if [ "$(grep -c -v spinlock "${result}")" != "0" ]; then 161 echo "[Fail] Recorded result should not have non-spinlocks:" "$(cat "${result}")" 162 err=1 163 exit 164 fi 165 166 if ! perf lock con -b true > /dev/null 2>&1 ; then 167 return 168 fi 169 170 perf lock con -a -b -Y spinlock -q -- perf bench sched messaging -p > /dev/null 2> ${result} 171 if [ "$(grep -c -v spinlock "${result}")" != "0" ]; then 172 echo "[Fail] BPF result should not have non-spinlocks:" "$(cat "${result}")" 173 err=1 174 exit 175 fi 176} 177 178test_lock_filter() 179{ 180 echo "Testing perf lock contention --lock-filter (w/ tasklist_lock)" 181 perf lock contention -i ${perfdata} -l -q 2> ${result} 182 if [ "$(grep -c tasklist_lock "${result}")" != "1" ]; then 183 echo "[Skip] Could not find 'tasklist_lock'" 184 return 185 fi 186 187 perf lock contention -i ${perfdata} -L tasklist_lock -q 2> ${result} 188 189 # find out the type of tasklist_lock 190 test_lock_filter_type=$(head -1 "${result}" | awk '{ print $8 }' | sed -e 's/:.*//') 191 192 if [ "$(grep -c -v "${test_lock_filter_type}" "${result}")" != "0" ]; then 193 echo "[Fail] Recorded result should not have non-${test_lock_filter_type} locks:" "$(cat "${result}")" 194 err=1 195 exit 196 fi 197 198 if ! perf lock con -b true > /dev/null 2>&1 ; then 199 return 200 fi 201 202 perf lock con -a -b -L tasklist_lock -q -- perf bench sched messaging -p > /dev/null 2> ${result} 203 if [ "$(grep -c -v "${test_lock_filter_type}" "${result}")" != "0" ]; then 204 echo "[Fail] BPF result should not have non-${test_lock_filter_type} locks:" "$(cat "${result}")" 205 err=1 206 exit 207 fi 208} 209 210test_stack_filter() 211{ 212 echo "Testing perf lock contention --callstack-filter (w/ unix_stream)" 213 perf lock contention -i ${perfdata} -v -q 2> ${result} 214 if [ "$(grep -c unix_stream "${result}")" = "0" ]; then 215 echo "[Skip] Could not find 'unix_stream'" 216 return 217 fi 218 219 perf lock contention -i ${perfdata} -E 1 -S unix_stream -q 2> ${result} 220 if [ "$(cat "${result}" | wc -l)" != "1" ]; then 221 echo "[Fail] Recorded result should have a lock from unix_stream:" "$(cat "${result}")" 222 err=1 223 exit 224 fi 225 226 if ! perf lock con -b true > /dev/null 2>&1 ; then 227 return 228 fi 229 230 perf lock con -a -b -S unix_stream -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} 231 if [ "$(cat "${result}" | wc -l)" != "1" ]; then 232 echo "[Fail] BPF result should have a lock from unix_stream:" "$(cat "${result}")" 233 err=1 234 exit 235 fi 236} 237 238test_aggr_task_stack_filter() 239{ 240 echo "Testing perf lock contention --callstack-filter with task aggregation" 241 perf lock contention -i ${perfdata} -v -q 2> ${result} 242 if [ "$(grep -c unix_stream "${result}")" = "0" ]; then 243 echo "[Skip] Could not find 'unix_stream'" 244 return 245 fi 246 247 perf lock contention -i ${perfdata} -t -E 1 -S unix_stream -q 2> ${result} 248 if [ "$(cat "${result}" | wc -l)" != "1" ]; then 249 echo "[Fail] Recorded result should have a task from unix_stream:" "$(cat "${result}")" 250 err=1 251 exit 252 fi 253 254 if ! perf lock con -b true > /dev/null 2>&1 ; then 255 return 256 fi 257 258 perf lock con -a -b -t -S unix_stream -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result} 259 if [ "$(cat "${result}" | wc -l)" != "1" ]; then 260 echo "[Fail] BPF result should have a task from unix_stream:" "$(cat "${result}")" 261 err=1 262 exit 263 fi 264} 265test_cgroup_filter() 266{ 267 echo "Testing perf lock contention --cgroup-filter" 268 269 if ! perf lock con -b true > /dev/null 2>&1 ; then 270 echo "[Skip] No BPF support" 271 return 272 fi 273 274 perf lock con -a -b -g -E 1 -F wait_total -q -- perf bench sched messaging -p > /dev/null 2> ${result} 275 if [ "$(cat "${result}" | wc -l)" != "1" ]; then 276 echo "[Fail] BPF result should have a cgroup result:" "$(cat "${result}")" 277 err=1 278 exit 279 fi 280 281 cgroup=$(cat "${result}" | awk '{ print $3 }') 282 perf lock con -a -b -g -E 1 -G "${cgroup}" -q -- perf bench sched messaging -p > /dev/null 2> ${result} 283 if [ "$(cat "${result}" | wc -l)" != "1" ]; then 284 echo "[Fail] BPF result should have a result with cgroup filter:" "$(cat "${cgroup}")" 285 err=1 286 exit 287 fi 288} 289 290 291test_csv_output() 292{ 293 echo "Testing perf lock contention CSV output" 294 perf lock contention -i ${perfdata} -E 1 -x , --output ${result} 295 # count the number of commas in the header 296 # it should have 5: contended, total-wait, max-wait, avg-wait, type, caller 297 header=$(grep "# output:" ${result} | tr -d -c , | wc -c) 298 if [ "${header}" != "5" ]; then 299 echo "[Fail] Recorded result does not have enough output columns: ${header} != 5" 300 err=1 301 exit 302 fi 303 # count the number of commas in the output 304 output=$(grep -v "^#" ${result} | tr -d -c , | wc -c) 305 if [ "${header}" != "${output}" ]; then 306 echo "[Fail] Recorded result does not match the number of commas: ${header} != ${output}" 307 err=1 308 exit 309 fi 310 311 if ! perf lock con -b true > /dev/null 2>&1 ; then 312 echo "[Skip] No BPF support" 313 return 314 fi 315 316 # the perf lock contention output goes to the stderr 317 perf lock con -a -b -E 1 -x , --output ${result} -- perf bench sched messaging -p > /dev/null 2>&1 318 output=$(grep -v "^#" ${result} | tr -d -c , | wc -c) 319 if [ "${header}" != "${output}" ]; then 320 echo "[Fail] BPF result does not match the number of commas: ${header} != ${output}" 321 err=1 322 exit 323 fi 324} 325 326check 327 328test_record 329test_bpf 330test_record_concurrent 331test_aggr_task 332test_aggr_addr 333test_aggr_cgroup 334test_type_filter 335test_lock_filter 336test_stack_filter 337test_aggr_task_stack_filter 338test_cgroup_filter 339test_csv_output 340 341exit ${err} 342