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