add benchmark for replayer's fast-forward mode (#947)
* add benchmark for replayer's fast-forward mode * add comments * change the title * build: make benchmark a seperate command
This commit is contained in:
@@ -5,8 +5,8 @@
|
||||
"scripts": {
|
||||
"prepare": "npm run prepack",
|
||||
"prepack": "npm run bundle",
|
||||
"test": "npm run bundle:browser && jest",
|
||||
"test:headless": "npm run bundle:browser && PUPPETEER_HEADLESS=true jest",
|
||||
"test": "npm run bundle:browser && jest --testPathIgnorePatterns test/benchmark",
|
||||
"test:headless": "PUPPETEER_HEADLESS=true npm run test",
|
||||
"test:watch": "PUPPETEER_HEADLESS=true npm run test -- --watch",
|
||||
"repl": "npm run bundle:browser && node scripts/repl.js",
|
||||
"dev": "yarn bundle:browser --watch",
|
||||
@@ -15,7 +15,8 @@
|
||||
"typings": "tsc -d --declarationDir typings",
|
||||
"check-types": "tsc -noEmit",
|
||||
"prepublish": "npm run typings && npm run bundle",
|
||||
"lint": "yarn eslint src"
|
||||
"lint": "yarn eslint src",
|
||||
"benchmark": "jest test/benchmark"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
170
packages/rrweb/test/benchmark/replay-fast-forward.test.ts
Normal file
170
packages/rrweb/test/benchmark/replay-fast-forward.test.ts
Normal file
@@ -0,0 +1,170 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import type { eventWithTime, recordOptions } from '../../src/types';
|
||||
import { launchPuppeteer, ISuite } from '../utils';
|
||||
|
||||
const suites: Array<{
|
||||
title: string;
|
||||
eval: string;
|
||||
eventsString?: string;
|
||||
times?: number; // defaults to 5
|
||||
}> = [
|
||||
{
|
||||
title: 'append 70 x 70 x 70 elements',
|
||||
eval: `
|
||||
() => {
|
||||
return new Promise((resolve) => {
|
||||
const branches = 70;
|
||||
const depth = 3;
|
||||
// append children for the current node
|
||||
function expand(node, depth) {
|
||||
if (depth == 0) return;
|
||||
for (let b = 0; b < branches; b++) {
|
||||
const child = document.createElement('div');
|
||||
node.appendChild(child);
|
||||
expand(child, depth - 1);
|
||||
}
|
||||
}
|
||||
const frag = document.createDocumentFragment();
|
||||
const node = document.createElement('div');
|
||||
expand(node, depth);
|
||||
frag.appendChild(node);
|
||||
document.body.appendChild(frag);
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
`,
|
||||
times: 3,
|
||||
},
|
||||
{
|
||||
title: 'append 1000 elements and reverse their order',
|
||||
eval: `
|
||||
() => {
|
||||
return new Promise(async (resolve) => {
|
||||
const branches = 1000;
|
||||
function waitForTimeout(timeout) {
|
||||
return new Promise((resolve) => setTimeout(() => resolve(), timeout));
|
||||
}
|
||||
const frag = document.createDocumentFragment();
|
||||
const node = document.createElement('div');
|
||||
for (let b = 0; b < branches; b++) {
|
||||
const child = document.createElement('div');
|
||||
node.appendChild(child);
|
||||
child.textContent = b + 1;
|
||||
}
|
||||
frag.appendChild(node);
|
||||
document.body.appendChild(frag);
|
||||
const children = node.children;
|
||||
await waitForTimeout(0);
|
||||
// reverse the order of children
|
||||
for (let i = children.length - 1; i >= 0; i--)
|
||||
node.appendChild(node.children[i]);
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
`,
|
||||
times: 3,
|
||||
},
|
||||
];
|
||||
|
||||
function avg(v: number[]): number {
|
||||
return v.reduce((prev, cur) => prev + cur, 0) / v.length;
|
||||
}
|
||||
|
||||
describe('benchmark: replayer fast-forward performance', () => {
|
||||
jest.setTimeout(240000);
|
||||
let code: ISuite['code'];
|
||||
let page: ISuite['page'];
|
||||
let browser: ISuite['browser'];
|
||||
|
||||
beforeAll(async () => {
|
||||
browser = await launchPuppeteer({
|
||||
headless: true,
|
||||
args: ['--disable-dev-shm-usage'],
|
||||
});
|
||||
|
||||
const bundlePath = path.resolve(__dirname, '../../dist/rrweb.min.js');
|
||||
code = fs.readFileSync(bundlePath, 'utf8');
|
||||
|
||||
for (const suite of suites)
|
||||
suite.eventsString = await generateEvents(suite.eval);
|
||||
}, 600_000);
|
||||
|
||||
afterAll(async () => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
for (const suite of suites) {
|
||||
it(
|
||||
suite.title,
|
||||
async () => {
|
||||
suite.times = suite.times ?? 5;
|
||||
const durations: number[] = [];
|
||||
for (let i = 0; i < suite.times; i++) {
|
||||
page = await browser.newPage();
|
||||
await page.goto('about:blank');
|
||||
await page.setContent(`<html>
|
||||
<script>
|
||||
${code.toString()}
|
||||
</script>
|
||||
<script>
|
||||
window.events = ${suite.eventsString};
|
||||
</script>
|
||||
</html>`);
|
||||
const duration = (await page.evaluate(() => {
|
||||
const replayer = new (window as any).rrweb.Replayer(
|
||||
(window as any).events,
|
||||
);
|
||||
const start = Date.now();
|
||||
replayer.play(replayer.getMetaData().totalTime + 100);
|
||||
return Date.now() - start;
|
||||
})) as number;
|
||||
durations.push(duration);
|
||||
await page.close();
|
||||
}
|
||||
|
||||
console.table([
|
||||
{
|
||||
title: suite.title,
|
||||
times: suite.times,
|
||||
duration: avg(durations),
|
||||
durations: durations.join(', '),
|
||||
},
|
||||
]);
|
||||
},
|
||||
60_000,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the recorded events after the mutation function is executed.
|
||||
*/
|
||||
async function generateEvents(mutateNodesFn: string): Promise<string> {
|
||||
const page = await browser.newPage();
|
||||
|
||||
await page.goto('about:blank');
|
||||
await page.setContent(`<html>
|
||||
<script>
|
||||
${code.toString()}
|
||||
</script>
|
||||
</html>`);
|
||||
const eventsString = (await page.evaluate((mutateNodesFn) => {
|
||||
return new Promise((resolve) => {
|
||||
const events: eventWithTime[] = [];
|
||||
const options: recordOptions<eventWithTime> = {
|
||||
emit: (event) => {
|
||||
events.push(event);
|
||||
},
|
||||
};
|
||||
const record = (window as any).rrweb.record;
|
||||
record(options);
|
||||
eval(mutateNodesFn)().then(() => {
|
||||
resolve(JSON.stringify(events));
|
||||
});
|
||||
});
|
||||
}, mutateNodesFn)) as string;
|
||||
|
||||
await page.close();
|
||||
return eventsString;
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user