Files
linux/tools/perf/tests/shell/lock_contention.sh
Ian Rogers 831068eed9 perf tests: Restore -p flag to lock contention test
Commit ae42a2a2a3 ("perf tests: Speed up lock contention analysis shell test")
in linux-next heavily optimized the test runtimes by switching the workload from
the default of 10 process groups down to 1 (`perf bench sched messaging -g 1`).

However, this change inadvertently dropped the original `-p` flag, causing the
benchmark to default to `socketpair()` instead of `pipe()`. While `socketpair()`
still generates some lock events on x86, it fails to trigger enough samples on
architectures like s390, causing the test suite to fail due to lack of captured
data.

Restore the omitted `-p` pipe flag. The test retains the massive speedups
achieved through the `-g 1` scaling, while producing a massive density of lock
events across all architectures to fully satisfy the BPF trace filtering logic.

Fixes: ae42a2a2a3 ("perf tests: Speed up lock contention analysis shell test")
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Thomas Richter <tmricht@linux.ibm.com>
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2026-07-09 17:44:22 -07:00

364 lines
9.7 KiB
Bash
Executable File

#!/bin/bash
# kernel lock contention analysis test
# SPDX-License-Identifier: GPL-2.0
set -e
err=0
perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
result=$(mktemp /tmp/__perf_test.result.XXXXX)
errout=$(mktemp /tmp/__perf_test.errout.XXXXX)
# Workload to generate lock contention.
# Using 1 group (-g 1) keeps runtime low while generating sufficient lock events.
# We include -p (pipes) because socketpairs don't generate enough lock events on s390.
msg_workload="perf bench sched messaging -g 1 -p"
cleanup() {
rm -f ${perfdata}
rm -f ${result}
rm -f ${errout}
trap - EXIT TERM INT ERR
}
trap_cleanup() {
if (( $? == 139 )); then #SIGSEGV
err=1
fi
echo "Unexpected signal in ${FUNCNAME[1]}"
cleanup
exit ${err}
}
trap trap_cleanup EXIT TERM INT ERR
check() {
if [ "$(id -u)" != 0 ]; then
echo "[Skip] No root permission"
err=2
exit
fi
if ! perf list tracepoint | grep -q lock:contention_begin; then
echo "[Skip] No lock contention tracepoints"
err=2
exit
fi
# shellcheck disable=SC2046
if [ `nproc` -lt 4 ]; then
echo "[Skip] Low number of CPUs (`nproc`), lock event cannot be triggered certainly"
err=2
exit
fi
}
test_record()
{
echo "Testing perf lock record and perf lock contention"
perf lock record -o ${perfdata} -- ${msg_workload} > /dev/null 2>&1
# the output goes to the stderr and we expect only 1 output (-E 1)
perf lock contention -i ${perfdata} -E 1 -q 2> ${result}
if [ "$(cat "${result}" | wc -l)" != "1" ]; then
echo "[Fail] Recorded result count is not 1:" "$(cat "${result}" | wc -l)"
err=1
exit
fi
}
test_bpf()
{
echo "Testing perf lock contention --use-bpf"
if ! perf lock con -b true > /dev/null 2>&1 ; then
echo "[Skip] No BPF support"
return
fi
# the perf lock contention output goes to the stderr
perf lock con -a -b -E 1 -q -- ${msg_workload} > /dev/null 2> ${result}
if [ "$(cat "${result}" | wc -l)" != "1" ]; then
echo "[Fail] BPF result count is not 1:" "$(cat "${result}" | wc -l)"
err=1
exit
fi
}
test_record_concurrent()
{
echo "Testing perf lock record and perf lock contention at the same time"
perf lock record -o- -- ${msg_workload} 2> ${errout} | \
perf lock contention -i- -E 1 -q 2> ${result}
if [ "$(cat "${result}" | wc -l)" != "1" ]; then
echo "[Fail] Recorded result count is not 1:" "$(cat "${result}" | wc -l)"
cat ${errout}
cat ${result}
err=1
exit
fi
}
test_aggr_task()
{
echo "Testing perf lock contention --threads"
perf lock contention -i ${perfdata} -t -E 1 -q 2> ${result}
if [ "$(cat "${result}" | wc -l)" != "1" ]; then
echo "[Fail] Recorded result count is not 1:" "$(cat "${result}" | wc -l)"
err=1
exit
fi
if ! perf lock con -b true > /dev/null 2>&1 ; then
return
fi
# the perf lock contention output goes to the stderr
perf lock con -a -b -t -E 1 -q -- ${msg_workload} > /dev/null 2> ${result}
if [ "$(cat "${result}" | wc -l)" != "1" ]; then
echo "[Fail] BPF result count is not 1:" "$(cat "${result}" | wc -l)"
err=1
exit
fi
}
test_aggr_addr()
{
echo "Testing perf lock contention --lock-addr"
perf lock contention -i ${perfdata} -l -E 1 -q 2> ${result}
if [ "$(cat "${result}" | wc -l)" != "1" ]; then
echo "[Fail] Recorded result count is not 1:" "$(cat "${result}" | wc -l)"
err=1
exit
fi
if ! perf lock con -b true > /dev/null 2>&1 ; then
return
fi
# the perf lock contention output goes to the stderr
perf lock con -a -b -l -E 1 -q -- ${msg_workload} > /dev/null 2> ${result}
if [ "$(cat "${result}" | wc -l)" != "1" ]; then
echo "[Fail] BPF result count is not 1:" "$(cat "${result}" | wc -l)"
err=1
exit
fi
}
test_aggr_cgroup()
{
echo "Testing perf lock contention --lock-cgroup"
if ! perf lock con -b true > /dev/null 2>&1 ; then
echo "[Skip] No BPF support"
return
fi
# the perf lock contention output goes to the stderr
perf lock con -a -b --lock-cgroup -E 1 -q -- ${msg_workload} > /dev/null 2> ${result}
if [ "$(cat "${result}" | wc -l)" != "1" ]; then
echo "[Fail] BPF result count is not 1:" "$(cat "${result}" | wc -l)"
err=1
exit
fi
}
test_type_filter()
{
echo "Testing perf lock contention --type-filter (w/ spinlock)"
perf lock contention -i ${perfdata} -Y spinlock -q 2> ${result}
if [ "$(grep -c -v spinlock "${result}")" != "0" ]; then
echo "[Fail] Recorded result should not have non-spinlocks:" "$(cat "${result}")"
err=1
exit
fi
if ! perf lock con -b true > /dev/null 2>&1 ; then
return
fi
perf lock con -a -b -Y spinlock -q -- ${msg_workload} > /dev/null 2> ${result}
if [ "$(grep -c -v spinlock "${result}")" != "0" ]; then
echo "[Fail] BPF result should not have non-spinlocks:" "$(cat "${result}")"
err=1
exit
fi
}
test_lock_filter()
{
echo "Testing perf lock contention --lock-filter (w/ tasklist_lock)"
perf lock contention -i ${perfdata} -l -q 2> ${result}
if [ "$(grep -c tasklist_lock "${result}")" != "1" ]; then
echo "[Skip] Could not find 'tasklist_lock'"
return
fi
perf lock contention -i ${perfdata} -L tasklist_lock -q 2> ${result}
# find out the type of tasklist_lock
test_lock_filter_type=$(head -1 "${result}" | awk '{ print $8 }' | sed -e 's/:.*//')
if [ "$(grep -c -v "${test_lock_filter_type}" "${result}")" != "0" ]; then
echo "[Fail] Recorded result should not have non-${test_lock_filter_type} locks:" "$(cat "${result}")"
err=1
exit
fi
if ! perf lock con -b true > /dev/null 2>&1 ; then
return
fi
perf lock con -a -b -L tasklist_lock -q -- ${msg_workload} > /dev/null 2> ${result}
if [ "$(grep -c -v "${test_lock_filter_type}" "${result}")" != "0" ]; then
echo "[Fail] BPF result should not have non-${test_lock_filter_type} locks:" "$(cat "${result}")"
err=1
exit
fi
perf lock con -b -L mmap_lock -q -- perf bench mem mmap -t 2 -l 10 > /dev/null 2> ${result}
# find out the type of mmap_lock
test_lock_filter_type=$(head -1 "${result}" | awk '{ print $8 }' | sed -e 's/:.*//')
if [ "$(grep -c -v "${test_lock_filter_type}" "${result}")" != "0" ]; then
echo "[Fail] BPF result should not have non-${test_lock_filter_type} locks:" "$(cat "${result}")"
err=1
exit
fi
}
test_stack_filter()
{
echo "Testing perf lock contention --callstack-filter (w/ unix_stream)"
perf lock contention -i ${perfdata} -v -q 2> ${result}
if [ "$(grep -c unix_stream "${result}")" = "0" ]; then
echo "[Skip] Could not find 'unix_stream'"
return
fi
perf lock contention -i ${perfdata} -E 1 -S unix_stream -q 2> ${result}
if [ "$(cat "${result}" | wc -l)" != "1" ]; then
echo "[Fail] Recorded result should have a lock from unix_stream:" "$(cat "${result}")"
err=1
exit
fi
if ! perf lock con -b true > /dev/null 2>&1 ; then
return
fi
perf lock con -a -b -S unix_stream -E 1 -q -- ${msg_workload} > /dev/null 2> ${result}
if [ "$(cat "${result}" | wc -l)" != "1" ]; then
echo "[Fail] BPF result should have a lock from unix_stream:" "$(cat "${result}")"
err=1
exit
fi
}
test_aggr_task_stack_filter()
{
echo "Testing perf lock contention --callstack-filter with task aggregation"
perf lock contention -i ${perfdata} -v -q 2> ${result}
if [ "$(grep -c unix_stream "${result}")" = "0" ]; then
echo "[Skip] Could not find 'unix_stream'"
return
fi
perf lock contention -i ${perfdata} -t -E 1 -S unix_stream -q 2> ${result}
if [ "$(cat "${result}" | wc -l)" != "1" ]; then
echo "[Fail] Recorded result should have a task from unix_stream:" "$(cat "${result}")"
err=1
exit
fi
if ! perf lock con -b true > /dev/null 2>&1 ; then
return
fi
perf lock con -a -b -t -S unix_stream -E 1 -q -- ${msg_workload} > /dev/null 2> ${result}
if [ "$(cat "${result}" | wc -l)" != "1" ]; then
echo "[Fail] BPF result should have a task from unix_stream:" "$(cat "${result}")"
err=1
exit
fi
}
test_cgroup_filter()
{
echo "Testing perf lock contention --cgroup-filter"
if ! perf lock con -b true > /dev/null 2>&1 ; then
echo "[Skip] No BPF support"
return
fi
perf lock con -a -b --lock-cgroup -E 1 -F wait_total -q \
-- ${msg_workload} > /dev/null 2> ${result}
if [ "$(cat "${result}" | wc -l)" != "1" ]; then
echo "[Fail] BPF result should have a cgroup result:" "$(cat "${result}")"
err=1
exit
fi
cgroup=$(cat "${result}" | awk '{ print $3 }')
perf lock con -a -b --lock-cgroup -E 1 -G "${cgroup}" -q \
-- ${msg_workload} > /dev/null 2> ${result}
if [ "$(cat "${result}" | wc -l)" != "1" ]; then
echo "[Fail] BPF result should have a result with cgroup filter:" "$(cat "${cgroup}")"
err=1
exit
fi
}
test_csv_output()
{
echo "Testing perf lock contention CSV output"
perf lock contention -i ${perfdata} -E 1 -x , --output ${result}
# count the number of commas in the header
# it should have 5: contended, total-wait, max-wait, avg-wait, type, caller
header=$(grep "# output:" ${result} | tr -d -c , | wc -c)
if [ "${header}" != "5" ]; then
echo "[Fail] Recorded result does not have enough output columns: ${header} != 5"
err=1
exit
fi
# count the number of commas in the output
output=$(grep -v "^#" ${result} | tr -d -c , | wc -c)
if [ "${header}" != "${output}" ]; then
echo "[Fail] Recorded result does not match the number of commas: ${header} != ${output}"
err=1
exit
fi
if ! perf lock con -b true > /dev/null 2>&1 ; then
echo "[Skip] No BPF support"
return
fi
# the perf lock contention output goes to the stderr
perf lock con -a -b -E 1 -x , --output ${result} -- ${msg_workload} > /dev/null 2>&1
output=$(grep -v "^#" ${result} | tr -d -c , | wc -c)
if [ "${header}" != "${output}" ]; then
echo "[Fail] BPF result does not match the number of commas: ${header} != ${output}"
err=1
exit
fi
}
check
test_record
test_bpf
test_record_concurrent
test_aggr_task
test_aggr_addr
test_aggr_cgroup
test_type_filter
test_lock_filter
test_stack_filter
test_aggr_task_stack_filter
test_cgroup_filter
test_csv_output
cleanup
exit ${err}