perf: правки по финальному ревью — скрипты, данные, фильтр long tasks

- run-all.sh: копия run-all.status.json в report-data с относительными путями;
  пример control4x с отдельным тегом и предупреждением (I-3, M-8); очищены
  три закоммиченные копии статуса
- lib/modal.ts: long tasks по пересечению окна (tasksInWindow), тест (M-7)
- scale_compare.py: строки листов на момент скролла (до grow), пояснения (M-6)
- hotspots_summary.py: оговорка о разбавлении «на шаг» (M-5)
- netlog_sizes.py + report-data/20261026-s1/analysis/netlog-sizes.md (M-3)

Refs #202

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev 2026-10-26 13:34:58 +04:00
parent 5c1822026d
commit 5f4afc0926
13 changed files with 236 additions and 55 deletions

View File

@ -17,6 +17,12 @@ import json
from pathlib import Path
STEP_NOTE = ("Шаги: hotspots.spec.ts всегда делает 40 шагов вперёд и 40 назад без проверки конца прокрутки. На коротких "
"страницах (свод 1 MAIN — 17 шагов до конца, AHR_RENT — 31 строка) часть шагов ничего не прокручивает, и "
"«на шаг» разбавлено: с main_thread_ms_per_step основного прогона (scroll.spec) не сравнивать; использовать доли, "
"рендеры на коммит и состав топа.")
def load(p: Path) -> list[dict]:
return [json.loads(x) for x in p.read_text().splitlines()] if p.exists() else []
@ -70,12 +76,12 @@ def main(argv=None):
(out / f"{a.name}.md").write_text("\n".join(md) + "\n")
print("\n".join(md))
return
md += ["## Рендеры React на шаг колеса 200 px (профилирующая сборка :8081)", "",
md += ["## Рендеры React на шаг колеса 200 px (профилирующая сборка :8081)", "", STEP_NOTE, "",
"| target | роль | шагов | коммитов/шаг | рендеров компонентов/шаг | из них Styled(td)/шаг | self React, мс | main thread/шаг, мс |", "|---|---|---|---|---|---|---|---|"]
md += [f"| {r['target']} | {r['role']} | {r['steps']} | {r['commits_per_step']} | {r['renders_per_step']} | {r['td_renders_per_step']} | {r['react_self_ms']} | {r['main_thread_ms_per_step']} |" for r in res["react"]]
for r in res["react"]:
md.append(f"- {r['target']}: " + "; ".join(f"{c} {n}/{s} мс" for c, n, s in r["top"][:6]))
md += ["", "## CPU-профили (prod-сборка с source maps :8082; разбор - cpuprofile-top.md)", "",
md += ["", "## CPU-профили (prod-сборка с source maps :8082; разбор - cpuprofile-top.md)", "", STEP_NOTE, "",
"| target | роль | шагов | main thread/шаг под профайлером, мс | профиль |", "|---|---|---|---|---|"]
md += [f"| {r['target']} | {r['role']} | {r['steps']} | {r['main_thread_ms_per_step']} | `{', '.join(r['artifacts'])}` |" for r in res["cpu"]]
md += ["", "## Фильтр свода: мутации DOM контейнера `.MuiTableContainer-root` за окно наблюдения после ввода «1»", "",

View File

@ -0,0 +1,55 @@
"""Размер ответов на проводе (сжатый, CDP) из сетевого лога сценариев - для report-data (network.jsonl в git не попадает).
cd perf && .venv/bin/python analysis/netlog_sizes.py results/20261026-s1 --out report-data/20261026-s1/analysis
По каждому шаблону пути данных (лист, отчёт проекта, своды) и шагу сценария: число ответов, медиана `body_size`
(сжатый размер по CDP `request.sizes()`, gzip уровня 1 бэка) и медиана `duration_ms` в браузере.
Распакованные размеры - в summary.md (bench, `bytes`) и `json_bytes_sheet` скролла. Вывод: <out>/netlog-sizes.md.
"""
from __future__ import annotations
import argparse
import json
import re
import statistics
from collections import defaultdict
from pathlib import Path
PATTERNS = [
(re.compile(r"/api/v1/form/(\d+)/sheet/(\w+)(\?.*)?$"), lambda m: f"GET /form/{m.group(1)}/sheet/{m.group(2)}{m.group(3) or ''}"),
(re.compile(r"/api/v1/projects/(\d+)/report/(\d+)/(\w+)$"), lambda m: f"GET /projects/{{id}}/report/{{year}}/{m.group(3)}"),
(re.compile(r"/api/v1/svod/(\d)/(\w+)/(\d+)"), lambda m: f"GET /svod/{m.group(1)}/{m.group(2)}/{{year}}"),
(re.compile(r"/api/v1/projects/plan-summary"), lambda m: "GET /projects/plan-summary"),
]
def main(argv=None):
ap = argparse.ArgumentParser()
ap.add_argument("run_dir")
ap.add_argument("--out", required=True)
a = ap.parse_args(argv)
groups = defaultdict(lambda: {"size": [], "dur": []})
for line in (Path(a.run_dir) / "network.jsonl").read_text().splitlines():
r = json.loads(line)
if r.get("method") != "GET" or r.get("status") != 200 or not r.get("body_size"):
continue
path = re.sub(r"^https?://[^/]+", "", r["url"])
for rx, name in PATTERNS:
m = rx.search(path)
if m:
g = groups[(name(m), r.get("scenario"), r.get("role"))]
g["size"].append(r["body_size"])
g["dur"].append(r.get("duration_ms") or 0)
break
md = [f"# Размер ответов на проводе (сжатый) по сетевому логу {Path(a.run_dir).name} (netlog_sizes.py)", "",
"| запрос | сценарий | роль | ответов | медиана body_size, КБ | медиана duration_ms в браузере |", "|---|---|---|---|---|---|"]
for (name, sc, role), g in sorted(groups.items(), key=lambda kv: -statistics.median(kv[1]["size"])):
md.append(f"| {name} | {sc} | {role} | {len(g['size'])} | {statistics.median(g['size']) / 1024:.0f} | {statistics.median(g['dur']):.0f} |")
out = Path(a.out)
out.mkdir(parents=True, exist_ok=True)
(out / "netlog-sizes.md").write_text("\n".join(md) + "\n")
print("\n".join(md[:14]))
if __name__ == "__main__":
main()

View File

@ -67,8 +67,17 @@ def main(argv=None):
g1, g2 = groups(a.s1), groups(a.s2)
m1 = json.loads((PERF / "report-data" / a.s1 / "manifest-s1.json").read_text())
m2 = json.loads((PERF / "report-data" / a.s2 / "manifest-s2.json").read_text())
rows1 = {f"{s['form_type']}/{s['sheet']}/{s['direction'] or 'null'}": s["rows"] for s in m1["sheets"] if s.get("owner", "rf") == "rf"}
rows2 = {f"{s['form_type']}/{s['sheet']}/{s['direction'] or 'null'}": s["rows"] for s in m2["sheets"] if s.get("owner", "rf") == "rf"}
def sheet_rows(man, run, scale):
# скролл снят до grow: для выращенных листов берём число строк «до» из grow-sS.json (манифест - после grow)
rows = {f"{s['form_type']}/{s['sheet']}/{s['direction'] or 'null'}": s["rows"] for s in man["sheets"] if s.get("owner", "rf") == "rf"}
gp = PERF / "report-data" / run / f"grow-s{scale}.json"
if gp.exists():
for g in json.loads(gp.read_text()):
rows[f"{g['sheet']}/null"] = g["before"]
return rows
rows1 = sheet_rows(m1, a.s1, 1)
rows2 = sheet_rows(m2, a.s2, 2)
res = {"scroll": [], "modal": [], "api": []}
for key, a1 in sorted(g1.items()):
sc, target, role, cpu = key
@ -112,6 +121,7 @@ def main(argv=None):
md = [f"# Масштаб 1 ({a.s1}) против масштаба 2 ({a.s2}, 1 повтор - оценка)", "",
"## Скролл: main thread на шаг колеса 200 px, мс (медиана; s2 - один замер)", "",
"Строк - на момент замера скролла (до grow; для AHR_UTILITY/AHR_SECURITY/FORM_4 CAP - значение «до» из grow-sS.json).", "",
"| target | роль | строк s1 → s2 | мс/шаг s1 | мс/шаг s2 | × | main thread s1, мс | s2, мс | ответ s1 → s2, МБ |", "|---|---|---|---|---|---|---|---|---|"]
for r in res["scroll"]:
inc = " (s2 incomplete)" if r["inc_s2"] else ""
@ -123,6 +133,7 @@ def main(argv=None):
for r in res["modal"]:
md.append(f"| {r['target']} | {r['role']} | {f(r['ms_s1'], 0)} | {f(r['ms_s2'], 0)} | {ratio(r['ms_s1'], r['ms_s2'])} | {f(r['mt_s1'], 0)} | {f(r['mt_s2'], 0)} |")
md += ["", "## API (bench, медиана 20 повторов по каждому URL; размер - распакованный ответ)", "",
"bench снят после grow: FORM_2/AHR - 2 092 строки на s1, AHR_UTILITY/SECURITY - 500, FORM_4/CAP - 300.", "",
"| запрос | роль | s1, мс | s2, мс | × | s1, МБ | s2, МБ |", "|---|---|---|---|---|---|---|"]
for r in res["api"]:
md.append(f"| {r['endpoint']} | {r['role']} | {r['ms_s1']} | {r['ms_s2']} | {ratio(r['ms_s1'], r['ms_s2'])} | {r['mb_s1']} | {r['mb_s2']} |")

View File

@ -6,7 +6,8 @@
* - появление: MutationObserver (+ проверка на каждом кадре) ловит видимый элемент по `appear`
* (по умолчанию `[role=dialog]`; у common/Modal и emotion-модалок приложения role нет, тогда css + text);
* - конец: кадр после кадра с появившейся модалкой (двойной rAF = «модалка отрисована»);
* - long tasks: PerformanceObserver 'longtask', засчитываются задачи, начавшиеся между pointerdown и концом;
* - long tasks: PerformanceObserver 'longtask', засчитываются задачи, пересекающие окно [pointerdown, конец] (tasksInWindow:
* задача клика начинается раньше, чем её обработчик pointerdown ставит t0);
* - main_thread_ms: прирост CDP Performance.TaskDuration от клика до конца окна (все задачи main thread:
* скрипт + стили + layout + paint-подготовка).
* Нет модалки за timeoutMs (5 с) - ошибка с id модалки.
@ -25,6 +26,11 @@ export interface OpenMetrics {
export const OPEN_TIMEOUT_MS = 5000;
/** Long tasks, пересекающие окно [t0, tEnd]: start <= tEnd и start + dur >= t0. */
export function tasksInWindow<T extends { start: number; dur: number }>(tasks: T[], t0: number, tEnd: number): T[] {
return tasks.filter((t) => t.start <= tEnd && t.start + t.dur >= t0);
}
export async function measureOpen(page: Page, opener: () => Promise<unknown>, opts: OpenOpts): Promise<OpenMetrics> {
const timeout = opts.timeoutMs ?? OPEN_TIMEOUT_MS;
const appear: Required<Appear> = { css: opts.appear?.css ?? '[role=dialog]', text: opts.appear?.text ?? '' };
@ -87,7 +93,7 @@ export async function measureOpen(page: Page, opener: () => Promise<unknown>, op
if (res.timedOut || res.tEnd < 0) {
throw new Error(`modal '${opts.id}' did not appear within ${timeout} ms (selector ${appear.css}${appear.text ? ` + text '${appear.text}'` : ''}, pointerdown ${res.t0 >= 0 ? 'seen' : 'not seen'})`);
}
const inWin = res.tasks.filter((t) => t.start >= res.t0 - 1 && t.start <= res.tEnd);
const inWin = tasksInWindow(res.tasks, res.t0, res.tEnd);
return {
click_to_visible_ms: res.tEnd - res.t0,
long_task_n: inWin.length,

View File

@ -1,6 +1,6 @@
import { test, expect } from '@playwright/test';
import path from 'node:path';
import { measureOpen } from '../lib/modal';
import { measureOpen, tasksInWindow } from '../lib/modal';
import { REACT_HOOK_SCRIPT, profileStart, profileStop } from '../lib/reactProfile';
const fx = (n: string) => 'file://' + path.resolve(__dirname, '../fixtures', n);
@ -74,3 +74,15 @@ test('reactProfile: хук получает коммиты, топ-20 по displ
expect(p.top[0].component).toBe('Row'); // сортировка по self_ms
expect(p.top.length).toBeLessThanOrEqual(20);
});
test('tasksInWindow: задача, начавшаяся до pointerdown и пересекающая окно, засчитывается (задача клика)', () => {
const t0 = 100, tEnd = 300;
const tasks = [
{ start: 40, dur: 50 }, // закончилась до клика - нет
{ start: 95, dur: 120 }, // задача клика: началась раньше t0 (обработчик pointerdown внутри неё) - да
{ start: 150, dur: 60 }, // внутри окна - да
{ start: 299, dur: 80 }, // началась до конца окна - да
{ start: 310, dur: 60 }, // после окна - нет
];
expect(tasksInWindow(tasks, t0, tEnd).map((t) => t.start)).toEqual([95, 150, 299]);
});

View File

@ -8,7 +8,7 @@
"start": "2026-10-26T12:26:46+0400",
"end": "2026-10-26T12:59:48+0400",
"duration_s": 1982,
"cmd": "rc=0; ( cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=1 PERF_RUN_ID=20261026-control-s1 PERF_WEB=http://localhost:8080 PERF_SQLSTATS_TAG=control4x_scroll PERF_CPU_RATES=4 PERF_REPEATS=1 PERF_TRACE=0 PERF_ROLES=rf,dfip PERF_TARGETS='FORM_2/AHR/null@y,svod/svod1_MAIN,svod/svod2_GO' npx playwright test scenarios/scroll.spec.ts ) || rc=$?; ( cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=1 PERF_RUN_ID=20261026-control-s1 PERF_WEB=http://localhost:8080 PERF_SQLSTATS_TAG=control4x_modals PERF_CPU_RATES=4 PERF_REPEATS=1 PERF_TRACE=0 PERF_PRIORITY=1,2 PERF_MODALS='sheet_select_vsp@big' npx playwright test scenarios/modals.spec.ts ) || rc=$?; exit $rc"
"cmd": "rc=0; ( cd 'perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=1 PERF_RUN_ID=20261026-control-s1 PERF_WEB=http://localhost:8080 PERF_SQLSTATS_TAG=control4x_scroll PERF_CPU_RATES=4 PERF_REPEATS=1 PERF_TRACE=0 PERF_ROLES=rf,dfip PERF_TARGETS='FORM_2/AHR/null@y,svod/svod1_MAIN,svod/svod2_GO' npx playwright test scenarios/scroll.spec.ts ) || rc=$?; ( cd 'perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=1 PERF_RUN_ID=20261026-control-s1 PERF_WEB=http://localhost:8080 PERF_SQLSTATS_TAG=control4x_modals PERF_CPU_RATES=4 PERF_REPEATS=1 PERF_TRACE=0 PERF_PRIORITY=1,2 PERF_MODALS='sheet_select_vsp@big' npx playwright test scenarios/modals.spec.ts ) || rc=$?; exit $rc"
},
"aggregate": {
"status": "OK",
@ -16,7 +16,7 @@
"start": "2026-10-26T12:59:48+0400",
"end": "2026-10-26T12:59:48+0400",
"duration_s": 0,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf' && rm -f '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-control-s1/summary.json' && '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.venv/bin/python' -m perfkit.aggregate 'results/20261026-control-s1' && { [ ! -f 'results/20261026-control-s1/modal.jsonl' ] || '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.venv/bin/python' -m perfkit.modals_inventory 'results/20261026-control-s1'; } && mkdir -p '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-control-s1' && for d in results/20261026-control-s1/sql/*/; do if [ -d \"$d\" ]; then t=$(basename \"$d\"); mkdir -p '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-control-s1/sql/'$t || exit 1; if [ -f \"$d\"sql_top.json ]; then cp \"$d\"sql_top.json '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-control-s1/sql/'$t/ || exit 1; fi; if [ -d \"$d\"explain ]; then cp -R \"$d\"explain '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-control-s1/sql/'$t/ || exit 1; fi; fi; done && for f in results/20261026-control-s1/memtrend.txt results/manifest-s1.json results/gen-stats-s1.json results/grow-s1.json results/20261026-control-s1/run-all.status.json; do if [ -f \"$f\" ]; then cp \"$f\" '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-control-s1/' || exit 1; fi; done && ls -R '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-control-s1' && test -f '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-control-s1/summary.json'"
"cmd": "cd 'perf' && rm -f 'perf/report-data/20261026-control-s1/summary.json' && 'perf/.venv/bin/python' -m perfkit.aggregate 'results/20261026-control-s1' && { [ ! -f 'results/20261026-control-s1/modal.jsonl' ] || 'perf/.venv/bin/python' -m perfkit.modals_inventory 'results/20261026-control-s1'; } && mkdir -p 'perf/report-data/20261026-control-s1' && for d in results/20261026-control-s1/sql/*/; do if [ -d \"$d\" ]; then t=$(basename \"$d\"); mkdir -p 'perf/report-data/20261026-control-s1/sql/'$t || exit 1; if [ -f \"$d\"sql_top.json ]; then cp \"$d\"sql_top.json 'perf/report-data/20261026-control-s1/sql/'$t/ || exit 1; fi; if [ -d \"$d\"explain ]; then cp -R \"$d\"explain 'perf/report-data/20261026-control-s1/sql/'$t/ || exit 1; fi; fi; done && for f in results/20261026-control-s1/memtrend.txt results/manifest-s1.json results/gen-stats-s1.json results/grow-s1.json results/20261026-control-s1/run-all.status.json; do if [ -f \"$f\" ]; then cp \"$f\" 'perf/report-data/20261026-control-s1/' || exit 1; fi; done && ls -R 'perf/report-data/20261026-control-s1' && test -f 'perf/report-data/20261026-control-s1/summary.json'"
}
}
}

View File

@ -2,6 +2,8 @@
## Рендеры React на шаг колеса 200 px (профилирующая сборка :8081)
Шаги: hotspots.spec.ts всегда делает 40 шагов вперёд и 40 назад без проверки конца прокрутки. На коротких страницах (свод 1 MAIN — 17 шагов до конца, AHR_RENT — 31 строка) часть шагов ничего не прокручивает, и «на шаг» разбавлено: с main_thread_ms_per_step основного прогона (scroll.spec) не сравнивать; использовать доли, рендеры на коммит и состав топа.
| target | роль | шагов | коммитов/шаг | рендеров компонентов/шаг | из них Styled(td)/шаг | self React, мс | main thread/шаг, мс |
|---|---|---|---|---|---|---|---|
| FORM_2/AHR/null:y | rf | 80 | 3.31 | 14808 | 1696 | 3708 | 76.5 |
@ -21,6 +23,8 @@
## CPU-профили (prod-сборка с source maps :8082; разбор - cpuprofile-top.md)
Шаги: hotspots.spec.ts всегда делает 40 шагов вперёд и 40 назад без проверки конца прокрутки. На коротких страницах (свод 1 MAIN — 17 шагов до конца, AHR_RENT — 31 строка) часть шагов ничего не прокручивает, и «на шаг» разбавлено: с main_thread_ms_per_step основного прогона (scroll.spec) не сравнивать; использовать доли, рендеры на коммит и состав топа.
| target | роль | шагов | main thread/шаг под профайлером, мс | профиль |
|---|---|---|---|---|
| FORM_2/AHR_RENT/null:y | rf | 80 | 7.7 | `artifacts/hot-FORM_2_AHR_RENT_null-y.cpuprofile` |

View File

@ -0,0 +1,79 @@
# Размер ответов на проводе (сжатый) по сетевому логу 20261026-s1 (netlog_sizes.py)
| запрос | сценарий | роль | ответов | медиана body_size, КБ | медиана duration_ms в браузере |
|---|---|---|---|---|---|
| GET /svod/2/RF/{year} | scroll | admin | 4 | 3419 | 1910 |
| GET /svod/2/RF/{year} | scroll | dfip | 4 | 3419 | 1828 |
| GET /svod/2/GO/{year} | scroll | admin | 4 | 2347 | 1142 |
| GET /svod/2/GO/{year} | scroll | dfip | 4 | 2347 | 1138 |
| GET /form/7/sheet/AHR | memory | rf | 20 | 378 | 957 |
| GET /form/7/sheet/AHR | modal | rf | 5 | 378 | 810 |
| GET /form/7/sheet/AHR | modal_renders | rf | 1 | 378 | 797 |
| GET /form/1/sheet/AHR?direction=Support | scroll | admin | 1 | 329 | 4445 |
| GET /form/7/sheet/AHR | scroll_coauthor | rf | 6 | 323 | 431 |
| GET /form/7/sheet/AHR | scroll | rf | 6 | 321 | 705 |
| GET /form/7/sheet/AHR | scroll | admin | 1 | 321 | 720 |
| GET /form/1/sheet/AHR?direction=Development | scroll | admin | 1 | 319 | 366 |
| GET /form/4/sheet/AHR | scroll | admin | 1 | 316 | 361 |
| GET /form/1/sheet/CAP?direction=Development | scroll | admin | 1 | 265 | 187 |
| GET /form/1/sheet/CAP?direction=Support | scroll | admin | 1 | 259 | 214 |
| GET /form/4/sheet/CAP | scroll | admin | 1 | 247 | 223 |
| GET /form/7/sheet/CAP | scroll | rf | 6 | 243 | 225 |
| GET /form/7/sheet/CAP | scroll | admin | 1 | 242 | 220 |
| GET /form/1/sheet/OPER | scroll | admin | 1 | 193 | 412 |
| GET /form/7/sheet/OPER | scroll | rf | 6 | 189 | 184 |
| GET /form/7/sheet/OPER | scroll | admin | 1 | 189 | 161 |
| GET /form/4/sheet/OPER | scroll | admin | 1 | 187 | 186 |
| GET /form/13/sheet/STRUCTURE | scroll | rf | 6 | 182 | 234 |
| GET /form/13/sheet/STRUCTURE | scroll_coauthor | rf | 6 | 182 | 211 |
| GET /form/13/sheet/STRUCTURE | memory | rf | 20 | 182 | 274 |
| GET /form/13/sheet/STRUCTURE | scroll | admin | 1 | 182 | 269 |
| GET /projects/{id}/report/{year}/LIMIT | scroll | rf | 36 | 161 | 387 |
| GET /projects/{id}/report/{year}/CURRENT_EXPENSES | scroll | rf | 36 | 159 | 392 |
| GET /projects/plan-summary | scroll | admin | 4 | 108 | 388 |
| GET /projects/plan-summary | scroll | dfip | 4 | 108 | 381 |
| GET /form/13/sheet/CAP | modal | rf | 15 | 73 | 1775 |
| GET /form/13/sheet/CAP | modal_renders | rf | 3 | 73 | 1680 |
| GET /form/13/sheet/AHR | scroll | rf | 6 | 48 | 709 |
| GET /form/13/sheet/AHR | modal | rf | 15 | 48 | 679 |
| GET /form/13/sheet/AHR | modal_renders | rf | 3 | 48 | 648 |
| GET /form/13/sheet/AHR | scroll | admin | 1 | 48 | 713 |
| GET /form/13/sheet/OPER | scroll | rf | 6 | 47 | 692 |
| GET /form/13/sheet/OPER | scroll | admin | 1 | 47 | 737 |
| GET /form/13/sheet/CAP | scroll | admin | 1 | 45 | 652 |
| GET /form/13/sheet/CAP | scroll | rf | 6 | 45 | 701 |
| GET /svod/1/MAIN/{year} | scroll | admin | 20 | 44 | 332 |
| GET /svod/1/MAIN/{year} | scroll | dfip | 20 | 44 | 336 |
| GET /svod/1/FORM_1/{year} | scroll | admin | 4 | 37 | 113 |
| GET /svod/1/FORM_1/{year} | scroll | dfip | 4 | 37 | 103 |
| GET /form/1/sheet/SMETA | scroll | admin | 1 | 34 | 498 |
| GET /svod/1/FORM_2/{year} | scroll | admin | 4 | 22 | 118 |
| GET /svod/1/FORM_2/{year} | scroll | dfip | 4 | 22 | 119 |
| GET /form/7/sheet/SMETA | scroll | rf | 6 | 21 | 106 |
| GET /form/7/sheet/SMETA | scroll | admin | 1 | 21 | 106 |
| GET /form/4/sheet/SMETA | scroll | admin | 1 | 21 | 130 |
| GET /svod/1/FORM_4/{year} | scroll | admin | 4 | 19 | 46 |
| GET /svod/1/FORM_4/{year} | scroll | dfip | 4 | 19 | 48 |
| GET /form/7/sheet/AHR_UTILITY | modal | rf | 5 | 17 | 33 |
| GET /form/7/sheet/AHR_UTILITY | modal_renders | rf | 1 | 17 | 35 |
| GET /svod/1/FORM_3/{year} | scroll | admin | 4 | 13 | 78 |
| GET /svod/1/FORM_3/{year} | scroll | dfip | 4 | 13 | 83 |
| GET /form/13/sheet/SMETA | scroll | rf | 6 | 12 | 66 |
| GET /form/13/sheet/SMETA | scroll | admin | 1 | 12 | 74 |
| GET /form/7/sheet/AHR_SECURITY | scroll | rf | 6 | 2 | 15 |
| GET /form/7/sheet/AHR_LIMIT | scroll | rf | 6 | 2 | 17 |
| GET /form/7/sheet/AHR_SECURITY | scroll | admin | 1 | 2 | 16 |
| GET /form/4/sheet/AHR_LIMIT | scroll | admin | 1 | 2 | 23 |
| GET /form/7/sheet/AHR_LIMIT | scroll | admin | 1 | 2 | 12 |
| GET /form/7/sheet/AHR_RENT | scroll | rf | 6 | 2 | 15 |
| GET /form/7/sheet/AHR_RENT | modal | rf | 10 | 2 | 15 |
| GET /form/7/sheet/AHR_RENT | modal_renders | rf | 2 | 2 | 15 |
| GET /form/7/sheet/AHR_UTILITY | scroll | rf | 6 | 2 | 15 |
| GET /form/7/sheet/AHR_RENT | scroll | admin | 1 | 2 | 14 |
| GET /form/7/sheet/AHR_UTILITY | scroll | admin | 1 | 2 | 13 |
| GET /form/4/sheet/AHR_SECURITY | scroll | admin | 1 | 0 | 15 |
| GET /form/7/sheet/OTCH9F | scroll | rf | 6 | 0 | 16 |
| GET /form/4/sheet/AHR_UTILITY | scroll | admin | 1 | 0 | 11 |
| GET /form/4/sheet/AHR_RENT | scroll | admin | 1 | 0 | 14 |
| GET /form/4/sheet/OTCH9F | scroll | admin | 1 | 0 | 14 |
| GET /form/7/sheet/OTCH9F | scroll | admin | 1 | 0 | 18 |

View File

@ -8,7 +8,7 @@
"start": "2026-10-26T03:15:25+0400",
"end": "2026-10-26T03:15:31+0400",
"duration_s": 6,
"cmd": "'/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/stand.sh' reset"
"cmd": "'perf/stand.sh' reset"
},
"gen": {
"status": "OK",
@ -16,7 +16,7 @@
"start": "2026-10-26T03:15:31+0400",
"end": "2026-10-26T03:26:14+0400",
"duration_s": 643,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf' && '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.venv/bin/python' -m perfkit.gen.run --scale 1"
"cmd": "cd 'perf' && 'perf/.venv/bin/python' -m perfkit.gen.run --scale 1"
},
"verify": {
"status": "OK",
@ -24,7 +24,7 @@
"start": "2026-10-26T03:26:14+0400",
"end": "2026-10-26T03:26:23+0400",
"duration_s": 8,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf' && '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.venv/bin/python' -m perfkit.gen.verify --scale 1"
"cmd": "cd 'perf' && 'perf/.venv/bin/python' -m perfkit.gen.verify --scale 1"
},
"stand": {
"status": "OK",
@ -32,7 +32,7 @@
"start": "2026-10-26T03:26:23+0400",
"end": "2026-10-26T03:26:24+0400",
"duration_s": 1,
"cmd": "(curl -fsS -o /dev/null 'http://localhost:8000/healthz' || '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/stand.sh' api) && ([ -f '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.build/prod/index.html' ] || '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/stand.sh' web-build) && (curl -fsS -o /dev/null 'http://localhost:8080/' || '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/stand.sh' web) && curl -fsS 'http://localhost:8080/' | cmp -s - '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.build/prod/index.html' && echo 'web :8080 = prod-сборка' && '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/stand.sh' smoke"
"cmd": "(curl -fsS -o /dev/null 'http://localhost:8000/healthz' || 'perf/stand.sh' api) && ([ -f 'perf/.build/prod/index.html' ] || 'perf/stand.sh' web-build) && (curl -fsS -o /dev/null 'http://localhost:8080/' || 'perf/stand.sh' web) && curl -fsS 'http://localhost:8080/' | cmp -s - 'perf/.build/prod/index.html' && echo 'web :8080 = prod-сборка' && 'perf/stand.sh' smoke"
},
"preflight": {
"status": "OK",
@ -40,7 +40,7 @@
"start": "2026-10-26T03:26:24+0400",
"end": "2026-10-26T03:26:26+0400",
"duration_s": 2,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/e2e' && for f in scenarios/scroll.spec.ts scenarios/modals.spec.ts scenarios/scroll-coauthor.spec.ts scenarios/memory.spec.ts; do env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=1 PERF_PRIORITY=1,2 npx playwright test --list $f | tail -1 || exit 1; done"
"cmd": "cd 'perf/e2e' && for f in scenarios/scroll.spec.ts scenarios/modals.spec.ts scenarios/scroll-coauthor.spec.ts scenarios/memory.spec.ts; do env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=1 PERF_PRIORITY=1,2 npx playwright test --list $f | tail -1 || exit 1; done"
},
"scroll": {
"status": "OK",
@ -48,7 +48,7 @@
"start": "2026-10-26T03:26:26+0400",
"end": "2026-10-26T06:29:23+0400",
"duration_s": 10977,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=1 PERF_RUN_ID=20261026-s1 PERF_WEB=http://localhost:8080 PERF_SQLSTATS_TAG=scroll npx playwright test scenarios/scroll.spec.ts"
"cmd": "cd 'perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=1 PERF_RUN_ID=20261026-s1 PERF_WEB=http://localhost:8080 PERF_SQLSTATS_TAG=scroll npx playwright test scenarios/scroll.spec.ts"
},
"coauthor": {
"status": "FAIL",
@ -56,7 +56,7 @@
"start": "2026-10-26T06:29:23+0400",
"end": "2026-10-26T06:34:34+0400",
"duration_s": 311,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=1 PERF_RUN_ID=20261026-s1 PERF_WEB=http://localhost:8080 PERF_SQLSTATS_TAG=coauthor PERF_COAUTHOR_RATES=1,5 npx playwright test scenarios/scroll-coauthor.spec.ts"
"cmd": "cd 'perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=1 PERF_RUN_ID=20261026-s1 PERF_WEB=http://localhost:8080 PERF_SQLSTATS_TAG=coauthor PERF_COAUTHOR_RATES=1,5 npx playwright test scenarios/scroll-coauthor.spec.ts"
},
"grow": {
"status": "OK",
@ -64,7 +64,7 @@
"start": "2026-10-26T06:34:34+0400",
"end": "2026-10-26T06:38:12+0400",
"duration_s": 218,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf' && '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.venv/bin/python' -m perfkit.gen.grow --scale 1"
"cmd": "cd 'perf' && 'perf/.venv/bin/python' -m perfkit.gen.grow --scale 1"
},
"modals": {
"status": "OK",
@ -72,7 +72,7 @@
"start": "2026-10-26T06:38:12+0400",
"end": "2026-10-26T06:47:01+0400",
"duration_s": 529,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=1 PERF_RUN_ID=20261026-s1 PERF_WEB=http://localhost:8080 PERF_SQLSTATS_TAG=modals PERF_PRIORITY=1,2 npx playwright test scenarios/modals.spec.ts"
"cmd": "cd 'perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=1 PERF_RUN_ID=20261026-s1 PERF_WEB=http://localhost:8080 PERF_SQLSTATS_TAG=modals PERF_PRIORITY=1,2 npx playwright test scenarios/modals.spec.ts"
},
"modals_profiling": {
"status": "OK",
@ -80,7 +80,7 @@
"start": "2026-10-26T06:47:01+0400",
"end": "2026-10-26T06:48:38+0400",
"duration_s": 97,
"cmd": "rc=0; '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/stand.sh' web-profiling && ( cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=1 PERF_RUN_ID=20261026-s1 PERF_WEB=http://localhost:8081 PERF_SQLSTATS_TAG=modals_profiling PERF_PROFILING=1 PERF_PRIORITY=1 npx playwright test scenarios/modals.spec.ts ) || rc=$?; if [ -f '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.run/web-profiling.pid' ]; then pkill -P $(cat '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.run/web-profiling.pid') 2>/dev/null; kill $(cat '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.run/web-profiling.pid') 2>/dev/null; rm -f '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.run/web-profiling.pid'; fi; exit $rc"
"cmd": "rc=0; 'perf/stand.sh' web-profiling && ( cd 'perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=1 PERF_RUN_ID=20261026-s1 PERF_WEB=http://localhost:8081 PERF_SQLSTATS_TAG=modals_profiling PERF_PROFILING=1 PERF_PRIORITY=1 npx playwright test scenarios/modals.spec.ts ) || rc=$?; if [ -f 'perf/.run/web-profiling.pid' ]; then pkill -P $(cat 'perf/.run/web-profiling.pid') 2>/dev/null; kill $(cat 'perf/.run/web-profiling.pid') 2>/dev/null; rm -f 'perf/.run/web-profiling.pid'; fi; exit $rc"
},
"memory": {
"status": "OK",
@ -88,7 +88,7 @@
"start": "2026-10-26T06:48:38+0400",
"end": "2026-10-26T07:44:37+0400",
"duration_s": 3359,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=1 PERF_RUN_ID=20261026-s1 PERF_WEB=http://localhost:8080 PERF_SQLSTATS_TAG=memory npx playwright test scenarios/memory.spec.ts"
"cmd": "cd 'perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=1 PERF_RUN_ID=20261026-s1 PERF_WEB=http://localhost:8080 PERF_SQLSTATS_TAG=memory npx playwright test scenarios/memory.spec.ts"
},
"memtrend": {
"status": "OK",
@ -96,7 +96,7 @@
"start": "2026-10-26T07:44:37+0400",
"end": "2026-10-26T07:44:37+0400",
"duration_s": 0,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf' && '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.venv/bin/python' -m perfkit.memtrend 'results/20261026-s1' | tee 'results/20261026-s1/memtrend.txt'"
"cmd": "cd 'perf' && 'perf/.venv/bin/python' -m perfkit.memtrend 'results/20261026-s1' | tee 'results/20261026-s1/memtrend.txt'"
},
"bench": {
"status": "OK",
@ -104,7 +104,7 @@
"start": "2026-10-26T07:44:37+0400",
"end": "2026-10-26T07:54:02+0400",
"duration_s": 564,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf' && '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.venv/bin/python' -m perfkit.bench 'results/20261026-s1' --repeats 20 --scale 1"
"cmd": "cd 'perf' && 'perf/.venv/bin/python' -m perfkit.bench 'results/20261026-s1' --repeats 20 --scale 1"
},
"aggregate": {
"status": "OK",
@ -112,7 +112,7 @@
"start": "2026-10-26T07:54:02+0400",
"end": "2026-10-26T07:54:02+0400",
"duration_s": 0,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf' && rm -f '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-s1/summary.json' && '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.venv/bin/python' -m perfkit.aggregate 'results/20261026-s1' && { [ ! -f 'results/20261026-s1/modal.jsonl' ] || '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.venv/bin/python' -m perfkit.modals_inventory 'results/20261026-s1'; } && mkdir -p '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-s1' && for d in results/20261026-s1/sql/*/; do if [ -d \"$d\" ]; then t=$(basename \"$d\"); mkdir -p '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-s1/sql/'$t || exit 1; if [ -f \"$d\"sql_top.json ]; then cp \"$d\"sql_top.json '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-s1/sql/'$t/ || exit 1; fi; if [ -d \"$d\"explain ]; then cp -R \"$d\"explain '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-s1/sql/'$t/ || exit 1; fi; fi; done && for f in results/20261026-s1/memtrend.txt results/manifest-s1.json results/gen-stats-s1.json results/grow-s1.json results/20261026-s1/run-all.status.json; do if [ -f \"$f\" ]; then cp \"$f\" '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-s1/' || exit 1; fi; done && ls -R '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-s1' && test -f '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-s1/summary.json'"
"cmd": "cd 'perf' && rm -f 'perf/report-data/20261026-s1/summary.json' && 'perf/.venv/bin/python' -m perfkit.aggregate 'results/20261026-s1' && { [ ! -f 'results/20261026-s1/modal.jsonl' ] || 'perf/.venv/bin/python' -m perfkit.modals_inventory 'results/20261026-s1'; } && mkdir -p 'perf/report-data/20261026-s1' && for d in results/20261026-s1/sql/*/; do if [ -d \"$d\" ]; then t=$(basename \"$d\"); mkdir -p 'perf/report-data/20261026-s1/sql/'$t || exit 1; if [ -f \"$d\"sql_top.json ]; then cp \"$d\"sql_top.json 'perf/report-data/20261026-s1/sql/'$t/ || exit 1; fi; if [ -d \"$d\"explain ]; then cp -R \"$d\"explain 'perf/report-data/20261026-s1/sql/'$t/ || exit 1; fi; fi; done && for f in results/20261026-s1/memtrend.txt results/manifest-s1.json results/gen-stats-s1.json results/grow-s1.json results/20261026-s1/run-all.status.json; do if [ -f \"$f\" ]; then cp \"$f\" 'perf/report-data/20261026-s1/' || exit 1; fi; done && ls -R 'perf/report-data/20261026-s1' && test -f 'perf/report-data/20261026-s1/summary.json'"
}
}
}

