perf: замеры без троттлинга CPU (решение человека)

Refs #202

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Andrey Epifancev 2026-10-25 23:20:48 +04:00
parent 419a20e950
commit 4836580c50
3 changed files with 16 additions and 9 deletions

View File

@ -150,3 +150,9 @@
| 2026-10-25 | Только вертикальный скролл (ось y), роль `rf` | Бриф: «скролл при соавторе»; горизонтальная ось не зависит от потока входящих правок | Нет замера оси x при соавторе | | 2026-10-25 | Только вертикальный скролл (ось y), роль `rf` | Бриф: «скролл при соавторе»; горизонтальная ось не зависит от потока входящих правок | Нет замера оси x при соавторе |
| 2026-10-25 | Вспомогательный `waitRows` продублирован в `scroll-coauthor.spec.ts`, а не вынесен в lib/ | Не трогать `scroll.spec.ts` Task 5; функция короткая | Дубли при правке | | 2026-10-25 | Вспомогательный `waitRows` продублирован в `scroll-coauthor.spec.ts`, а не вынесен в lib/ | Не трогать `scroll.spec.ts` Task 5; функция короткая | Дубли при правке |
| 2026-10-25 | Фильтр свода по умолчанию мерится на `max(PERF_CPU_RATES)` (при умолчании `1`), имя теста `filter cpu<N>` | Троттлинг отключён по умолчанию, но `PERF_CPU_RATES=1,4,6` должен вести себя как прежде | Нет | | 2026-10-25 | Фильтр свода по умолчанию мерится на `max(PERF_CPU_RATES)` (при умолчании `1`), имя теста `filter cpu<N>` | Троттлинг отключён по умолчанию, но `PERF_CPU_RATES=1,4,6` должен вести себя как прежде | Нет |
## Decisions made with the human
| Дата | Решение | Источник |
|---|---|---|
| 2026-10-25 | Замеры без троттлинга CPU: все сценарии по умолчанию на CPU 1×; код `throttle()` и env `PERF_CPU_RATES=1,4,6` оставлены для ручного включения; число повторов (3) не сокращено | Решение человека, передано координатором |

View File

