Files
Karti Tripathi 006feee0f7
CI / verify (push) Successful in 24s
CI / deploy (push) Failing after 1m14s
Lumbridge Bench
2026-08-04 00:44:07 -07:00

135 lines
3.9 KiB
TypeScript

import type { PerfPoint } from "@/lib/results";
/**
* Aggregate throughput plotted against concurrency, drawn as a scope sweep.
*
* The x axis is logarithmic because concurrency is sampled in octaves
* (1, 8, 32). On a linear axis the low-concurrency points — the ones that
* describe what a single user actually feels — collapse against the origin
* and the most important part of the curve becomes unreadable.
*/
export function ScopeTrace({
points,
width = 520,
height = 150,
showAxis = true,
}: {
points: PerfPoint[];
width?: number;
height?: number;
showAxis?: boolean;
}) {
if (points.length < 2) return null;
const pad = { top: 14, right: 14, bottom: showAxis ? 22 : 10, left: showAxis ? 46 : 10 };
const w = width - pad.left - pad.right;
const h = height - pad.top - pad.bottom;
const xs = points.map((p) => Math.log2(Math.max(1, p.concurrency)));
const ys = points.map((p) => p.output_tps_total);
const xMax = Math.max(...xs) || 1;
const yMax = Math.max(...ys) * 1.15;
const px = (i: number) => pad.left + (xs[i] / xMax) * w;
const py = (v: number) => pad.top + h - (v / yMax) * h;
const path = points.map((p, i) => `${i === 0 ? "M" : "L"}${px(i)},${py(p.output_tps_total)}`).join(" ");
const area = `${path} L${px(points.length - 1)},${pad.top + h} L${px(0)},${pad.top + h} Z`;
// Rough path length so the draw-on animation has a dash offset to work with.
const traceLen = Math.round(w * 1.6);
const gridLines = [0, 0.25, 0.5, 0.75, 1];
return (
<svg
viewBox={`0 0 ${width} ${height}`}
className="w-full"
role="img"
aria-label="Aggregate throughput against concurrency"
>
<defs>
<linearGradient id="trace-fill" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="var(--color-signal)" stopOpacity="0.22" />
<stop offset="100%" stopColor="var(--color-signal)" stopOpacity="0" />
</linearGradient>
</defs>
{gridLines.map((g) => (
<line
key={g}
x1={pad.left}
x2={pad.left + w}
y1={pad.top + h - g * h}
y2={pad.top + h - g * h}
stroke="var(--color-rule)"
strokeWidth="1"
/>
))}
{showAxis &&
gridLines
.filter((g) => g > 0)
.map((g) => (
<text
key={`l${g}`}
x={pad.left - 8}
y={pad.top + h - g * h + 3}
textAnchor="end"
className="fill-[var(--color-dimmer)]"
style={{ fontSize: 9, fontFamily: "var(--font-mono)" }}
>
{Math.round(yMax * g)}
</text>
))}
<path d={area} fill="url(#trace-fill)" />
<path
d={path}
fill="none"
stroke="var(--color-signal)"
strokeWidth="1.75"
strokeLinejoin="round"
strokeLinecap="round"
className="trace"
style={{ ["--trace-len" as string]: traceLen }}
/>
{points.map((p, i) => (
<g key={p.concurrency}>
<circle
cx={px(i)}
cy={py(p.output_tps_total)}
r="3"
fill="var(--color-void)"
stroke="var(--color-signal)"
strokeWidth="1.5"
/>
{showAxis && (
<text
x={px(i)}
y={height - 6}
textAnchor="middle"
className="fill-[var(--color-dimmer)]"
style={{ fontSize: 9, fontFamily: "var(--font-mono)" }}
>
{p.concurrency}
</text>
)}
</g>
))}
{showAxis && (
<text
x={pad.left}
y={11}
className="fill-[var(--color-dimmer)]"
style={{ fontSize: 9, letterSpacing: "0.14em", fontFamily: "var(--font-mono)" }}
>
TOK/S AGGREGATE / CONCURRENCY
</text>
)}
</svg>
);
}