55 lines
1.9 KiB
Python
55 lines
1.9 KiB
Python
"""Тренд памяти по записям сценария memory (Task 8).
|
||
|
||
CLI: python -m perfkit.memtrend <run_dir>
|
||
Читает <run_dir>/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 <run_dir>", 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())
|