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