Andrey Epifancev 4836580c50 perf: замеры без троттлинга CPU (решение человека)
Refs #202

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 23:20:48 +04:00

70 lines
6.9 KiB
Markdown
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.

# Профилирование: perf/
## Стенд
Требования: Docker, python3.12, Node 24, npm.
```
perf/stand.sh all # up, migrate, bootstrap, web-build, api, web, smoke
perf/stand.sh down # остановить бэк, фронт и Postgres
```
Подкоманды: `up | migrate | bootstrap | api | web-build | web | smoke | reset | down | all`.
`reset` — чистая БД: останавливает бэк, сносит volume Postgres, поднимает заново (`up`, `migrate`, `bootstrap`, `api`); фронт не трогает.
- Postgres 16 (`pg_stat_statements`) на `localhost:55432`, `perf/perf/perf`.
- Бэк (`DEBUG=true`) на `http://localhost:8000`, логи и PID в `perf/.run/`.
- Фронт (prod-сборка, `rsbuild preview`) на `http://localhost:8080`; `/api` (включая WebSocket) проксируется на бэк.
- Профилирующая сборка (`PERF_PROFILING=1`, `react-dom/profiling`) лежит в `perf/.build/profiling`, обычная в `perf/.build/prod`.
Для запуска preview с профилирующей сборкой: `PERF_PROFILING=1 perf/stand.sh web` (после остановки обычного `web`).
- Админ: `admin` / `admin`.
- Переменные: `PERF_API`, `PERF_WEB`, `PERF_DB_DSN`.
- Зависимости Python ставятся в `perf/.venv` (`api/requirements-dev.txt` + `perf/requirements.txt`).
- npm берёт пакеты с `https://registry.npmjs.org` (`npm_config_registry`), `web/.npmrc` не нужен.
## Данные
```
perf/stand.sh reset # пустая БД (генератор на непустой БД откажется работать)
cd perf && .venv/bin/python -m perfkit.gen.run --scale 1 # ~20-40 мин, пишет results/manifest-s1.json
cd perf && .venv/bin/python -m perfkit.gen.verify --scale 1 # должен напечатать VERIFY OK
```
Генератор работает через HTTP-API под `admin` (WebSocket — только для программ и проектов FORM_4,
у них нет HTTP-ручки). Пользователи: `perf_rf`, `perf_rf_coauthor` (одна РФ, роль 3) и `perf_dfip`
(роль 2, все оргединицы), пароль `perf`; в манифесте они под ключами `rf`, `rf_coauthor`, `dfip`.
Числа плана и их обоснование — в `perf/perfkit/gen/plan.py`.
## Фронт: замеры
Каркас: `perf/e2e` (Playwright + CDP). Версии: `@playwright/test` 1.64.1, Chromium 156.0.8078.4 (headless shell, revision 1248).
```
cd perf/e2e && npm install && npx playwright install chromium # npm_config_registry=https://registry.npmjs.org
npx playwright test tests/harness.spec.ts # самопроверка каркаса
```
- `PERF_RUN_ID` — имя каталога прогона `perf/results/<run_id>/` (по умолчанию `YYYYMMDD-HHMM`).
- `PERF_SCALE` — масштаб манифеста `perf/results/manifest-s<scale>.json` (по умолчанию 1).
- `PERF_API`, `PERF_WEB` — адреса стенда (`http://localhost:8000`, `http://localhost:8080`).
- Агрегация: `cd perf && .venv/bin/python -m perfkit.aggregate results/<run_id>`.
- Библиотеки `perf/e2e/lib/`: `auth.loginAs`, `cdp.*` (throttle, trace, gc, heap), `probe` (long tasks > 50 мс, кадры rAF; тяжёлый кадр — интервал > 50 мс), `results.append`, `manifest.loadManifest`.
### Сценарии скролла
`perf/e2e/scenarios/scroll.spec.ts`, библиотека `lib/scroll.ts` (`scrollThrough`: колесо мыши шагами по 200 px вниз/вправо до конца и обратно, `complete` = `scrollTop + clientHeight >= scrollHeight - 2`). Самопроверка: `npx playwright test tests/scroll-lib.spec.ts`.
```
cd perf/e2e
PERF_RUN_ID=s1 PERF_SCALE=1 npx playwright test scenarios/scroll.spec.ts # вся матрица масштаба (долго!)
PERF_RUN_ID=t PERF_TARGETS='FORM_2/AHR/*' PERF_CPU_RATES=1 PERF_REPEATS=1 npx playwright test scenarios/scroll.spec.ts
cd .. && .venv/bin/python -m perfkit.aggregate results/s1
```
- Матрица: роль `rf` x листы с `owner=rf` и отчёты проектов x оси y,x x CPU 1 (без троттлинга, решение человека) x 3 повтора; `admin` x все листы x ось y x CPU x 1 повтор (только масштаб 1); `admin` и `dfip` x своды (svod1_MAIN/FORM_1..4, svod2_GO/RF, projects_summaries) x ось y x CPU x 3 повтора + одна смена фильтра на CPU 6 (target `.../filter`).
- target: `FORM_x/<sheet>/<direction|null>`, `project/<report_type>/<project_id>`, `svod/<name>`; к записи добавляется суффикс оси `@y` / `@x` (агрегатор группирует по target).
- Переменные: `PERF_TARGETS` (glob через запятую; сопоставляется с target без суффикса оси и с полным), `PERF_CPU_RATES` (по умолчанию `1`; `1,4,6` включает троттлинг вручную), `PERF_REPEATS` (число повторов вместо матричного), `PERF_ROLES` (`rf,admin,dfip`), `PERF_AXES` (`y,x`), `PERF_LOAD_TIMEOUT_MS` (ожидание данных, по умолчанию 15 мин; ответ свода 2 до 47 МБ), `PERF_MAX_STEPS`, `PERF_TEST_TIMEOUT_MS` (таймаут одного замера, по умолчанию 45 мин), `PERF_TEST_TIMEOUT_SVOD2_MS` (для свода 2, по умолчанию 3 ч: загрузка до 15 мин + скролл на CPU 6 порядка 40 мин).
- Каждый замер - новый browser context; CPU-троттлинг включается после загрузки данных (до скролла). Перед замером ждём >= 20 строк `tbody tr`; если не дождались - запись `incomplete: true` с `skip_reason`.
- Метрики: probe (long tasks, кадры), `axis` (0 = y, 1 = x), `rows_visible_before/after`, `json_bytes_sheet` (размер распакованного ответа загрузки данных из сетевого лога), `steps`. Записи с `skip_reason` (`no_overflow`, `rows<20`, `filter_no_effect`, `scroll_incomplete`...) всегда `incomplete:true`; в конце прогона они выводятся списком. Метрика `traced=1` - замер с включённым трейсом (повтор 0), Task 10 может исключать его из статистики. Trace первого повтора - в `perf/results/<run_id>/artifacts/` (30-70 МБ каждый, в git не попадают).
- Сайт свода не читает `#hash` из URL: вкладка (`FORM_1`, `GO`...) выбирается кликом по `role=tab`.