perf: сценарий памяти свода 2 (GO «все» → RF «все» → GO)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5dc6662767
commit
3363291801
@ -74,3 +74,8 @@ export class ByteCounter {
|
|||||||
export function filterResultMs(startAt: number, stableAt: number, respAt: number | null): number {
|
export function filterResultMs(startAt: number, stableAt: number, respAt: number | null): number {
|
||||||
return Math.max(stableAt, respAt ?? 0) - startAt;
|
return Math.max(stableAt, respAt ?? 0) - startAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Точки замера памяти свода 2: GO «все» -> RF «все» -> (опц. прокрутка RF) -> снова GO. */
|
||||||
|
export function memoryPoints(env: Record<string, string | undefined>): string[] {
|
||||||
|
return env.PERF_SVOD2_MEM_SCROLL === '1' ? ['go', 'rf', 'rf_scrolled', 'final'] : ['go', 'rf', 'final'];
|
||||||
|
}
|
||||||
|
|||||||
92
perf/e2e/scenarios/svod2-memory.spec.ts
Normal file
92
perf/e2e/scenarios/svod2-memory.spec.ts
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/**
|
||||||
|
* Сценарий памяти свода 2 (Task 16): роль dfip, свежий контекст на каждый повтор, одна SPA-сессия внутри повтора.
|
||||||
|
* Точки (lib/svod2.ts memoryPoints): go (вкладка GO, «Все ССП/РФ», «Загрузить») -> rf (вкладка RF, то же)
|
||||||
|
* [-> rf_scrolled при PERF_SVOD2_MEM_SCROLL=1] -> final (возврат на GO, «Загрузить»).
|
||||||
|
* В каждой точке gc -> heapUsed, domCounters. Запись: scenario "svod2-memory", target "svod2/<point>".
|
||||||
|
* Env: PERF_SCALE, PERF_RUN_ID, PERF_REPEATS (3), PERF_SVOD2_MEM_SCROLL, PERF_LOAD_TIMEOUT_MS, PERF_MAX_STEPS,
|
||||||
|
* PERF_TEST_TIMEOUT_MS.
|
||||||
|
*/
|
||||||
|
import { test, type Page } from '@playwright/test';
|
||||||
|
import { loadManifest, scale } from '../lib/manifest';
|
||||||
|
import { loginAs, WEB } from '../lib/auth';
|
||||||
|
import { throttle, heapUsed, domCounters } from '../lib/cdp';
|
||||||
|
import { append } from '../lib/results';
|
||||||
|
import { scrollThrough } from '../lib/scroll';
|
||||||
|
import { SVOD2_DATA_ROW_SELECTOR, memoryPoints } from '../lib/svod2';
|
||||||
|
|
||||||
|
const CONTAINER = '.MuiTableContainer-root';
|
||||||
|
const MIN_ROWS = 20;
|
||||||
|
const REPEATS = Number(process.env.PERF_REPEATS ?? 3);
|
||||||
|
const LOAD_TIMEOUT = Number(process.env.PERF_LOAD_TIMEOUT_MS ?? 900_000);
|
||||||
|
const MAX_STEPS = Number(process.env.PERF_MAX_STEPS ?? 5000);
|
||||||
|
|
||||||
|
async function waitRows(page: Page, what: string): Promise<number> {
|
||||||
|
const t0 = Date.now();
|
||||||
|
for (;;) {
|
||||||
|
const n = await page.evaluate(([sel, rs]) => document.querySelectorAll(`${sel} ${rs}`).length, [CONTAINER, SVOD2_DATA_ROW_SELECTOR]);
|
||||||
|
if (n >= MIN_ROWS) return n;
|
||||||
|
if (Date.now() - t0 > LOAD_TIMEOUT) throw new Error(`${what}: rows<${MIN_ROWS} за ${LOAD_TIMEOUT} мс (rows=${n})`);
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** «Все ССП/РФ» + «Загрузить» (Svod2Page.jsx), как в scroll.spec.ts. */
|
||||||
|
async function loadAll(page: Page): Promise<void> {
|
||||||
|
await page.getByLabel('ССП/РФ').click();
|
||||||
|
await page.getByRole('option', { name: 'Все ССП/РФ' }).click();
|
||||||
|
await page.keyboard.press('Escape');
|
||||||
|
await page.getByRole('button', { name: 'Загрузить' }).click();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let repeat = 0; repeat < REPEATS; repeat++) {
|
||||||
|
test(`svod2-memory: dfip #${repeat}`, async ({ browser }) => {
|
||||||
|
test.setTimeout(Number(process.env.PERF_TEST_TIMEOUT_MS ?? 3600_000));
|
||||||
|
const user = loadManifest().users['dfip'];
|
||||||
|
if (!user) throw new Error('в манифесте нет пользователя dfip');
|
||||||
|
const points = memoryPoints(process.env);
|
||||||
|
const ctx = await browser.newContext({ viewport: { width: 1600, height: 900 } });
|
||||||
|
try {
|
||||||
|
await loginAs(ctx, user);
|
||||||
|
const page = await ctx.newPage();
|
||||||
|
page.on('pageerror', (e) => console.log('pageerror:', e.message));
|
||||||
|
await page.goto(WEB + '/svod/2');
|
||||||
|
await throttle(page, 1);
|
||||||
|
|
||||||
|
const sample = async (point: string, rows: number) => {
|
||||||
|
const heap = await heapUsed(page); // gc внутри
|
||||||
|
const dom = await domCounters(page);
|
||||||
|
append({
|
||||||
|
scenario: 'svod2-memory', target: `svod2/${point}`, role: 'dfip', scale: scale(), cpu_rate: 1, repeat,
|
||||||
|
metrics: { heap_used_mb: heap / 1048576, nodes: dom.nodes, documents: dom.documents, js_event_listeners: dom.jsEventListeners, rows_visible: rows },
|
||||||
|
artifacts: [],
|
||||||
|
});
|
||||||
|
console.log(`${point} #${repeat}: heap ${(heap / 1048576).toFixed(1)} MB, nodes ${dom.nodes}, listeners ${dom.jsEventListeners}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const point of points) {
|
||||||
|
let rows: number;
|
||||||
|
if (point === 'go') {
|
||||||
|
await page.getByRole('tab').nth(0).click();
|
||||||
|
await loadAll(page);
|
||||||
|
rows = await waitRows(page, point);
|
||||||
|
} else if (point === 'rf') {
|
||||||
|
await page.getByRole('tab').nth(1).click();
|
||||||
|
await loadAll(page);
|
||||||
|
rows = await waitRows(page, point);
|
||||||
|
} else if (point === 'rf_scrolled') {
|
||||||
|
const r = await scrollThrough(page, CONTAINER, 'y', 200, MAX_STEPS);
|
||||||
|
if (!r.complete) throw new Error(`rf_scrolled: скролл не дошёл до конца (${r.reason ?? 'incomplete'})`);
|
||||||
|
rows = await waitRows(page, point);
|
||||||
|
} else {
|
||||||
|
await page.getByRole('tab').nth(0).click();
|
||||||
|
await loadAll(page);
|
||||||
|
rows = await waitRows(page, point);
|
||||||
|
}
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
await sample(point, rows);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
await ctx.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -7,6 +7,7 @@ import {
|
|||||||
svod2RespRe,
|
svod2RespRe,
|
||||||
countPagesRequested,
|
countPagesRequested,
|
||||||
filterResultMs,
|
filterResultMs,
|
||||||
|
memoryPoints,
|
||||||
SVOD2_DATA_ROW_SELECTOR,
|
SVOD2_DATA_ROW_SELECTOR,
|
||||||
SVOD2_PLACEHOLDER_SELECTOR,
|
SVOD2_PLACEHOLDER_SELECTOR,
|
||||||
} from '../lib/svod2.ts';
|
} from '../lib/svod2.ts';
|
||||||
@ -69,3 +70,12 @@ test('filterResultMs: нет запроса поиска - только стаб
|
|||||||
assert.equal(filterResultMs(1000, 1700, 1200), 700);
|
assert.equal(filterResultMs(1000, 1700, 1200), 700);
|
||||||
assert.equal(filterResultMs(1000, 1700, 1900), 900);
|
assert.equal(filterResultMs(1000, 1700, 1900), 900);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('memoryPoints: по умолчанию go, rf, final', () => {
|
||||||
|
assert.deepEqual(memoryPoints({}), ['go', 'rf', 'final']);
|
||||||
|
assert.deepEqual(memoryPoints({ PERF_SVOD2_MEM_SCROLL: '0' }), ['go', 'rf', 'final']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('memoryPoints: PERF_SVOD2_MEM_SCROLL=1 добавляет rf_scrolled', () => {
|
||||||
|
assert.deepEqual(memoryPoints({ PERF_SVOD2_MEM_SCROLL: '1' }), ['go', 'rf', 'rf_scrolled', 'final']);
|
||||||
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user