Files
orca/config/scripts/plugin-message-budget-benchmark.mjs
T

96 lines
3.0 KiB
JavaScript

import assert from 'node:assert/strict'
import { execFileSync } from 'node:child_process'
import { readFileSync } from 'node:fs'
import { dirname, resolve } from 'node:path'
import { performance } from 'node:perf_hooks'
import { build } from 'esbuild'
import { buildCounterbalancedSchedule } from './counterbalanced-benchmark-schedule.mjs'
const baseline = process.argv[2] ?? '20ab9950654'
const file = 'src/shared/plugins/plugin-panel-message-budget.ts'
async function load(contents) {
const result = await build({
stdin: { contents, loader: 'ts', resolveDir: dirname(resolve(file)) },
bundle: true,
platform: 'node',
format: 'esm',
write: false
})
return import(
`data:text/javascript;base64,${Buffer.from(result.outputFiles[0].text).toString('base64')}`
)
}
const before = await load(
execFileSync('git', ['show', `${baseline}:${file}`], { encoding: 'utf8' })
)
const after = await load(readFileSync(file, 'utf8'))
const results = []
for (const count of [5, 1000, 100000]) {
const entries = Array.from({ length: count }, (_, i) => [`key-${i}`, `value-${i}`])
for (const [kind, value] of [
['array', entries.map(([, value]) => value)],
['map', new Map(entries)],
['set', new Set(entries.map(([, value]) => value))],
['object', Object.fromEntries(entries)]
]) {
const input = structuredClone(value)
for (const cap of [0, 1, 64, 1024, 65536, Infinity]) {
assert.equal(
after.structuredCloneMessageBytes(input, cap),
before.structuredCloneMessageBytes(input, cap)
)
}
const arms = { before, after }
const iterations = count < 100 ? 1000 : 10
const run = (arm) => {
global.gc?.()
const start = performance.now()
const cpuStart = process.cpuUsage()
for (let i = 0; i < iterations; i++) {
arms[arm].structuredCloneMessageBytes(input)
}
const cpu = process.cpuUsage(cpuStart)
return {
ms: (performance.now() - start) / iterations,
cpuMs: (cpu.user + cpu.system) / 1000 / iterations
}
}
for (let i = 0; i < 3; i++) {
run('before')
run('after')
}
const samples = { before: [], after: [] }
for (const pair of buildCounterbalancedSchedule(10, 'before', 'after')) {
for (const arm of pair) {
samples[arm].push(run(arm))
}
}
const median = (values) => {
const sorted = [...values].sort((a, b) => a - b)
return (sorted[4] + sorted[5]) / 2
}
results.push({
count,
kind,
beforeMs: median(samples.before.map((sample) => sample.ms)),
beforeCpuMs: median(samples.before.map((sample) => sample.cpuMs)),
afterMs: median(samples.after.map((sample) => sample.ms)),
afterCpuMs: median(samples.after.map((sample) => sample.cpuMs)),
samples
})
}
}
console.log(
JSON.stringify(
{
baseline,
node: process.version,
platform: process.platform,
forcedGc: Boolean(global.gc),
results
},
null,
2
)
)