xref: /linux/tools/perf/tests/shell/lock_contention.sh (revision 998ccc327b14c03861247540ff6f8135a5283621)
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