#!/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()