xref: /linux/tools/perf/tests/shell/lock_contention.sh (revision 4cb5dd0379999af455941ab87d0b30c2ba7d9d66)
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	perf lock con -b -L mmap_lock -q -- perf bench mem mmap -t 2 -l 10 > /dev/null 2> ${result}
213
214	# find out the type of mmap_lock
215	test_lock_filter_type=$(head -1 "${result}" | awk '{ print $8 }' | sed -e 's/:.*//')
216
217	if [ "$(grep -c -v "${test_lock_filter_type}" "${result}")" != "0" ]; then
218		echo "[Fail] BPF result should not have non-${test_lock_filter_type} locks:" "$(cat "${result}")"
219		err=1
220		exit
221	fi
222}
223
224test_stack_filter()
225{
226	echo "Testing perf lock contention --callstack-filter (w/ unix_stream)"
227	perf lock contention -i ${perfdata} -v -q 2> ${result}
228	if [ "$(grep -c unix_stream "${result}")" = "0" ]; then
229		echo "[Skip] Could not find 'unix_stream'"
230		return
231	fi
232
233	perf lock contention -i ${perfdata} -E 1 -S unix_stream -q 2> ${result}
234	if [ "$(cat "${result}" | wc -l)" != "1" ]; then
235		echo "[Fail] Recorded result should have a lock from unix_stream:" "$(cat "${result}")"
236		err=1
237		exit
238	fi
239
240	if ! perf lock con -b true > /dev/null 2>&1 ; then
241		return
242	fi
243
244	perf lock con -a -b -S unix_stream -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result}
245	if [ "$(cat "${result}" | wc -l)" != "1" ]; then
246		echo "[Fail] BPF result should have a lock from unix_stream:" "$(cat "${result}")"
247		err=1
248		exit
249	fi
250}
251
252test_aggr_task_stack_filter()
253{
254	echo "Testing perf lock contention --callstack-filter with task aggregation"
255	perf lock contention -i ${perfdata} -v -q 2> ${result}
256	if [ "$(grep -c unix_stream "${result}")" = "0" ]; then
257		echo "[Skip] Could not find 'unix_stream'"
258		return
259	fi
260
261	perf lock contention -i ${perfdata} -t -E 1 -S unix_stream -q 2> ${result}
262	if [ "$(cat "${result}" | wc -l)" != "1" ]; then
263		echo "[Fail] Recorded result should have a task from unix_stream:" "$(cat "${result}")"
264		err=1
265		exit
266	fi
267
268	if ! perf lock con -b true > /dev/null 2>&1 ; then
269		return
270	fi
271
272	perf lock con -a -b -t -S unix_stream -E 1 -q -- perf bench sched messaging -p > /dev/null 2> ${result}
273	if [ "$(cat "${result}" | wc -l)" != "1" ]; then
274		echo "[Fail] BPF result should have a task from unix_stream:" "$(cat "${result}")"
275		err=1
276		exit
277	fi
278}
279test_cgroup_filter()
280{
281	echo "Testing perf lock contention --cgroup-filter"
282
283	if ! perf lock con -b true > /dev/null 2>&1 ; then
284		echo "[Skip] No BPF support"
285		return
286	fi
287
288	perf lock con -a -b --lock-cgroup -E 1 -F wait_total -q -- perf bench sched messaging -p > /dev/null 2> ${result}
289	if [ "$(cat "${result}" | wc -l)" != "1" ]; then
290		echo "[Fail] BPF result should have a cgroup result:" "$(cat "${result}")"
291		err=1
292		exit
293	fi
294
295	cgroup=$(cat "${result}" | awk '{ print $3 }')
296	perf lock con -a -b --lock-cgroup -E 1 -G "${cgroup}" -q -- perf bench sched messaging -p > /dev/null 2> ${result}
297	if [ "$(cat "${result}" | wc -l)" != "1" ]; then
298		echo "[Fail] BPF result should have a result with cgroup filter:" "$(cat "${cgroup}")"
299		err=1
300		exit
301	fi
302}
303
304
305test_csv_output()
306{
307	echo "Testing perf lock contention CSV output"
308	perf lock contention -i ${perfdata} -E 1 -x , --output ${result}
309	# count the number of commas in the header
310	# it should have 5: contended, total-wait, max-wait, avg-wait, type, caller
311	header=$(grep "# output:" ${result} | tr -d -c , | wc -c)
312	if [ "${header}" != "5" ]; then
313		echo "[Fail] Recorded result does not have enough output columns: ${header} != 5"
314		err=1
315		exit
316	fi
317	# count the number of commas in the output
318	output=$(grep -v "^#" ${result} | tr -d -c , | wc -c)
319	if [ "${header}" != "${output}" ]; then
320		echo "[Fail] Recorded result does not match the number of commas: ${header} != ${output}"
321		err=1
322		exit
323	fi
324
325	if ! perf lock con -b true > /dev/null 2>&1 ; then
326		echo "[Skip] No BPF support"
327		return
328	fi
329
330	# the perf lock contention output goes to the stderr
331	perf lock con -a -b -E 1 -x , --output ${result} -- perf bench sched messaging -p > /dev/null 2>&1
332	output=$(grep -v "^#" ${result} | tr -d -c , | wc -c)
333	if [ "${header}" != "${output}" ]; then
334		echo "[Fail] BPF result does not match the number of commas: ${header} != ${output}"
335		err=1
336		exit
337	fi
338}
339
340check
341
342test_record
343test_bpf
344test_record_concurrent
345test_aggr_task
346test_aggr_addr
347test_aggr_cgroup
348test_type_filter
349test_lock_filter
350test_stack_filter
351test_aggr_task_stack_filter
352test_cgroup_filter
353test_csv_output
354
355cleanup
356exit ${err}
357