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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ jobs:
/internal-explorer/bundles/0x1 /api/internal-explorer/blocks \
/tips /tips/block/0x1 /tips/bundles/0x1 /api/tips/blocks \
/benchmark /benchmark/run/latest /benchmark/run-comparison/1 \
/benchmark/load-tests/sepolia /scaling; do
/benchmark/load-tests/sepolia /scaling /scaling/da /scaling/guardrails /scaling/runs; do
code=$(curl -s -o /dev/null -w '%{http_code}' "http://localhost:3000${route}")
if [ "${code}" != "404" ]; then
echo "FAIL: ${route} returned ${code}, expected 404"
Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/components/BaseChart.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useRef, useEffect, useState } from "react";
import * as d3 from "d3";
import { MetricData } from "../types";
import { MetricData } from "../../scaling/runs/lib/types";

interface BaseChartProps {
data: MetricData[];
Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/components/BenchmarkToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useRouter, useSearchParams } from "next/navigation";

import { useLoadTestList, useTestMetadata } from "../utils/useDataSeries";
import { uniqBy } from "../utils/collections";
import { formatLoadTestTimestamp } from "../utils/formatters";
import { formatLoadTestTimestamp } from "../../scaling/runs/lib/formatters";
import { loadTestHref } from "../routes";
import Select from "./Select";

Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/components/ChartGrid.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import { SORTED_CHART_CONFIG } from "../metricDefinitions";
import { DataSeries } from "../types";
import { SORTED_CHART_CONFIG } from "../../scaling/runs/lib/metricDefinitions";
import { DataSeries } from "../../scaling/runs/lib/types";
import LineChart from "./LineChart";

interface ProvidedProps {
Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/components/ChartSelector.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
"use client";

import { useEffect, useMemo, useRef } from "react";
import { BenchmarkRuns } from "../types";
import { BenchmarkRuns } from "../../scaling/runs/lib/types";
import { deepEqual } from "../utils/collections";
import {
camelToTitleCase,
formatValue,
formatLabel,
} from "../utils/formatters";
} from "../../scaling/runs/lib/formatters";
import { interpolateWarm } from "d3";
import { useBenchmarkFilters } from "../hooks/useBenchmarkFilters";
import Link from "next/link";
Expand Down
5 changes: 3 additions & 2 deletions app/benchmark/components/ConfigCard.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { describe, expect, it } from "vitest";

import { buildRows, formatTransactions } from "./ConfigCard";
import { LoadTestConfig } from "../types";
import { buildRows } from "./ConfigCard";
import { formatTransactions } from "../../scaling/runs/lib/formatters";
import { LoadTestConfig } from "../../scaling/runs/lib/types";

