Files
linux/tools/perf/tests/shell/record_offcpu.sh
James Clark 2f5d370dec perf test: Change all remaining #!/bin/sh to #!/bin/bash
There are 43 instances of posix shell tests and 35 instances of bash. To
give us a single consistent language for testing in, replace
all #!/bin/sh to #!/bin/bash. Common sources that are included in both
different shells will now work as expected. And we no longer have to fix
up bashisms that appear to work when someone's system has sh symlinked
to bash, but don't work on other systems that have both shells
installed.

Although we could have chosen sh, it's not backwards compatible so it
wouldn't be possible to bulk convert without re-writing the existing
bash tests.

Choosing bash also gives us some nicer features including 'local'
variable definitions and regexes in if statements that are already
widely used in the tests.

It's not expected that there are any users with only sh available due to
the large number of bash tests that exist.

Discussed in relation to running shellcheck here:
https://lore.kernel.org/linux-perf-users/e3751a74be34bbf3781c4644f518702a7270220b.1749785642.git.collin.funk1@gmail.com/

Signed-off-by: James Clark <james.clark@linaro.org>
Reviewed-by: Collin Funk <collin.funk1@gmail.com>
Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: https://lore.kernel.org/r/20250623-james-perf-bash-tests-v1-1-f572f54d4559@linaro.org
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
2025-06-26 10:31:05 -07:00

175 lines
4.4 KiB
Bash
Executable File

#!/bin/bash
# perf record offcpu profiling tests (exclusive)
# SPDX-License-Identifier: GPL-2.0
set -e
err=0
perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
ts=$(printf "%u" $((~0 << 32))) # OFF_CPU_TIMESTAMP
dummy_timestamp=${ts%???} # remove the last 3 digits to match perf script
cleanup() {
rm -f ${perfdata}
rm -f ${perfdata}.old
trap - EXIT TERM INT
}
trap_cleanup() {
cleanup
exit 1
}
trap trap_cleanup EXIT TERM INT
test_above_thresh="Threshold test (above threshold)"
test_below_thresh="Threshold test (below threshold)"
test_offcpu_priv() {
echo "Checking off-cpu privilege"
if [ "$(id -u)" != 0 ]
then
echo "off-cpu test [Skipped permission]"
err=2
return
fi
if perf version --build-options 2>&1 | grep HAVE_BPF_SKEL | grep -q OFF
then
echo "off-cpu test [Skipped missing BPF support]"
err=2
return
fi
}
test_offcpu_basic() {
echo "Basic off-cpu test"
if ! perf record --off-cpu -e dummy -o ${perfdata} sleep 1 2> /dev/null
then
echo "Basic off-cpu test [Failed record]"
err=1
return
fi
if ! perf evlist -i ${perfdata} | grep -q "offcpu-time"
then
echo "Basic off-cpu test [Failed no event]"
err=1
return
fi
if ! perf report -i ${perfdata} -q --percent-limit=90 | grep -E -q sleep
then
echo "Basic off-cpu test [Failed missing output]"
err=1
return
fi
echo "Basic off-cpu test [Success]"
}
test_offcpu_child() {
echo "Child task off-cpu test"
# perf bench sched messaging creates 400 processes
if ! perf record --off-cpu -e dummy -o ${perfdata} -- \
perf bench sched messaging -g 10 > /dev/null 2>&1
then
echo "Child task off-cpu test [Failed record]"
err=1
return
fi
if ! perf evlist -i ${perfdata} | grep -q "offcpu-time"
then
echo "Child task off-cpu test [Failed no event]"
err=1
return
fi
# each process waits at least for poll, so it should be more than 400 events
if ! perf report -i ${perfdata} -s comm -q -n -t ';' --percent-limit=90 | \
awk -F ";" '{ if (NF > 3 && int($3) < 400) exit 1; }'
then
echo "Child task off-cpu test [Failed invalid output]"
err=1
return
fi
echo "Child task off-cpu test [Success]"
}
# task blocks longer than the --off-cpu-thresh, perf should collect a direct sample
test_offcpu_above_thresh() {
echo "${test_above_thresh}"
# collect direct off-cpu samples for tasks blocked for more than 999ms
if ! perf record -e dummy --off-cpu --off-cpu-thresh 999 -o ${perfdata} -- sleep 1 2> /dev/null
then
echo "${test_above_thresh} [Failed record]"
err=1
return
fi
# direct sample's timestamp should be lower than the dummy_timestamp of the at-the-end sample
# check if a direct sample exists
if ! perf script --time "0, ${dummy_timestamp}" -i ${perfdata} -F event | grep -q "offcpu-time"
then
echo "${test_above_thresh} [Failed missing direct samples]"
err=1
return
fi
# there should only be one direct sample, and its period should be higher than off-cpu-thresh
if ! perf script --time "0, ${dummy_timestamp}" -i ${perfdata} -F period | \
awk '{ if (int($1) > 999000000) exit 0; else exit 1; }'
then
echo "${test_above_thresh} [Failed off-cpu time too short]"
err=1
return
fi
echo "${test_above_thresh} [Success]"
}
# task blocks shorter than the --off-cpu-thresh, perf should collect an at-the-end sample
test_offcpu_below_thresh() {
echo "${test_below_thresh}"
# collect direct off-cpu samples for tasks blocked for more than 1.2s
if ! perf record -e dummy --off-cpu --off-cpu-thresh 1200 -o ${perfdata} -- sleep 1 2> /dev/null
then
echo "${test_below_thresh} [Failed record]"
err=1
return
fi
# see if there's an at-the-end sample
if ! perf script --time "${dummy_timestamp}," -i ${perfdata} -F event | grep -q 'offcpu-time'
then
echo "${test_below_thresh} [Failed at-the-end samples cannot be found]"
err=1
return
fi
# plus there shouldn't be any direct samples
if perf script --time "0, ${dummy_timestamp}" -i ${perfdata} -F event | grep -q 'offcpu-time'
then
echo "${test_below_thresh} [Failed direct samples are found when they shouldn't be]"
err=1
return
fi
echo "${test_below_thresh} [Success]"
}
test_offcpu_priv
if [ $err = 0 ]; then
test_offcpu_basic
fi
if [ $err = 0 ]; then
test_offcpu_child
fi
if [ $err = 0 ]; then
test_offcpu_above_thresh
fi
if [ $err = 0 ]; then
test_offcpu_below_thresh
fi
cleanup
exit $err