Andrey Epifancev efa537e008 perf: каркас замеров фронта
Refs #202

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 22:12:36 +04:00

64 lines
2.3 KiB
TypeScript

import type { CDPSession, Page } from '@playwright/test';
import { createWriteStream, mkdirSync, writeFileSync } from 'node:fs';
import path from 'node:path';
const sessions = new WeakMap<Page, CDPSession>();
async function cdp(page: Page): Promise<CDPSession> {
let s = sessions.get(page);
if (!s) {
s = await page.context().newCDPSession(page);
sessions.set(page, s);
}
return s;
}
/** CPU throttling: rate=1 — без замедления, 4 — в 4 раза медленнее. */
export async function throttle(page: Page, rate: number): Promise<void> {
await (await cdp(page)).send('Emulation.setCPUThrottlingRate', { rate });
}
export async function startTrace(page: Page): Promise<void> {
await page.context().browser()!.startTracing(page, {
categories: ['devtools.timeline', 'disabled-by-default-devtools.timeline', 'v8.execute', 'blink.user_timing'],
screenshots: false,
});
}
export async function stopTrace(page: Page, file: string): Promise<void> {
mkdirSync(path.dirname(file), { recursive: true });
const buf = await page.context().browser()!.stopTracing();
writeFileSync(file, buf);
}
export async function gc(page: Page): Promise<void> {
const s = await cdp(page);
await s.send('HeapProfiler.enable');
await s.send('HeapProfiler.collectGarbage');
}
export async function domCounters(page: Page): Promise<{ documents: number; nodes: number; jsEventListeners: number }> {
return (await (await cdp(page)).send('Memory.getDOMCounters')) as any;
}
/** Размер JS-кучи после GC, байты. */
export async function heapUsed(page: Page): Promise<number> {
await gc(page);
const s = await cdp(page);
await s.send('Runtime.enable');
const r = (await s.send('Runtime.getHeapUsage')) as { usedSize: number };
return r.usedSize;
}
export async function heapSnapshot(page: Page, file: string): Promise<void> {
mkdirSync(path.dirname(file), { recursive: true });
const s = await cdp(page);
const out = createWriteStream(file);
const onChunk = (e: { chunk: string }) => { out.write(e.chunk); };
s.on('HeapProfiler.addHeapSnapshotChunk', onChunk);
await s.send('HeapProfiler.enable');
await s.send('HeapProfiler.takeHeapSnapshot', { reportProgress: false });
s.off('HeapProfiler.addHeapSnapshotChunk', onChunk);
await new Promise<void>((res) => out.end(res));
}