Files
tia-love/scripts/measure-cpu.py
T

90 lines
2.0 KiB
Python

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