mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Ian Rogers <irogers@google.com>
To: irogers@google.com, acme@kernel.org, namhyung@kernel.org
Cc: adrian.hunter@intel.com, james.clark@linaro.org,
	jolsa@kernel.org,  linux-kernel@vger.kernel.org,
	linux-perf-users@vger.kernel.org,  mingo@redhat.com,
	peterz@infradead.org
Subject: [PATCH v3 3/9] perf python stat-cpi: Fix live mode signal races and test flakiness
Date: Mon, 28 Sep 2026 23:58:33 -0700	[thread overview]
Message-ID: <20260929065839.407062-4-irogers@google.com> (raw)
In-Reply-To: <20260929065839.407062-1-irogers@google.com>

In test_stat_cpi_python.sh, 'perf test -w noploop &' defaults to a
1-second duration and can exit under heavy parallel load before
'perf stat -p' and 'perf script stat-cpi' finish starting up. In
addition, the fixed 'sleep 0.5' before sending SIGINT can fire before
Python finishes importing the perf module, opening the live evlist, and
flushing the first interval.

In stat-cpi.py, register SIGINT and SIGTERM handlers before calling
_open_live_evlist() and pass flush=True when printing live output so
redirected stdout is flushed immediately after each interval.

In test_stat_cpi_python.sh, run 'perf test -w noploop 60 &' so the
target workload stays alive until killed, and poll the output file for
'cpi' (up to 5 seconds) before sending SIGINT.

Fixes: 4425182d426b ("perf python: Port stat-cpi to perf module")
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Ian Rogers <irogers@google.com>
---
 tools/perf/python/stat-cpi.py                 | 32 +++++++++++++------
 .../perf/tests/shell/test_stat_cpi_python.sh  | 12 +++++--
 2 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/tools/perf/python/stat-cpi.py b/tools/perf/python/stat-cpi.py
index 0b7d76876a6c..b4ec87b07938 100755
--- a/tools/perf/python/stat-cpi.py
+++ b/tools/perf/python/stat-cpi.py
@@ -106,7 +106,8 @@ class StatCpiAnalyzer:
             if ins != 0:
                 cpi = cyc / float(ins)
             t_sec = timestamp / 1000000000.0
-            print(f"{t_sec:15f}: cpu {cpu}, thread {thread} -> cpi {cpi:f} ({cyc:.0f}/{ins:.0f})")
+            print(f"{t_sec:15f}: cpu {cpu}, thread {thread} -> cpi {cpi:f} ({cyc:.0f}/{ins:.0f})",
+                  flush=True)
 
     def read_counters(self, evlist: Any) -> None:
         """Read counters live."""
@@ -151,6 +152,7 @@ class StatCpiAnalyzer:
 
         last_err: Optional[OSError] = None
         for events, tmap in candidates:
+            evlist = None
             try:
                 evlist = perf.parse_events(events, None, tmap)
                 for evsel in evlist:
@@ -161,32 +163,41 @@ class StatCpiAnalyzer:
                 evlist.enable()
                 return evlist
             except PermissionError as e:
+                if evlist is not None:
+                    evlist.close()
                 last_err = e
             except OSError as e:
+                if evlist is not None:
+                    evlist.close()
                 if e.errno == 13:
                     last_err = e
                 else:
                     raise
+            except BaseException:
+                if evlist is not None:
+                    evlist.close()
+                raise
         if last_err is not None:
             raise last_err
         raise RuntimeError("Failed to open events")
 
     def run_live(self) -> None:
         """Read counters live."""
-        try:
-            evlist = self._open_live_evlist()
-        except OSError as e:
-            print(f"Failed to open events: {e}", file=sys.stderr)
-            sys.exit(1)
-
         def handle_signal(_signum: int, _frame: Any) -> None:
             raise KeyboardInterrupt
 
         signal.signal(signal.SIGINT, signal.default_int_handler)
         signal.signal(signal.SIGTERM, handle_signal)
 
-        print("Live mode started. Press Ctrl+C to stop.")
+        evlist = None
         try:
+            try:
+                evlist = self._open_live_evlist()
+            except OSError as e:
+                print(f"Failed to open events: {e}", file=sys.stderr)
+                sys.exit(1)
+
+            print("Live mode started. Press Ctrl+C to stop.", flush=True)
             while True:
                 time.sleep(self.args.interval)
                 timestamp = time.time_ns()
@@ -195,9 +206,10 @@ class StatCpiAnalyzer:
                 self.data.clear()
                 self.recorded_pairs.clear()
         except KeyboardInterrupt:
-            print("\nStopped.")
+            print("\nStopped.", flush=True)
         finally:
-            evlist.close()
+            if evlist is not None:
+                evlist.close()
 
 def main() -> None:
     """Main function."""
