projects/linux·blob master · refs

363 lines · 9.7 KiB

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