#!/usr/bin/env python3 """Ukur CPU + output pty binary TUI tia (Phase 0). Dipakai untuk spike T-0.4 (docs/spikes/T-0.4-animasi.md): fase 1 animasi 30 FPS menyala, fase 2 setelah tombol 'a' (reduced-motion). Pakai: python3 scripts/measure-cpu.py [./tia-love] [detik-per-fase] """ import fcntl import os import pty import signal import struct import sys import termios import threading import time BIN = sys.argv[1] if len(sys.argv) > 1 else "./tia-love" SECS = float(sys.argv[2]) if len(sys.argv) > 2 else 8.0 ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) pid, fd = pty.fork() if pid == 0: os.chdir(ROOT) os.execvp("timeout", ["timeout", str(int(SECS * 2 + 10)), BIN]) fcntl.ioctl(fd, termios.TIOCSWINSZ, struct.pack("HHHH", 40, 120, 0, 0)) nbytes = [0] def drain(): while True: try: b = os.read(fd, 65536) except OSError: return if not b: return nbytes[0] += len(b) threading.Thread(target=drain, daemon=True).start() def app_pid(): """PID anak (binary tia), bukan PID `timeout`.""" for _ in range(50): try: kids = open(f"/proc/{pid}/task/{pid}/children").read().split() if kids: return int(kids[0]) except FileNotFoundError: pass time.sleep(0.1) return pid apid = app_pid() print("monitoring PID:", apid) HZ = os.sysconf("SC_CLK_TCK") def cpu(): p = open(f"/proc/{apid}/stat").read().split() return (int(p[13]) + int(p[14])) / HZ def phase(label): b0, c0, t0 = nbytes[0], cpu(), time.time() time.sleep(SECS) b1, c1, t1 = nbytes[0], cpu(), time.time() print(f"{label:<38} CPU {100 * (c1 - c0) / (t1 - t0):5.2f}% ยท output pty {(b1 - b0) / (t1 - t0) / 1024:5.1f} KB/s") time.sleep(3) # warmup phase("FASE 1 (animasi 30fps)") os.write(fd, b"t") # picu toast time.sleep(3.5) os.write(fd, b"a") # reduced-motion time.sleep(1) phase("FASE 2 (reduced-motion)") try: os.kill(pid, signal.SIGKILL) except ProcessLookupError: pass print("selesai")