aboutsummaryrefslogtreecommitdiffziptar.gz
path: root/scripts/thread_instr.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/thread_instr.py')
-rwxr-xr-xscripts/thread_instr.py42
1 files changed, 42 insertions, 0 deletions
diff --git a/scripts/thread_instr.py b/scripts/thread_instr.py
new file mode 100755
index 0000000..846d27f
--- /dev/null
+++ b/scripts/thread_instr.py
@@ -0,0 +1,42 @@
+#!/usr/bin/env python3
+"""User-space instructions per thread name over an interval (perf stat --per-thread) —
+a load-independent cost measure: CPU % swings with other work on the machine and
+clock speed, retired instructions don't (smoke_run.sh step `instr:<s>`).
+
+Usage: scripts/thread_instr.py PID SECONDS
+"""
+import re
+import subprocess
+import sys
+from collections import defaultdict
+
+
+def parse(text):
+ """{thread name: instructions} from `perf stat --per-thread -x,` output."""
+ out = defaultdict(int)
+ for line in text.splitlines():
+ parts = line.split(",")
+ if len(parts) < 4 or "instructions" not in parts[3]:
+ continue
+ try:
+ count = int(parts[1])
+ except ValueError:
+ continue # <not counted>
+ out[re.sub(r"-\d+$", "", parts[0].strip())] += count
+ return out
+
+
+def main():
+ pid, seconds = sys.argv[1], float(sys.argv[2])
+ res = subprocess.run(["perf", "stat", "--per-thread", "-x,", "-e", "instructions:u", "-p", pid,
+ "--", "sleep", str(seconds)], capture_output=True, text=True)
+ counts = parse(res.stderr)
+ total = sum(counts.values())
+ print(f"instr: {total / seconds / 1e6:.0f} M/s total over {seconds:g}s")
+ for name, n in sorted(counts.items(), key=lambda kv: -kv[1])[:8]:
+ if n / seconds >= 1e6:
+ print(f" {n / seconds / 1e6:7.0f} M/s {name}")
+
+
+if __name__ == "__main__":
+ main()