@ -61,9 +61,9 @@ PERF_RUN_ID=t PERF_TARGETS='FORM_2/AHR/*' PERF_CPU_RATES=1 PERF_REPEATS=1 npx pl
cd .. && .venv/bin/python -m perfkit.aggregate results/s1 cd .. && .venv/bin/python -m perfkit.aggregate results/s1
``` ```
- Матрица: роль `rf` x листы с `owner=rf` и отчёты проектов x оси y,x x CPU 1,4,6 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`). - Матрица: роль `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). - target: `FORM_x/<sheet>/<direction|null>`, `project/<report_type>/<project_id>`, `svod/<name>`; к записи добавляется суффикс оси `@y` / `@x` (агрегатор группирует по target).
- Переменные: `PERF_TARGETS` (glob через запятую; сопоставляется с target без суффикса оси и с полным), `PERF_CPU_RATES` (`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 мин). - Переменные: `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`. - Каждый замер - новый 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 не попадают). - Метрики: 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`. - Сайт свода не читает `#hash` из URL: вкладка (`FORM_1`, `GO`...) выбирается кликом по `role=tab`.

View File

@ -7,7 +7,7 @@
* сопоставляется с target без суффикса оси и с полным (`.../@y`) * сопоставляется с target без суффикса оси и с полным (`.../@y`)
* PERF_RUN_ID каталог прогона perf/results/<run_id> * PERF_RUN_ID каталог прогона perf/results/<run_id>
* PERF_REPEATS число повторов вместо матричного (3 для rf/свод, 1 для admin-контроля) * PERF_REPEATS число повторов вместо матричного (3 для rf/свод, 1 для admin-контроля)
* PERF_CPU_RATES '1,4,6' - список CPU throttling rate * PERF_CPU_RATES '1' по умолчанию (без троттлинга, решение человека); '1,4,6' включает троттлинг вручную
* PERF_ROLES фильтр ролей через запятую (rf,admin,dfip) * PERF_ROLES фильтр ролей через запятую (rf,admin,dfip)
* PERF_AXES 'y,x' - оси для rf (по умолчанию y,x) * PERF_AXES 'y,x' - оси для rf (по умолчанию y,x)
* PERF_LOAD_TIMEOUT_MS ожидание данных после навигации (по умолчанию 900000) * PERF_LOAD_TIMEOUT_MS ожидание данных после навигации (по умолчанию 900000)
@ -29,7 +29,8 @@ const LOAD_TIMEOUT = Number(process.env.PERF_LOAD_TIMEOUT_MS ?? 900_000);
const MAX_STEPS = Number(process.env.PERF_MAX_STEPS ?? 5000); const MAX_STEPS = Number(process.env.PERF_MAX_STEPS ?? 5000);
const envList = (n: string, d: string[]) => (process.env[n] ? process.env[n]!.split(',').map((s) => s.trim()).filter(Boolean) : d); const envList = (n: string, d: string[]) => (process.env[n] ? process.env[n]!.split(',').map((s) => s.trim()).filter(Boolean) : d);
const CPU_RATES = envList('PERF_CPU_RATES', ['1', '4', '6']).map(Number); const CPU_RATES = envList('PERF_CPU_RATES', ['1']).map(Number);
const FILTER_CPU = Math.max(...CPU_RATES); // замер смены фильтра: на самом тяжёлом из заданных CPU (по умолчанию 1)
const ROLES = envList('PERF_ROLES', ['rf', 'admin', 'dfip']); const ROLES = envList('PERF_ROLES', ['rf', 'admin', 'dfip']);
const AXES = envList('PERF_AXES', ['y', 'x']) as Axis[]; const AXES = envList('PERF_AXES', ['y', 'x']) as Axis[];
const repeats = (dflt: number) => (process.env.PERF_REPEATS ? Number(process.env.PERF_REPEATS) : dflt); const repeats = (dflt: number) => (process.env.PERF_REPEATS ? Number(process.env.PERF_REPEATS) : dflt);
@ -234,7 +235,7 @@ async function measure(browser: import('@playwright/test').Browser, o: RunOpts)
} }
} }
/** Таймаут теста: 45 мин по умолчанию, свод 2 (загрузка до 15 мин + скролл на CPU 6 ~40 мин) - 3 ч. */ /** Таймаут теста: 45 мин по умолчанию, свод 2 (загрузка до 15 мин + скролл на CPU 6 ~40 мин, если включён вручную) - 3 ч. */
const testTimeout = (t: Target) => const testTimeout = (t: Target) =>
t.kind === 'svod2' t.kind === 'svod2'
? Number(process.env.PERF_TEST_TIMEOUT_SVOD2_MS ?? 3 * 3600_000) ? Number(process.env.PERF_TEST_TIMEOUT_SVOD2_MS ?? 3 * 3600_000)
@ -256,11 +257,11 @@ test.describe('scroll', () => {
}); });
} }
} }
// смена фильтра - только своды, один раз на CPU 6 // смена фильтра - только своды, один раз на FILTER_CPU
if (t.kind !== 'sheet' && t.kind !== 'project' && CPU_RATES.includes(6)) { if (t.kind !== 'sheet' && t.kind !== 'project') {
test(`${t.name} ${ra.role} filter cpu6`, async ({ browser }) => { test(`${t.name} ${ra.role} filter cpu${FILTER_CPU}`, async ({ browser }) => {
test.setTimeout(testTimeout(t)); test.setTimeout(testTimeout(t));
await measure(browser, { t, role: ra.role, axis, cpu: 6, repeat: 0, filter: true }); await measure(browser, { t, role: ra.role, axis, cpu: FILTER_CPU, repeat: 0, filter: true });
}); });
} }
} }