summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Rogers <irogers@google.com>2026-09-28 23:58:32 -0700
committerArnaldo Carvalho de Melo <acme@redhat.com>2026-09-29 20:51:06 +0200
commitac6e4e290bd8a0ae9c12c148b62f2be4b5d7a422 (patch)
tree112b8cd3a0c4cb3e89bb05914d7f2c2acfde1ae9
parent7c89ea1bd4c612eb5cc2e6c01f77ebfc21d5c95d (diff)
downloadlinux-next-ac6e4e290bd8a0ae9c12c148b62f2be4b5d7a422.tar.gz
linux-next-ac6e4e290bd8a0ae9c12c148b62f2be4b5d7a422.zip
perf python sctop: Fix offline interval printing and test flakiness
In sctop.py: - If an earlier interval elapsed and printed an empty table before the target comm ('sleep') executed any syscalls, analyzer.printed became True and the final partial interval containing the target comm's syscalls was never flushed at EOF. Flush print_current_totals() in finally when analyzer.syscalls is non-empty as well as when nothing has been printed yet. - Initialize analyzer.e_machine after creating perf.session rather than when session is still None. In test_sctop_python.sh: - Use a private temporary directory via 'mktemp -d'. - Drop '-a' and pass '-B -N --no-bpf-event' to 'perf record', and sleep briefly in the subshell ('sh -c "sleep 0.1; sleep 0.05"') with a bounded retry loop so 'sleep's PERF_RECORD_COMM and sys_enter events are reliably captured under heavy load. Fixes: b83f0bacf5e4f936 ("perf python: Port sctop to perf module") Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers <irogers@google.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rwxr-xr-xtools/perf/python/sctop.py7
-rwxr-xr-xtools/perf/tests/shell/test_sctop_python.sh58
2 files changed, 34 insertions, 31 deletions
diff --git a/tools/perf/python/sctop.py b/tools/perf/python/sctop.py
index 42e95ecfffad..48320af8b755 100755
--- a/tools/perf/python/sctop.py
+++ b/tools/perf/python/sctop.py
@@ -37,6 +37,7 @@ class SCTopAnalyzer:
self.offline = offline
self.own_pid = os.getpid()
self.last_print_time: Optional[int] = None
+ self.printed = False
self.session: Optional[perf.session] = None
self.e_machine: Optional[int] = None
@@ -137,6 +138,7 @@ class SCTopAnalyzer:
def print_current_totals(self):
"""Print current syscall totals."""
+ self.printed = True
# Clear terminal
if not self.offline:
print("\x1b[2J\x1b[H", end="")
@@ -217,8 +219,8 @@ def main():
if args.input:
session = perf.session(perf.data(args.input), sample=analyzer.process_event)
analyzer.session = session
- session.process_events()
analyzer.e_machine = getattr(session, "e_machine", None)
+ session.process_events()
else:
try:
live_session = LiveSession(
@@ -237,7 +239,8 @@ def main():
sys.exit(1)
finally:
if args.input:
- analyzer.print_current_totals()
+ if not analyzer.printed or analyzer.syscalls:
+ analyzer.print_current_totals()
# Break the reference cycle between perf.session and analyzer.process_event
# because perf.session lacks cyclic GC support (tp_traverse).
analyzer.session = None
diff --git a/tools/perf/tests/shell/test_sctop_python.sh b/tools/perf/tests/shell/test_sctop_python.sh
index 007f2584cce6..b042fc3eefe5 100755
--- a/tools/perf/tests/shell/test_sctop_python.sh
+++ b/tools/perf/tests/shell/test_sctop_python.sh
@@ -27,51 +27,51 @@ if [ ! -f "$script_path" ]; then
fi
err=0
-temp_data=""
-temp_out=""
+temp_dir=$(mktemp -d /tmp/perf-sctop-XXXXXX)
+temp_data="${temp_dir}/perf.data"
+temp_out="${temp_dir}/perf.out"
cleanup() {
- rm -f "${temp_data}" "${temp_out}"
+ rm -rf "${temp_dir}"
}
trap 'cleanup' EXIT TERM INT
-temp_data=$(mktemp /tmp/perf.data.XXXXXX)
-temp_out=$(mktemp /tmp/perf.out.XXXXXX)
-
echo "Testing sctop.py..."
# Create a perf.data file.
-if perf list | grep -q "raw_syscalls:sys_enter"; then
- perf record -e raw_syscalls:sys_enter -a -o "${temp_data}" \
- -- sleep 0.1 >/dev/null 2>&1 || \
- { echo "Skipping test, perf record failed"; exit 2; }
-else
+if ! perf list tracepoint | grep -q "raw_syscalls:sys_enter"; then
echo "Skipping test, no raw_syscalls:sys_enter event"
exit 2
fi
-if [ ! -s "${temp_data}" ]; then
- echo "Skipping test, perf record failed to create data"
- exit 2
-fi
+passed=0
+for _ in 1 2 3 4 5; do
+ rm -f "${temp_data}" "${temp_out}"
+ if ! perf record -B -N --no-bpf-event -e raw_syscalls:sys_enter -o "${temp_data}" \
+ -- sh -c "sleep 0.1; sleep 0.05" >/dev/null 2>&1; then
+ echo "Skipping test, perf record failed"
+ exit 2
+ fi
-# Check that the script executes
-if ! perf script sctop -i "${temp_data}" > "${temp_out}"; then
+ if [ ! -s "${temp_data}" ]; then
+ continue
+ fi
+
+ # Check that the script executes
+ if perf script sctop -i "${temp_data}" > "${temp_out}" && \
+ grep -E -q "[0-9]+$" "${temp_out}" && \
+ perf script sctop -i "${temp_data}" sleep 1 > "${temp_out}" && \
+ grep -E -q "[0-9]+$" "${temp_out}"; then
+ passed=1
+ break
+ fi
+done
+
+if [ "$passed" -eq 0 ]; then
echo "sctop.py test failed"
err=1
-elif ! grep -E -q "[0-9]+$" "${temp_out}"; then
- echo "Failed to find metric data rows in default run"
- err=1
-elif ! perf script sctop -i "${temp_data}" sleep 1 > "${temp_out}"; then
- echo "sctop.py comm+interval test failed"
- err=1
else
- if ! grep -E -q "[0-9]+$" "${temp_out}"; then
- echo "Failed to find metric data rows"
- err=1
- else
- echo "sctop test passed."
- fi
+ echo "sctop test passed."
fi
rm -f "${temp_out}"