describe("formatTransactions", () => {
it("formats a weighted transaction mix", () => {
Expand Down
28 changes: 2 additions & 26 deletions app/benchmark/components/ConfigCard.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { LoadTestConfig } from "../types";
import { formatEthFromWeiString } from "../utils/formatters";
import { LoadTestConfig } from "../../scaling/runs/lib/types";
import { formatEthFromWeiString, formatTransactions } from "../../scaling/runs/lib/formatters";
import StatCard from "./StatCard";

interface ConfigCardProps {
Expand All @@ -11,30 +11,6 @@ interface Row {
value: string;
}

const percent = (value: number): string => `${Math.round(value * 100)}%`;

export const formatTransactions = (
config: Pick<LoadTestConfig, "transactions" | "fresh_recipient_ratio">,
): string => {
const txs = config.transactions;
if (!txs || txs.length === 0) return "—";
const total = txs.reduce((acc, t) => acc + t.weight, 0);
if (total === 0) return txs.map((t) => t.type).join(" · ");

const freshRecipientRatio = config.fresh_recipient_ratio ?? 0;
return txs
.map((t) => {
if (t.type === "transfer" && freshRecipientRatio >= 1) {
return `account-create (${percent(t.weight / total)})`;
}
if (t.type === "transfer" && freshRecipientRatio > 0) {
return `${t.type} (${percent(t.weight / total)}, ${percent(freshRecipientRatio)} account-create)`;
}
return `${t.type} (${percent(t.weight / total)})`;
})
.join(" · ");
};

const formatTargetGps = (gps: number): string => {
if (gps >= 1e9) return `${(gps / 1e9).toFixed(1)}B gas/s`;
if (gps >= 1e6) return `${(gps / 1e6).toFixed(0)}M gas/s`;
Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/components/ConfigurationTags.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { formatValue, formatLabel } from "../utils/formatters";
import { camelToTitleCase } from "../utils/formatters";
import { formatValue, formatLabel } from "../../scaling/runs/lib/formatters";
import { camelToTitleCase } from "../../scaling/runs/lib/formatters";

interface ConfigurationTagsProps {
testConfig: Record<string, unknown>;
Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/components/LineChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ import React, {
useMemo,
} from "react";
import * as d3 from "d3";
import { DataSeries, MetricData, ChartConfig } from "../types";
import { DataSeries, MetricData, ChartConfig } from "../../scaling/runs/lib/types";
import BaseChart from "./BaseChart";
import { formatValue, formatLabel } from "../utils/formatters";
import { formatValue, formatLabel } from "../../scaling/runs/lib/formatters";
import calculateTooltipLayout from "../hooks/useTooltipLayout";
import useChartHoverSync, { ChartHoverEvent } from "../hooks/useChartHoverSync";
import { deepEqual } from "../utils/collections";
Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/components/MachineInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MachineInfo as MachineInfoType } from "../types";
import { MachineInfo as MachineInfoType } from "../../scaling/runs/lib/types";

interface MachineInfoProps {
machineInfo?: MachineInfoType;
Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/components/RunList.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { groupBy } from "../utils/collections";
import { useState } from "react";
import { formatValue, MetricValue } from "../utils/formatters";
import { formatValue, MetricValue } from "../../scaling/runs/lib/formatters";
import ThresholdDisplay from "../views/ThresholdDisplay";
import { BenchmarkRunWithStatus } from "../types";
import { BenchmarkRunWithStatus } from "../../scaling/runs/lib/types";
import StatusBadge from "./StatusBadge";
import StatusSummary from "./StatusSummary";
import ConfigurationTags from "./ConfigurationTags";
Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/components/RunListFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

import Link from "next/link";
import { useState } from "react";
import { camelToTitleCase, formatLabel } from "../utils/formatters";
import { camelToTitleCase, formatLabel } from "../../scaling/runs/lib/formatters";
import { FilterValue } from "../filter";
import { BenchmarkRunWithStatus } from "../types";
import { BenchmarkRunWithStatus } from "../../scaling/runs/lib/types";
import { downloadAllRuns, downloadAllRunsCSV } from "../utils/downloadUtils";
import Select from "./Select";
import FloatingDropdown from "./FloatingDropdown";
Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/components/ThroughputChart.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useRef, useState } from "react";
import * as d3 from "d3";
import { ThroughputSample } from "../types";
import { formatTps, formatGps } from "../utils/formatters";
import { ThroughputSample } from "../../scaling/runs/lib/types";
import { formatTps, formatGps } from "../../scaling/runs/lib/formatters";

interface ThroughputChartProps {
samples: ThroughputSample[];
Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/filter.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, it, expect } from "vitest";
import { getBenchmarkVariables } from "./filter";
import { BenchmarkRun } from "./types";
import { BenchmarkRun } from "../scaling/runs/lib/types";

// Sample data for testing - This data now aligns with the ActualBenchmarkRun type
const sampleRuns: BenchmarkRun[] = [
Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/hooks/useBenchmarkFilters.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useCallback, useMemo } from "react";
import { deepEqual } from "../utils/collections";
import { type BenchmarkRun } from "../types";
import { type BenchmarkRun } from "../../scaling/runs/lib/types";
import { useSearchParamsState } from "../utils/useSearchParamsState";
import { getBenchmarkVariables } from "../filter";
type FilterValue = string | number | boolean;
Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/utils/downloadUtils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BenchmarkRunWithStatus } from "../types";
import { BenchmarkRunWithStatus } from "../../scaling/runs/lib/types";

/**
* Downloads run information as a JSON file
Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/utils/useDataSeries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import {
LoadTestEntry,
LoadTestResult,
MetricData,
} from "../types";
} from "../../scaling/runs/lib/types";
import { useCallback } from "react";
import { getDataService } from "../services/dataService";
import { getDataService } from "../../scaling/runs/lib/dataService";

// Fetch metrics data using the configured data service
export const fetchMetrics = async (
Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/views/LoadTestAllRuns.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import Link from "next/link";
import { useLoadTestList } from "../utils/useDataSeries";
import { formatLoadTestTimestamp } from "../utils/formatters";
import { formatLoadTestTimestamp } from "../../scaling/runs/lib/formatters";
import { loadTestHref, loadTestsHref } from "../routes";

interface ProvidedProps {
Expand Down
4 changes: 2 additions & 2 deletions app/benchmark/views/LoadTestDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ import {
formatGpsVerbose,
formatLoadTestTimestamp,
formatTps,
} from "../utils/formatters";
} from "../../scaling/runs/lib/formatters";
import {
BlockRange,
FlashblocksLatencyStats,
LatencyStats,
LoadTestResult,
} from "../types";
} from "../../scaling/runs/lib/types";
import { LoadTestRunSelect } from "../components/BenchmarkToolbar";
import { loadTestAllHref } from "../routes";

Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/views/RunComparison.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import ChartSelector, {
} from "../components/ChartSelector";
import ChartGrid from "../components/ChartGrid";
import { useTestMetadata, useMultipleDataSeries } from "../utils/useDataSeries";
import { DataSeries } from "../types";
import { DataSeries } from "../../scaling/runs/lib/types";
import { BenchmarkRunSelect } from "../components/BenchmarkToolbar";
import DataSourceError from "../components/DataSourceError";
import { runComparisonHref } from "../routes";
Expand Down
2 changes: 1 addition & 1 deletion app/benchmark/views/RunIndex.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useTestMetadata } from "../utils/useDataSeries";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { getBenchmarkVariables } from "../filter";
import RunList from "../components/RunList";
import { BenchmarkRuns, getTestRunsWithStatus } from "../types";
import { BenchmarkRuns, getTestRunsWithStatus } from "../../scaling/runs/lib/types";
import { groupBy } from "../utils/collections";
import RunListFilter from "../components/RunListFilter";
import { BenchmarkRunSelect } from "../components/BenchmarkToolbar";
Expand Down
35 changes: 35 additions & 0 deletions app/scaling/[area]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { notFound } from 'next/navigation';

import { EmptyState } from '../../components/ui/EmptyState';
import { Text } from '../../components/ui/Text';
import { AREAS, CeilingCard } from '../components/CeilingCards';
import { SectionTable } from '../components/SectionTable';
import { Header, loadSnapshot, Unavailable } from '../loadSnapshot';

export const dynamic = 'force-dynamic';

export default async function ScalingAreaPage({ params }: { params: Promise<{ area: string }> }) {
const { area } = await params;
const entry = AREAS.find(([a]) => a === area);
if (!entry) notFound();
const loaded = await loadSnapshot();
if (loaded.kind !== 'ok') return <Unavailable loaded={loaded} />;

const { snapshot } = loaded;
const section = snapshot.sections.find((s) => s.id === area);
return (
<div className="flex flex-col gap-10 pb-8">
<Header loaded={loaded} title={`${entry[1]} · ${snapshot.network}`} crumb={entry[1]} />
<section className="flex flex-col gap-3">
<Text as="h2" variant="headline">Ceiling <span className="text-bds-gray-60">· Mgas/s</span></Text>
<CeilingCard area={entry[0]} ceilings={snapshot.ceilings} />
</section>
{section ? (
<SectionTable section={section} windows={snapshot.windows} />
) : (
<EmptyState title="No detailed metrics yet" description="This snapshot has no metrics for this area." />
)}
<EmptyState title="Related runs" description="Benchmark and load-test runs for this area land here later." />
</div>
);
}
48 changes: 48 additions & 0 deletions app/scaling/components/CeilingCards.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import Link from 'next/link';

import { Card } from '../../components/ui/Card';
import { Text } from '../../components/ui/Text';
import { deriveBinding, type Ceiling, type CeilingInput } from '../snapshot.mjs';
import { Info } from './Info';
import { Tag } from './Tag';

export const AREAS: [Ceiling['area'], string][] = [['da', 'DA'], ['execution', 'Execution'], ['state', 'State'], ['networking', 'Networking']];

function input({ name, value, unit, status, asOf }: CeilingInput): string {
const shown = value === null ? status : `${value} ${unit}`.trim();
return [name, shown, value === null ? null : status, asOf && new Date(asOf).toISOString().slice(0, 10)].filter(Boolean).join(' · ');
}

export function CeilingCards({ ceilings }: { ceilings: Ceiling[] }) {
return (
<section className="flex flex-col gap-3">
<Text as="h2" variant="headline">Ceilings by bottleneck <span className="text-bds-gray-60">· Mgas/s</span></Text>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-4">
{AREAS.map(([area]) => <CeilingCard key={area} area={area} ceilings={ceilings} />)}
</div>
</section>
);
}

export function CeilingCard({ area, ceilings }: { area: Ceiling['area']; ceilings: Ceiling[] }) {
const name = AREAS.find(([a]) => a === area)![1];
const c = ceilings.find((x) => x.area === area)!;
return (
<Card className="flex flex-col gap-2 bg-background p-4 text-[13px] dark:bg-white/5">
<span className="flex items-center gap-1">
<Link className="underline" href={`/scaling/${area}`}><Text as="span" variant="label">{name}</Text></Link>
<Info label={`About the ${name} ceiling`}>{c.help}</Info>
</span>
<span className="flex flex-wrap items-center gap-2">
<span className="font-mono text-[20px]">{c.value === null ? '—' : c.value.toLocaleString('en-US', { maximumFractionDigits: 2 })}</span>
<Tag tag={c.tag} />
{c === deriveBinding(ceilings) ? <span className="rounded-md bg-base-blue px-2 py-0.5 text-[12px] text-white">Binding</span> : null}
</span>
<code className="break-words font-mono text-[12px] text-bds-gray-60">{c.formula}</code>
{c.reason ? <p className="text-bds-gray-60">{c.reason}</p> : null}
<ul className="flex flex-col gap-0.5 text-[12px] text-bds-gray-60 empty:hidden">
{c.inputs.map((i) => <li key={i.name}>{input(i)}</li>)}
</ul>
</Card>
);
}
61 changes: 61 additions & 0 deletions app/scaling/components/Guardrails.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import Link from 'next/link';

import { cn } from '../../components/ui/cn';
import { Card } from '../../components/ui/Card';
import { Text } from '../../components/ui/Text';
import type { Guardrail } from '../snapshot.mjs';
import { Info } from './Info';
import { Tag } from './Tag';

const TH = 'px-4 py-2 text-left text-[12px] font-[500] text-bds-gray-60';
const TD = 'px-4 py-3 align-top';
const DOT: Record<Guardrail['status'], string> = { ok: 'bg-bds-green-50', breached: 'bg-bds-red-50', unknown: 'bg-bds-gray-30' };
const STATUS: Record<Guardrail['status'], string> = { ok: 'OK', breached: 'Breached', unknown: 'Unknown' };

const fmt = (n: number, unit: string) => `${n.toLocaleString('en-US', { maximumFractionDigits: 2 })} ${unit}`.trim();

export function Guardrails({ guardrails, detailed = false }: { guardrails: Guardrail[]; detailed?: boolean }) {
return (
<section className="flex flex-col gap-3">
{detailed ? null : <Text as="h2" variant="headline"><Link className="underline" href="/scaling/guardrails">Guardrails →</Link></Text>}
<Card className="overflow-x-auto bg-background dark:bg-white/5">
<table className="w-full border-collapse text-[13px]">
<thead>
<tr className="border-b border-bds-gray-10 dark:border-white/10">
<th className={TH}>Guardrail</th>
<th className={TH}>Value</th>
<th className={TH}>Threshold</th>
<th className={TH}>Status</th>
</tr>
</thead>
<tbody>
{guardrails.map((g) => (
<tr key={g.id} className="border-b border-bds-gray-10 last:border-0 dark:border-white/10">
<td className={TD}>
{detailed ? <>{g.label}<p className="text-bds-gray-60">{g.help}</p></> : (
<span className="flex items-center gap-1">{g.label} <Info label={`About ${g.label}`}>{g.help}</Info></span>
)}
</td>
<td className={cn(TD, 'whitespace-nowrap font-mono')}>{g.value === null ? '—' : fmt(g.value, g.unit)}</td>
<td className={TD}>
<span className="flex flex-wrap items-center gap-2">
<span className="whitespace-nowrap font-mono">{g.threshold === null ? '—' : `${g.comparator === '<=' ? '≤' : '≥'} ${fmt(g.threshold, g.unit)}`}</span>
{g.thresholdTag === 'set' ? null : <Tag tag={g.thresholdTag} />}
{g.owner ? <span className="text-bds-gray-60">{g.owner}</span> : null}
</span>
</td>
<td className={cn(TD, 'whitespace-nowrap')}>
<span className="flex items-center gap-2">
<span aria-hidden="true" className={cn('h-2 w-2 rounded-full', DOT[g.status])} />
{STATUS[g.status]}
</span>
</td>
</tr>
))}
</tbody>
</table>
</Card>
<Text variant="footnote" tone="muted">Breached SLOs are not attributed to saturation until triaged.</Text>
</section>
);
}
Loading
Loading