diff options
| author | Ian Rogers <irogers@google.com> | 2026-09-28 23:58:32 -0700 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2026-09-29 20:51:06 +0200 |
| commit | ac6e4e290bd8a0ae9c12c148b62f2be4b5d7a422 (patch) | |
| tree | 112b8cd3a0c4cb3e89bb05914d7f2c2acfde1ae9 /tools/perf | |
| parent | 7c89ea1bd4c612eb5cc2e6c01f77ebfc21d5c95d (diff) | |
| download | linux-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>
Diffstat (limited to 'tools/perf')
| -rwxr-xr-x | tools/perf/python/sctop.py | 7 | ||||
| -rwxr-xr-x | tools/perf/tests/shell/test_sctop_python.sh | 58 |
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}" |
