DFiP_Budget_planing/perf/analysis/memory_cycles.py
Andrey Epifancev 8e9f53a478 perf: скрипты разбора и сводные данные прогонов 20261026
- perf/analysis: разбор trace (timeline_breakdown), CPU-профилей с source maps
  (cpuprofile_top), heap snapshots (heapdiff), циклов памяти, сравнения масштабов,
  ручной EXPLAIN вложенных запросов (explain_manual), API против X-DB-Time-Ms
  (api_split), сводка горячих точек; тесты ядра в perf/tests/test_analysis.py
- perf/e2e/scenarios/hotspots.spec.ts: CPU-профиль, рендеры React, мутации DOM
  после фильтра, рост CSS-правил по циклам (вне run-all)
- prod-сборка с source maps: PERF_SOURCEMAP=1, perf/stand.sh web-sourcemap (:8082)
- perf/report-data/20261026-s1, 20261026-s2 (summary, sql, analysis, explain-manual),
  t5-types (иллюстрация CPU 6x)
- design.md: решения T10b без обсуждения

Refs #202

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 12:43:46 +04:00

48 lines
2.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Таблица циклов сценария памяти (memory.jsonl) с длительностью цикла - для report-data (сырой jsonl в git не попадает).
cd perf && .venv/bin/python analysis/memory_cycles.py results/20261026-s1 --out report-data/20261026-s1/analysis
Вывод: <out>/memory-cycles.md - по циклу heap_used_mb, nodes, js_event_listeners, ws_open, documents, cycle_s, relogin;
наклон МНК cycle_s по циклам 1..N (секунд на цикл) и рост последнего цикла к первому.
"""
from __future__ import annotations
import argparse
import json
from pathlib import Path
def slope(xs, ys):
n = len(xs)
mx, my = sum(xs) / n, sum(ys) / n
den = sum((x - mx) ** 2 for x in xs)
return sum((x - mx) * (y - my) for x, y in zip(xs, ys)) / den if den else 0.0
def main(argv=None):
ap = argparse.ArgumentParser()
ap.add_argument("run_dir")
ap.add_argument("--out", required=True)
a = ap.parse_args(argv)
rows = [json.loads(x) for x in (Path(a.run_dir) / "memory.jsonl").read_text().splitlines()]
rows.sort(key=lambda r: r["metrics"]["cycle"])
md = [f"# Циклы сценария памяти ({Path(a.run_dir).name}, memory_cycles.py)", "",
"| цикл | heap_used_mb | nodes | js_event_listeners | ws_open | documents | cycle_s | relogin |", "|---|---|---|---|---|---|---|---|"]
for r in rows:
m = r["metrics"]
md.append(f"| {m['cycle']} | {m['heap_used_mb']:.2f} | {m['nodes']} | {m['js_event_listeners']} | {m['ws_open']} | {m.get('documents')} | "
f"{m.get('cycle_s', 0):.0f} | {m.get('relogin', '')} |")
c = [r for r in rows if r["metrics"]["cycle"] >= 1]
xs = [r["metrics"]["cycle"] for r in c]
ys = [r["metrics"].get("cycle_s", 0) for r in c]
md += ["", f"cycle_s: наклон МНК по циклам {xs[0]}-{xs[-1]} - {slope(xs, ys):.2f} с на цикл; первый {ys[0]:.0f} с, последний {ys[-1]:.0f} с "
f"(+{100 * (ys[-1] / ys[0] - 1):.0f} %)."]
out = Path(a.out)
out.mkdir(parents=True, exist_ok=True)
(out / "memory-cycles.md").write_text("\n".join(md) + "\n")
print("\n".join(md[-3:]))
if __name__ == "__main__":
main()