mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-11-14 00:07:00 +01:00
28 lines
5.8 KiB
JavaScript
28 lines
5.8 KiB
JavaScript
'use strict';
|
||
const fs=require('node:fs'),path=require('node:path'),assert=require('node:assert/strict');
|
||
const input=process.argv[2]||'backend/reports/http-archive-benchmark.json';
|
||
const report=JSON.parse(fs.readFileSync(input,'utf8'));
|
||
const median=values=>[...values].sort((a,b)=>a-b)[Math.floor(values.length/2)];
|
||
const fixtures=[...new Set(report.results.map(r=>r.fixture))];
|
||
const rows=fixtures.map(fixture=>({fixture,...Object.fromEntries(['node','go'].map(runtime=>{
|
||
const samples=report.results.filter(r=>r.fixture===fixture&&r.runtime===runtime);
|
||
assert.ok(samples.length);
|
||
if(samples.some(r=>r.status==='failed'))return [runtime,{failure:samples.find(r=>r.status==='failed').failure}];
|
||
return [runtime,Object.fromEntries([1,8].map(concurrency=>{
|
||
const batches=samples.map(r=>r.warm.find(w=>w.concurrency===concurrency));assert.ok(batches.every(Boolean));
|
||
return [concurrency,Object.fromEntries(['p95Ms','requestsPerSecond','peakProcessTreeRssBytes','cpuMsPerRequest'].map(metric=>[metric,median(batches.map(w=>metric==='cpuMsPerRequest'?w.cpuMs/w.requests:w[metric]))]))];
|
||
}))];
|
||
}))}));
|
||
const data=JSON.stringify(rows).replaceAll('<','\\u003c');
|
||
const title='Node and Go: archive file requests';
|
||
const html=`<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${title}</title><style>
|
||
body{margin:0;background:transparent;color:var(--foreground,#242424);font:14px/1.5 var(--font-sans,system-ui,sans-serif)}h2{font-size:20px;margin:0 0 8px;font-weight:650}p{margin:8px 0;color:var(--muted-foreground,#68717d)}.controls{display:flex;gap:12px;flex-wrap:wrap;margin:18px 0}label{display:flex;flex-direction:column;gap:4px;font-size:12px}select{font:inherit;font-size:14px;padding:7px 9px;border:1px solid var(--border,#b8bdc6);border-radius:6px;background:var(--card,#fff);color:inherit}table{border-collapse:collapse;width:100%;table-layout:fixed}th,td{padding:12px 5px;border-bottom:1px solid var(--border,#d0d5dd);text-align:right;vertical-align:top;overflow-wrap:anywhere}th{font-size:12px;font-weight:600;color:var(--muted-foreground,#68717d)}th:first-child,td:first-child{text-align:left;width:35%;padding-left:0}th:last-child,td:last-child{padding-right:0}td{font-variant-numeric:tabular-nums}.failure{color:var(--destructive,#b4413b);font-size:12px}.note{font-size:12px;margin-top:14px}.limit{border-left:3px solid var(--border,#9aa2ad);padding-left:12px;margin-top:18px}footer{font-size:11px;color:var(--muted-foreground,#68717d);margin:16px 0 0}@media(max-width:440px){th,td{padding:10px 3px;font-size:12px}h2{font-size:18px}}
|
||
</style></head><body><h2>${title}</h2><p>Real server entrypoints, disposable MongoDB and Redis, synthetic archive originals. Every successful response was checked by SHA-256.</p><div class="controls"><label>Concurrent requests<select id="concurrency"><option value="8">8 warm requests</option><option value="1">1 warm request</option></select></label><label>Metric<select id="metric"><option value="p95Ms">p95 response time</option><option value="requestsPerSecond">Throughput</option><option value="peakProcessTreeRssBytes">Sampled peak RSS</option><option value="cpuMsPerRequest">CPU per request</option></select></label></div><table><thead><tr><th scope="col">Fixture</th><th scope="col">Node</th><th scope="col">Go</th><th scope="col">Go / Node</th></tr></thead><tbody id="rows"></tbody></table><p class="note" id="explanation"></p><p class="limit">Node returned HTTP 500 for the 2 MiB text fixture: its persisted term array could not be cloned into the worker. No speedup is assigned to that failed baseline.</p><p class="note">${report.method.quick?'Smoke run; 16 warm requests per batch.':'Three alternating-order rounds; 100 warm requests per batch.'} CPU includes worker processes and post-response view writes. RSS is sampled every 10 ms and excludes MongoDB, Redis and the load generator. Shared gzip caching, remote providers, S3 and startup are outside this workload.</p><footer>${report.node} · ${report.go} · ${report.hardware.cpu} · ${report.recordedAt}</footer><script>
|
||
const data=${data};const descriptions={p95Ms:'Lower is better. Values are medians of the per-round p95 latencies, not a pooled p95.',requestsPerSecond:'Higher is better. Values are medians of three per-round throughputs.',peakProcessTreeRssBytes:'Lower is better. Median of the sampled per-round process-tree peaks. Short-lived peaks can be missed.',cpuMsPerRequest:'Lower is better. Approximate server process-tree CPU per completed request, then median across rounds.'};
|
||
function render(){const metric=document.querySelector('#metric').value,c=document.querySelector('#concurrency').value,body=document.querySelector('#rows');body.replaceChildren();for(const row of data){const tr=document.createElement('tr');const name=document.createElement('td');name.textContent=row.fixture;tr.append(name);for(const runtime of ['node','go']){const td=document.createElement('td');if(row[runtime].failure){td.textContent='HTTP 500';td.className='failure'}else{let value=row[runtime][c][metric],unit=metric==='requestsPerSecond'?'req/s':'ms';if(metric==='peakProcessTreeRssBytes'){value/=1048576;unit='MiB'}td.textContent=value.toFixed(1)+' '+unit}tr.append(td)}const ratio=document.createElement('td');ratio.textContent=row.node.failure||row.go.failure?'—':(row.go[c][metric]/row.node[c][metric]).toFixed(2)+'×';tr.append(ratio);body.append(tr)}document.querySelector('#explanation').textContent=descriptions[metric]+' The last column divides Go by Node.'}
|
||
document.querySelectorAll('select').forEach(select=>select.addEventListener('change',render));render();console.log('Benchmark rows:',data.length);
|
||
</script></body></html>`;
|
||
const target=input.replace(/\.json$/,'.html');assert.notEqual(target,input);fs.writeFileSync(target,html);
|
||
console.log(target);
|
||
for(const row of rows)console.log(JSON.stringify(row));
|