diff options
Diffstat (limited to 'scripts/thread_instr.py')
| -rwxr-xr-x | scripts/thread_instr.py | 42 |
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() |
