Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/app/benchmarks/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,11 @@ export default async function BenchmarkPage({
(r) => r.value === "all" || regionsWithData.has(r.value),
);
const kindOptions = aggregate.dimensions?.kind ?? [];
const venueOptions = aggregate.dimensions?.venue ?? [];
const chain = chainOptions[0]?.value ?? null;
const region = regionOptions[0]?.value ?? null;
const kind = kindOptions[0]?.value ?? null;
const venue = venueOptions[0]?.value ?? null;

// Variants (chain × region × kind) are NOT embedded anymore. The old
// pre-fetch awaited every variant (rpc-capabilities: 39 full provider
Expand Down Expand Up @@ -524,9 +526,11 @@ export default async function BenchmarkPage({
chainOptions={chainOptions}
regionOptions={regionOptions}
kindOptions={kindOptions}
venueOptions={venueOptions}
initialChain={chain ?? null}
initialRegion={region ?? null}
initialKind={kind ?? null}
initialVenue={venue ?? null}
hasLongHistory={benchmark.slug === "hyperliquid-frontends"}
/>
</Suspense>
Expand Down
70 changes: 51 additions & 19 deletions src/components/benchmark-body.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,9 @@ function variantKey(
chain: string | null,
region: string | null,
kind: string | null,
venue: string | null = null,
): string {
return `${chain ?? "__none"}|${region ?? "__none"}|${kind ?? "__none"}`;
return `${chain ?? "__none"}|${region ?? "__none"}|${kind ?? "__none"}|${venue ?? "__none"}`;
}

/** Region values that appear in extras.seriesByRegion24h. Used when the
Expand Down Expand Up @@ -152,18 +153,22 @@ export function BenchmarkBody({
chainOptions,
regionOptions,
kindOptions = [],
venueOptions = [],
initialChain,
initialRegion,
initialKind = null,
initialVenue = null,
hasLongHistory = false,
}: {
variants: Record<string, Benchmark>;
chainOptions: ChainOption[];
regionOptions: ChainOption[];
kindOptions?: ChainOption[];
venueOptions?: ChainOption[];
initialChain: string | null;
initialRegion: string | null;
initialKind?: string | null;
initialVenue?: string | null;
/** When true, render the long-window archive toggle (24h..All time)
* below the main ledger. Only set on benches whose harness ships a
* long-window archive blob (currently: hyperliquid-frontends). */
Expand All @@ -178,6 +183,7 @@ export function BenchmarkBody({
const urlChain = searchParams.get("chain");
const urlRegion = searchParams.get("region");
const urlKind = searchParams.get("kind");
const urlVenue = searchParams.get("venue");
const urlLayer = searchParams.get("layer");
// Canonical-aware lookup: a URL with the new slug ("?chain=gram")
// still selects the dimension whose YAML value is the legacy "ton".
Expand All @@ -189,34 +195,40 @@ export function BenchmarkBody({
(urlRegion && regionOptions.find((r) => r.value === urlRegion)?.value) ?? initialRegion;
const resolvedInitialKind =
(urlKind && kindOptions.find((k) => k.value === urlKind)?.value) ?? initialKind;
const resolvedInitialVenue =
(urlVenue && venueOptions.find((v) => v.value === urlVenue)?.value) ?? initialVenue;
const resolvedInitialLayer: ProviderLayer =
urlLayer === "l2" ? "l2" : "l1";

const [chain, setChain] = useState<string | null>(resolvedInitialChain);
const [region, setRegion] = useState<string | null>(resolvedInitialRegion);
const [kind, setKind] = useState<string | null>(resolvedInitialKind);
const [venue, setVenue] = useState<string | null>(resolvedInitialVenue);
const [layer, setLayer] = useState<ProviderLayer>(resolvedInitialLayer);

useEffect(() => {
const url = new URL(window.location.href);
syncParam(url, "chain", chain, chainOptions);
syncParam(url, "region", region, regionOptions);
syncParam(url, "kind", kind, kindOptions);
syncParam(url, "venue", venue, venueOptions);
// Layer param: drop when default ("l1"), keep when user picked l2.
if (layer === "l1") url.searchParams.delete("layer");
else url.searchParams.set("layer", layer);
const next = url.pathname + (url.search ? url.search : "");
if (next !== window.location.pathname + window.location.search) {
window.history.replaceState(null, "", next);
}
}, [chain, region, kind, layer, chainOptions, regionOptions, kindOptions]);
}, [chain, region, kind, venue, layer, chainOptions, regionOptions, kindOptions, venueOptions]);

const fallbackChain = chainOptions[0]?.value ?? null;
const fallbackRegion = regionOptions[0]?.value ?? null;
const fallbackKind = kindOptions[0]?.value ?? null;
const fallbackVenue = venueOptions[0]?.value ?? null;
const effectiveChain = chainOptions.length > 0 ? (chain ?? fallbackChain) : null;
const effectiveRegion = regionOptions.length > 0 ? (region ?? fallbackRegion) : null;
const effectiveKind = kindOptions.length > 0 ? (kind ?? fallbackKind) : null;
const effectiveVenue = venueOptions.length > 0 ? (venue ?? fallbackVenue) : null;

// The page ships ONLY the aggregate view (embedding every variant made
// ISR regenerations take 30-60 s). Filtered variants are fetched here
Expand All @@ -225,13 +237,14 @@ export function BenchmarkBody({
// tab still works, numbers stay cross-dimension) and may retry on the
// next flip.
const [variantMap, setVariantMap] = useState<Record<string, Benchmark>>(variants);
const activeKey = variantKey(effectiveChain, effectiveRegion, effectiveKind);
const activeKey = variantKey(effectiveChain, effectiveRegion, effectiveKind, effectiveVenue);
const aggregateBench =
variants[variantKey(null, null, null)] ?? Object.values(variants)[0];
variants[variantKey(null, null, null, null)] ?? Object.values(variants)[0];
const isAllSelection =
(!effectiveChain || effectiveChain === "all") &&
(!effectiveRegion || effectiveRegion === "all") &&
(!effectiveKind || effectiveKind === "all");
(!effectiveKind || effectiveKind === "all") &&
(!effectiveVenue || effectiveVenue === "all");
useEffect(() => {
if (variantMap[activeKey] || !aggregateBench) return;
// The all/all/all selection IS the aggregate: derived at render time,
Expand All @@ -242,6 +255,7 @@ export function BenchmarkBody({
if (!isAll(effectiveChain)) qs.set("chain", effectiveChain!);
if (!isAll(effectiveRegion)) qs.set("region", effectiveRegion!);
if (!isAll(effectiveKind)) qs.set("kind", effectiveKind!);
if (!isAll(effectiveVenue)) qs.set("venue", effectiveVenue!);
let cancelled = false;
fetch(`/api/bench/${aggregateBench.slug}/variant?${qs.toString()}`)
.then((r) => (r.ok ? r.json() : null))
Expand All @@ -267,25 +281,24 @@ export function BenchmarkBody({
useEffect(() => {
if (!aggregateBench) return;
const isAll = (v: string | null) => !v || v === "all";
const combos: [string | null, string | null, string | null][] = [
...chainOptions.map(
(c) => [c.value, effectiveRegion, effectiveKind] as [string | null, string | null, string | null],
),
...regionOptions.map(
(r) => [effectiveChain, r.value, effectiveKind] as [string | null, string | null, string | null],
),
type Combo = [string | null, string | null, string | null, string | null];
const combos: Combo[] = [
...chainOptions.map((c) => [c.value, effectiveRegion, effectiveKind, effectiveVenue] as Combo),
...regionOptions.map((r) => [effectiveChain, r.value, effectiveKind, effectiveVenue] as Combo),
...venueOptions.map((v) => [effectiveChain, effectiveRegion, effectiveKind, v.value] as Combo),
];
let cancelled = false;
const timers: ReturnType<typeof setTimeout>[] = [];
let i = 0;
for (const [c, r, k] of combos) {
if (isAll(c) && isAll(r) && isAll(k)) continue;
const key = variantKey(c, r, k);
for (const [c, r, k, vn] of combos) {
if (isAll(c) && isAll(r) && isAll(k) && isAll(vn)) continue;
const key = variantKey(c, r, k, vn);
if (variantMap[key]) continue;
const qs = new URLSearchParams();
if (!isAll(c)) qs.set("chain", c!);
if (!isAll(r)) qs.set("region", r!);
if (!isAll(k)) qs.set("kind", k!);
if (!isAll(vn)) qs.set("venue", vn!);
timers.push(
setTimeout(() => {
if (cancelled) return;
Expand Down Expand Up @@ -528,7 +541,8 @@ export function BenchmarkBody({
{(hasLayerSplit ||
chainOptions.length > 0 ||
regionOptions.length > 0 ||
kindOptions.length > 0) && (
kindOptions.length > 0 ||
venueOptions.length > 0) && (
<div className="mt-8 space-y-3">
{hasLayerSplit && (
<DimensionRow
Expand All @@ -541,6 +555,24 @@ export function BenchmarkBody({
onSelect={(v) => setLayer(v as ProviderLayer)}
/>
)}
{venueOptions.length > 0 && (
<DimensionRow
label="Venue"
options={venueOptions}
selected={venue ?? fallbackVenue}
onSelect={setVenue}
metaByValue={Object.fromEntries(
venueOptions
.map((o) => [
o.value,
summarize(
variantMap[variantKey(effectiveChain, effectiveRegion, effectiveKind, o.value)],
),
])
.filter(([, v]) => v !== null) as [string, ChainMeta][]
)}
/>
)}
{kindOptions.length > 0 && (
<DimensionRow
label="Kind"
Expand All @@ -552,7 +584,7 @@ export function BenchmarkBody({
.map((o) => [
o.value,
summarize(
variantMap[variantKey(effectiveChain, effectiveRegion, o.value)],
variantMap[variantKey(effectiveChain, effectiveRegion, o.value, effectiveVenue)],
),
])
.filter(([, v]) => v !== null) as [string, ChainMeta][]
Expand All @@ -569,7 +601,7 @@ export function BenchmarkBody({
chainOptions
.map((o) => [
o.value,
summarize(variantMap[variantKey(o.value, effectiveRegion, effectiveKind)]),
summarize(variantMap[variantKey(o.value, effectiveRegion, effectiveKind, effectiveVenue)]),
])
.filter(([, v]) => v !== null) as [string, ChainMeta][]
)}
Expand All @@ -585,7 +617,7 @@ export function BenchmarkBody({
regionOptions
.map((o) => [
o.value,
summarize(variantMap[variantKey(effectiveChain, o.value, effectiveKind)]),
summarize(variantMap[variantKey(effectiveChain, o.value, effectiveKind, effectiveVenue)]),
])
.filter(([, v]) => v !== null) as [string, ChainMeta][]
)}
Expand Down
1 change: 1 addition & 0 deletions src/types/benchmark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ export type Benchmark = {
chain?: { value: string; label: string }[];
region?: { value: string; label: string }[];
kind?: { value: string; label: string }[];
venue?: { value: string; label: string }[];
};
category: "Aggregators" | "Bridges" | "Blockchains" | "Trading" | "Wallets" | "RPCs" | "NFT APIs" | "Explorers";
results: ProviderResult[];
Expand Down
Loading