"""Тренд памяти по записям сценария memory (Task 8). CLI: python -m perfkit.memtrend Читает /memory.jsonl, сортирует записи по metrics.cycle и печатает наклон МНК (единиц метрики на цикл) для heap_used_mb, nodes, js_event_listeners. """ from __future__ import annotations import json import sys from pathlib import Path METRICS = ("heap_used_mb", "nodes", "js_event_listeners") def slope_per_cycle(values: list[float]) -> float: """Наклон прямой МНК по точкам (0, v0), (1, v1), ... Меньше двух точек - ValueError.""" n = len(values) if n < 2: raise ValueError("нужно минимум две точки") mx = (n - 1) / 2 my = sum(values) / n sxx = sum((i - mx) ** 2 for i in range(n)) sxy = sum((i - mx) * (v - my) for i, v in enumerate(values)) return sxy / sxx def load_memory(run_dir) -> list[dict]: f = Path(run_dir) / "memory.jsonl" recs = [] for line in f.read_text(encoding="utf-8").splitlines(): if not line.strip(): continue r = json.loads(line) if r.get("scenario") == "memory": recs.append(r) return sorted(recs, key=lambda r: r["metrics"]["cycle"]) def main(argv: list[str] | None = None) -> int: argv = sys.argv[1:] if argv is None else argv if len(argv) != 1: print("usage: python -m perfkit.memtrend ", file=sys.stderr) return 2 recs = load_memory(argv[0]) print(f"циклов (записей): {len(recs)}") for m in METRICS: vals = [float(r["metrics"][m]) for r in recs] print(f"{m}: {slope_per_cycle(vals):.3f} на цикл (первый {vals[0]:.1f}, последний {vals[-1]:.1f})") return 0 if __name__ == "__main__": sys.exit(main())