View File

@ -93,8 +93,8 @@
{
"target": "FORM_2/AHR_SECURITY/null@x",
"role": "rf",
"rows_s1": 500,
"rows_s2": 500,
"rows_s1": 31,
"rows_s2": 61,
"mt_per_step_s1": 85.5549375,
"mt_per_step_s2": 83.62412499999999,
"mt_s1": 2737.758,
@ -108,8 +108,8 @@
{
"target": "FORM_2/AHR_SECURITY/null@y",
"role": "rf",
"rows_s1": 500,
"rows_s2": 500,
"rows_s1": 31,
"rows_s2": 61,
"mt_per_step_s1": 76.4081875,
"mt_per_step_s2": 77.01785,
"mt_s1": 611.2655,
@ -123,8 +123,8 @@
{
"target": "FORM_2/AHR_UTILITY/null@x",
"role": "rf",
"rows_s1": 500,
"rows_s2": 500,
"rows_s1": 31,
"rows_s2": 61,
"mt_per_step_s1": 86.60009375,
"mt_per_step_s2": 82.18025,
"mt_s1": 2771.203,
@ -138,8 +138,8 @@
{
"target": "FORM_2/AHR_UTILITY/null@y",
"role": "rf",
"rows_s1": 500,
"rows_s2": 500,
"rows_s1": 31,
"rows_s2": 61,
"mt_per_step_s1": 77.100875,
"mt_per_step_s2": 79.7505,
"mt_s1": 616.807,
@ -303,8 +303,8 @@
{
"target": "FORM_4/CAP/null@x",
"role": "rf",
"rows_s1": 300,
"rows_s2": 300,
"rows_s1": 110,
"rows_s2": 210,
"mt_per_step_s1": 88.53567530487805,
"mt_per_step_s2": 87.65557926829268,
"mt_s1": 29039.7015,
@ -318,8 +318,8 @@
{
"target": "FORM_4/CAP/null@y",
"role": "rf",
"rows_s1": 300,
"rows_s2": 300,
"rows_s1": 110,
"rows_s2": 210,
"mt_per_step_s1": 93.31751315789475,
"mt_per_step_s2": 89.75829487179487,
"mt_s1": 3546.0655000000006,

View File

@ -2,6 +2,8 @@
## Скролл: main thread на шаг колеса 200 px, мс (медиана; s2 - один замер)
Строк - на момент замера скролла (до grow; для AHR_UTILITY/AHR_SECURITY/FORM_4 CAP - значение «до» из grow-sS.json).
| target | роль | строк s1 → s2 | мс/шаг s1 | мс/шаг s2 | × | main thread s1, мс | s2, мс | ответ s1 → s2, МБ |
|---|---|---|---|---|---|---|---|---|
| FORM_2/AHR/null@x | rf | 1154 → 1744 | 78.7 | 78.3 | 1.00 | 26899 | 26786 | 4.29 → 6.50 |
@ -10,10 +12,10 @@
| FORM_2/AHR_LIMIT/null@y | rf | 27 → 27 | 71.1 | 71.7 | 1.01 | 284 | 287 | 0.01 → 0.01 |
| FORM_2/AHR_RENT/null@x | rf | 31 → 61 | 91.2 | 83.5 | 0.92 | 3102 | 2840 | 0.02 → 0.03 |
| FORM_2/AHR_RENT/null@y | rf | 31 → 61 | 77.4 | 78.9 | 1.02 | 619 | 1578 | 0.02 → 0.03 |
| FORM_2/AHR_SECURITY/null@x | rf | 500 → 500 | 85.6 | 83.6 | 0.98 | 2738 | 2676 | 0.02 → 0.03 |
| FORM_2/AHR_SECURITY/null@y | rf | 500 → 500 | 76.4 | 77.0 | 1.01 | 611 | 1540 | 0.02 → 0.03 |
| FORM_2/AHR_UTILITY/null@x | rf | 500 → 500 | 86.6 | 82.2 | 0.95 | 2771 | 2630 | 0.02 → 0.03 |
| FORM_2/AHR_UTILITY/null@y | rf | 500 → 500 | 77.1 | 79.8 | 1.03 | 617 | 1595 | 0.02 → 0.03 |
| FORM_2/AHR_SECURITY/null@x | rf | 31 → 61 | 85.6 | 83.6 | 0.98 | 2738 | 2676 | 0.02 → 0.03 |
| FORM_2/AHR_SECURITY/null@y | rf | 31 → 61 | 76.4 | 77.0 | 1.01 | 611 | 1540 | 0.02 → 0.03 |
| FORM_2/AHR_UTILITY/null@x | rf | 31 → 61 | 86.6 | 82.2 | 0.95 | 2771 | 2630 | 0.02 → 0.03 |
| FORM_2/AHR_UTILITY/null@y | rf | 31 → 61 | 77.1 | 79.8 | 1.03 | 617 | 1595 | 0.02 → 0.03 |
| FORM_2/CAP/null@x | rf | 708 → 1208 | 78.8 | 80.4 | 1.02 | 27000 | 27483 | 2.65 → 4.51 |
| FORM_2/CAP/null@y | rf | 708 → 1208 | 85.4 | 87.2 | 1.02 | 23740 | 41698 | 2.65 → 4.51 |
| FORM_2/OPER/null@x | rf | 547 → 1047 | 80.1 | 80.7 | 1.01 | 27395 | 27600 | 2.03 → 3.88 |
@ -24,8 +26,8 @@
| FORM_2/SMETA/null@y | rf | 134 → 134 | 84.9 | 85.0 | 1.00 | 4075 | 4080 | 0.10 → 0.10 |
| FORM_4/AHR/null@x | rf | 110 → 210 | 90.6 | 87.3 | 0.96 | 29727 | 28632 | 0.44 → 0.84 |
| FORM_4/AHR/null@y | rf | 110 → 210 | 90.2 | 89.5 | 0.99 | 3426 | 6984 | 0.44 → 0.84 |
| FORM_4/CAP/null@x | rf | 300 → 300 | 88.5 | 87.7 | 0.99 | 29040 | 28751 | 0.44 → 0.83 |
| FORM_4/CAP/null@y | rf | 300 → 300 | 93.3 | 89.8 | 0.96 | 3546 | 7001 | 0.44 → 0.83 |
| FORM_4/CAP/null@x | rf | 110 → 210 | 88.5 | 87.7 | 0.99 | 29040 | 28751 | 0.44 → 0.83 |
| FORM_4/CAP/null@y | rf | 110 → 210 | 93.3 | 89.8 | 0.96 | 3546 | 7001 | 0.44 → 0.83 |
| FORM_4/OPER/null@x | rf | 110 → 210 | 89.0 | 88.3 | 0.99 | 29383 | 29129 | 0.44 → 0.84 |
| FORM_4/OPER/null@y | rf | 110 → 210 | 92.1 | 90.2 | 0.98 | 3498 | 7036 | 0.44 → 0.84 |
| FORM_4/SMETA/null@x | rf | 109 → 109 | 61.8 | 62.8 | 1.02 | 1235 | 1255 | 0.08 → 0.08 |
@ -121,6 +123,8 @@
## API (bench, медиана 20 повторов по каждому URL; размер - распакованный ответ)
bench снят после grow: FORM_2/AHR - 2 092 строки на s1, AHR_UTILITY/SECURITY - 500, FORM_4/CAP - 300.
| запрос | роль | s1, мс | s2, мс | × | s1, МБ | s2, МБ |
|---|---|---|---|---|---|---|
| GET свод 2 RF | dfip | 1805.5 | 7319.2 | 4.05 | 52.69 | 195.08 |

View File

@ -8,7 +8,7 @@
"start": "2026-10-26T07:54:02+0400",
"end": "2026-10-26T07:54:08+0400",
"duration_s": 6,
"cmd": "'/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/stand.sh' reset"
"cmd": "'perf/stand.sh' reset"
},
"gen": {
"status": "OK",
@ -16,7 +16,7 @@
"start": "2026-10-26T07:54:08+0400",
"end": "2026-10-26T08:49:46+0400",
"duration_s": 3338,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf' && '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.venv/bin/python' -m perfkit.gen.run --scale 2"
"cmd": "cd 'perf' && 'perf/.venv/bin/python' -m perfkit.gen.run --scale 2"
},
"verify": {
"status": "OK",
@ -24,7 +24,7 @@
"start": "2026-10-26T08:49:46+0400",
"end": "2026-10-26T08:50:06+0400",
"duration_s": 20,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf' && '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.venv/bin/python' -m perfkit.gen.verify --scale 2"
"cmd": "cd 'perf' && 'perf/.venv/bin/python' -m perfkit.gen.verify --scale 2"
},
"stand": {
"status": "OK",
@ -32,7 +32,7 @@
"start": "2026-10-26T08:50:06+0400",
"end": "2026-10-26T08:50:07+0400",
"duration_s": 1,
"cmd": "(curl -fsS -o /dev/null 'http://localhost:8000/healthz' || '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/stand.sh' api) && ([ -f '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.build/prod/index.html' ] || '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/stand.sh' web-build) && (curl -fsS -o /dev/null 'http://localhost:8080/' || '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/stand.sh' web) && curl -fsS 'http://localhost:8080/' | cmp -s - '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.build/prod/index.html' && echo 'web :8080 = prod-сборка' && '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/stand.sh' smoke"
"cmd": "(curl -fsS -o /dev/null 'http://localhost:8000/healthz' || 'perf/stand.sh' api) && ([ -f 'perf/.build/prod/index.html' ] || 'perf/stand.sh' web-build) && (curl -fsS -o /dev/null 'http://localhost:8080/' || 'perf/stand.sh' web) && curl -fsS 'http://localhost:8080/' | cmp -s - 'perf/.build/prod/index.html' && echo 'web :8080 = prod-сборка' && 'perf/stand.sh' smoke"
},
"preflight": {
"status": "OK",
@ -40,7 +40,7 @@
"start": "2026-10-26T08:50:07+0400",
"end": "2026-10-26T08:50:08+0400",
"duration_s": 1,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/e2e' && for f in scenarios/scroll.spec.ts scenarios/modals.spec.ts; do env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=2 PERF_PRIORITY=1,2 npx playwright test --list $f | tail -1 || exit 1; done"
"cmd": "cd 'perf/e2e' && for f in scenarios/scroll.spec.ts scenarios/modals.spec.ts; do env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=2 PERF_PRIORITY=1,2 npx playwright test --list $f | tail -1 || exit 1; done"
},
"scroll": {
"status": "OK",
@ -48,7 +48,7 @@
"start": "2026-10-26T08:50:08+0400",
"end": "2026-10-26T11:19:59+0400",
"duration_s": 8991,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=2 PERF_RUN_ID=20261026-s2 PERF_WEB=http://localhost:8080 PERF_LOAD_TIMEOUT_MS=2400000 PERF_TEST_TIMEOUT_MS=5400000 PERF_SQLSTATS_TAG=scroll PERF_REPEATS=1 PERF_TRACE=0 npx playwright test scenarios/scroll.spec.ts"
"cmd": "cd 'perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=2 PERF_RUN_ID=20261026-s2 PERF_WEB=http://localhost:8080 PERF_LOAD_TIMEOUT_MS=2400000 PERF_TEST_TIMEOUT_MS=5400000 PERF_SQLSTATS_TAG=scroll PERF_REPEATS=1 PERF_TRACE=0 npx playwright test scenarios/scroll.spec.ts"
},
"coauthor": {
"status": "SKIP",
@ -64,7 +64,7 @@
"start": "2026-10-26T11:19:59+0400",
"end": "2026-10-26T11:22:15+0400",
"duration_s": 136,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf' && '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.venv/bin/python' -m perfkit.gen.grow --scale 2"
"cmd": "cd 'perf' && 'perf/.venv/bin/python' -m perfkit.gen.grow --scale 2"
},
"modals": {
"status": "OK",
@ -72,7 +72,7 @@
"start": "2026-10-26T11:22:15+0400",
"end": "2026-10-26T11:31:24+0400",
"duration_s": 549,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=2 PERF_RUN_ID=20261026-s2 PERF_WEB=http://localhost:8080 PERF_LOAD_TIMEOUT_MS=2400000 PERF_TEST_TIMEOUT_MS=5400000 PERF_SQLSTATS_TAG=modals PERF_PRIORITY=1,2 npx playwright test scenarios/modals.spec.ts"
"cmd": "cd 'perf/e2e' && env -u PERF_TARGETS -u PERF_REPEATS -u PERF_CPU_RATES -u PERF_ROLES -u PERF_AXES -u PERF_MODALS -u PERF_PRIORITY -u PERF_PROFILING -u PERF_SQLSTATS_TAG -u PERF_SQLSTATS -u PERF_COAUTHOR_RATES -u PERF_TRACE -u PERF_RESULTS_DIR -u PERF_MEM_CYCLES -u PERF_MEM_SNAPSHOTS PERF_SCALE=2 PERF_RUN_ID=20261026-s2 PERF_WEB=http://localhost:8080 PERF_LOAD_TIMEOUT_MS=2400000 PERF_TEST_TIMEOUT_MS=5400000 PERF_SQLSTATS_TAG=modals PERF_PRIORITY=1,2 npx playwright test scenarios/modals.spec.ts"
},
"modals_profiling": {
"status": "SKIP",
@ -104,7 +104,7 @@
"start": "2026-10-26T11:31:25+0400",
"end": "2026-10-26T11:47:44+0400",
"duration_s": 979,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf' && '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.venv/bin/python' -m perfkit.bench 'results/20261026-s2' --repeats 20 --scale 2"
"cmd": "cd 'perf' && 'perf/.venv/bin/python' -m perfkit.bench 'results/20261026-s2' --repeats 20 --scale 2"
},
"aggregate": {
"status": "OK",
@ -112,7 +112,7 @@
"start": "2026-10-26T11:47:44+0400",
"end": "2026-10-26T11:47:44+0400",
"duration_s": 0,
"cmd": "cd '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf' && rm -f '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-s2/summary.json' && '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.venv/bin/python' -m perfkit.aggregate 'results/20261026-s2' && { [ ! -f 'results/20261026-s2/modal.jsonl' ] || '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/.venv/bin/python' -m perfkit.modals_inventory 'results/20261026-s2'; } && mkdir -p '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-s2' && for d in results/20261026-s2/sql/*/; do if [ -d \"$d\" ]; then t=$(basename \"$d\"); mkdir -p '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-s2/sql/'$t || exit 1; if [ -f \"$d\"sql_top.json ]; then cp \"$d\"sql_top.json '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-s2/sql/'$t/ || exit 1; fi; if [ -d \"$d\"explain ]; then cp -R \"$d\"explain '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-s2/sql/'$t/ || exit 1; fi; fi; done && for f in results/20261026-s2/memtrend.txt results/manifest-s2.json results/gen-stats-s2.json results/grow-s2.json results/20261026-s2/run-all.status.json; do if [ -f \"$f\" ]; then cp \"$f\" '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-s2/' || exit 1; fi; done && ls -R '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-s2' && test -f '/Users/andrey.epifancev/projects/fomichev_claude/DFiP_Budget_planing/.claude/worktrees/perf-profiling/perf/report-data/20261026-s2/summary.json'"
"cmd": "cd 'perf' && rm -f 'perf/report-data/20261026-s2/summary.json' && 'perf/.venv/bin/python' -m perfkit.aggregate 'results/20261026-s2' && { [ ! -f 'results/20261026-s2/modal.jsonl' ] || 'perf/.venv/bin/python' -m perfkit.modals_inventory 'results/20261026-s2'; } && mkdir -p 'perf/report-data/20261026-s2' && for d in results/20261026-s2/sql/*/; do if [ -d \"$d\" ]; then t=$(basename \"$d\"); mkdir -p 'perf/report-data/20261026-s2/sql/'$t || exit 1; if [ -f \"$d\"sql_top.json ]; then cp \"$d\"sql_top.json 'perf/report-data/20261026-s2/sql/'$t/ || exit 1; fi; if [ -d \"$d\"explain ]; then cp -R \"$d\"explain 'perf/report-data/20261026-s2/sql/'$t/ || exit 1; fi; fi; done && for f in results/20261026-s2/memtrend.txt results/manifest-s2.json results/gen-stats-s2.json results/grow-s2.json results/20261026-s2/run-all.status.json; do if [ -f \"$f\" ]; then cp \"$f\" 'perf/report-data/20261026-s2/' || exit 1; fi; done && ls -R 'perf/report-data/20261026-s2' && test -f 'perf/report-data/20261026-s2/summary.json'"
}
}
}

View File

@ -4,8 +4,10 @@
# perf/run-all.sh # всё: масштаб 1, затем 2
# PERF_DRY_RUN=1 perf/run-all.sh # план: шаги, команды, оценка длительности; ничего не запускает
# PERF_SCALES=2 PERF_RUN_TAG=20261026 PERF_SKIP_RESET=1 PERF_STEPS=modals,bench,aggregate perf/run-all.sh # возобновить
# PERF_SCALES=1 PERF_RUN_TAG=20261026 PERF_STEPS=control4x,aggregate \
# PERF_CONTROL_TARGETS='FORM_2/AHR/null@y,modal:sheet_select_vsp' perf/run-all.sh # контроль CPU 4x
# PERF_SCALES=1 PERF_RUN_TAG=20261026-control PERF_SKIP_RESET=1 PERF_STEPS=control4x,aggregate \
# PERF_CONTROL_TARGETS='FORM_2/AHR/null@y,svod/svod1_MAIN,svod/svod2_GO,modal:sheet_select_vsp@big' perf/run-all.sh # контроль CPU 4x
# ВНИМАНИЕ: control4x с тегом основного прогона (PERF_RUN_TAG=20261026) допишет в results/20261026-s1 и пересоберёт
# report-data/20261026-s1 (summary, копии манифеста/gen-stats/grow) - для контроля нужен отдельный тег (design.md).
#
# Переменные:
# PERF_SCALES масштабы по порядку (по умолчанию "1 2")
@ -31,6 +33,7 @@
set -uo pipefail
PERF="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(dirname "$PERF")" # копия run-all.status.json в report-data - с путями относительно корня репозитория
E2E="$PERF/e2e"
PY="${PERF_PY:-$PERF/.venv/bin/python}" # python для perfkit (подмена - только тесты run-all)
STATUS_PY="$PERF/.venv/bin/python"
@ -149,8 +152,9 @@ step_cmd() {
"&& mkdir -p '$out' && for d in results/$RID/sql/*/; do if [ -d \"\$d\" ]; then t=\$(basename \"\$d\");" \
"mkdir -p '$out/sql/'\$t || exit 1; if [ -f \"\$d\"sql_top.json ]; then cp \"\$d\"sql_top.json '$out/sql/'\$t/ || exit 1; fi;" \
"if [ -d \"\$d\"explain ]; then cp -R \"\$d\"explain '$out/sql/'\$t/ || exit 1; fi; fi; done" \
"&& for f in results/$RID/memtrend.txt results/manifest-s$SCALE.json results/gen-stats-s$SCALE.json results/grow-s$SCALE.json results/$RID/run-all.status.json;" \
"&& for f in results/$RID/memtrend.txt results/manifest-s$SCALE.json results/gen-stats-s$SCALE.json results/grow-s$SCALE.json;" \
"do if [ -f \"\$f\" ]; then cp \"\$f\" '$out/' || exit 1; fi; done" \
"&& { [ ! -f 'results/$RID/run-all.status.json' ] || sed 's#$REPO_ROOT/##g' 'results/$RID/run-all.status.json' > '$out/run-all.status.json'; }" \
"&& ls -R '$out' && test -f '$out/summary.json'" ;;
esac
}
@ -238,7 +242,7 @@ for SCALE in $SCALES; do
fi
done
# итоговый статус - и в report-data (если aggregate уже создал каталог)
[ -d "$PERF/report-data/$RID" ] && cp "$STATUS" "$PERF/report-data/$RID/"
[ -d "$PERF/report-data/$RID" ] && sed "s#$REPO_ROOT/##g" "$STATUS" > "$PERF/report-data/$RID/run-all.status.json"
log "=== масштаб $SCALE готов: $(jq -r '[.steps|to_entries[]|"\(.key)=\(.value.status)"]|join(" ")' "$STATUS" 2>/dev/null)"
done
if [ "$DRY" = 1 ]; then