Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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}