diff --git a/tools/perf/tests/shell/test_stat_cpi_python.sh b/tools/perf/tests/shell/test_stat_cpi_python.sh
index fe7562307634..6cb376c92e2f 100755
--- a/tools/perf/tests/shell/test_stat_cpi_python.sh
+++ b/tools/perf/tests/shell/test_stat_cpi_python.sh
@@ -50,7 +50,7 @@ test_live_mode() {
 		echo "perf stat failed (permissions?), skipping live mode test."
 		return 0
 	fi
-	perf test -w noploop &
+	perf test -w noploop 60 &
 	workload_pid=$!
 	if ! perf stat -e cycles,instructions -p "$workload_pid" -- sleep 0.05 2>/dev/null && \
 	   ! perf stat -e cycles:u,instructions:u -p "$workload_pid" -- sleep 0.05 2>/dev/null; then
@@ -61,10 +61,16 @@ test_live_mode() {
 	fi
 	ran=1
 
-	# Run live mode for 1 interval in the background, give it a tiny sleep, then interrupt
+	# Run live mode in the background, wait until at least one interval is
+	# printed, then interrupt.
 	perf script stat-cpi -I 0.1 -p "$workload_pid" > "${temp_out}" &
 	pid=$!
-	sleep 0.5
+	for _ in $(seq 1 50); do
+		if grep -q "cpi" "${temp_out}"; then
+			break
+		fi
+		sleep 0.1
+	done
 	kill -INT "$pid" 2>/dev/null || true
 	set +e
 	wait "$pid"
-- 
2.56.0.rc1.315.gc6ed9934b7-goog


  parent reply	other threads:[~2026-09-29  6:58 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-29  2:19 [PATCH v1 0/9] perf python: Follow-up fixes and shell test deflaking Ian Rogers
2026-09-29  2:19 ` [PATCH v1 1/9] perf evsel: Clamp sample_id size for ksymbol, bpf, and text_poke events Ian Rogers
2026-09-29  2:19 ` [PATCH v1 2/9] perf python sctop: Fix offline interval printing and test flakiness Ian Rogers
2026-09-29  2:19 ` [PATCH v1 3/9] perf python stat-cpi: Fix live mode signal races " Ian Rogers
2026-09-29  2:19 ` [PATCH v1 4/9] perf test: Deflake Intel PT Python shell tests under load Ian Rogers
2026-09-29  2:19 ` [PATCH v1 5/9] perf test: Deflake failed-syscalls " Ian Rogers
2026-09-29  2:19 ` [PATCH v1 6/9] perf test: Reduce overhead and contention in Python shell tests Ian Rogers
2026-09-29  2:19 ` [PATCH v1 7/9] perf python event_analyzing_sample: Default to in-memory SQLite database Ian Rogers
2026-09-29  2:19 ` [PATCH v1 8/9] perf python: Initialize debug output on module load Ian Rogers
2026-09-29  2:19 ` [PATCH v1 9/9] perf pmu: Fix race with concurrent tracepoint creation and removal in perf list Ian Rogers
2026-09-29  6:29 ` [PATCH v2 0/9] perf python: Follow-up fixes and shell test deflaking Ian Rogers
2026-09-29  6:29   ` [PATCH v2 1/9] perf evsel: Clamp sample_id size for ksymbol, bpf, and text_poke events Ian Rogers
2026-09-29  6:29   ` [PATCH v2 2/9] perf python sctop: Fix offline interval printing and test flakiness Ian Rogers
2026-09-29  6:29   ` [PATCH v2 3/9] perf python stat-cpi: Fix live mode signal races " Ian Rogers
2026-09-29  6:29   ` [PATCH v2 4/9] perf test: Deflake Intel PT Python shell tests under load Ian Rogers
2026-09-29  6:29   ` [PATCH v2 5/9] perf test: Deflake failed-syscalls " Ian Rogers
2026-09-29  6:29   ` [PATCH v2 6/9] perf test: Reduce overhead and contention in Python shell tests Ian Rogers
2026-09-29  6:29   ` [PATCH v2 7/9] perf python event_analyzing_sample: Default to in-memory SQLite database Ian Rogers
2026-09-29  6:29   ` [PATCH v2 8/9] perf python: Initialize debug output on module load Ian Rogers
2026-09-29  6:29   ` [PATCH v2 9/9] perf pmu: Fix race with concurrent tracepoint creation and removal in perf list Ian Rogers
2026-09-29  6:58   ` [PATCH v3 0/9] perf python: Follow-up fixes and shell test deflaking Ian Rogers
2026-09-29  6:58     ` [PATCH v3 1/9] perf evsel: Clamp sample_id size for ksymbol, bpf, and text_poke events Ian Rogers
2026-09-29  6:58     ` [PATCH v3 2/9] perf python sctop: Fix offline interval printing and test flakiness Ian Rogers
2026-09-29  6:58     ` Ian Rogers [this message]
2026-09-29  6:58     ` [PATCH v3 4/9] perf test: Deflake Intel PT Python shell tests under load Ian Rogers
2026-09-29  6:58     ` [PATCH v3 5/9] perf test: Deflake failed-syscalls " Ian Rogers
2026-09-29  6:58     ` [PATCH v3 6/9] perf test: Reduce overhead and contention in Python shell tests Ian Rogers
2026-09-29  6:58     ` [PATCH v3 7/9] perf python event_analyzing_sample: Default to in-memory SQLite database Ian Rogers
2026-09-29  6:58     ` [PATCH v3 8/9] perf python: Initialize debug output on module load Ian Rogers
2026-09-29  6:58     ` [PATCH v3 9/9] perf pmu: Fix race with concurrent tracepoint creation and removal in perf list Ian Rogers
2026-09-29 18:44     ` [PATCH v3 0/9] perf python: Follow-up fixes and shell test deflaking Arnaldo Carvalho de Melo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260929065839.407062-4-irogers@google.com \
    --to=irogers@google.com \
    --cc=acme@kernel.org \
    --cc=adrian.hunter@intel.com \
    --cc=james.clark@linaro.org \
    --cc=jolsa@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=namhyung@kernel.org \
    --cc=peterz@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®