From b18a7a3ee8543ecfb5e7791a6aa427ad3400c25d Mon Sep 17 00:00:00 2001 From: Erhnysr Date: Tue, 19 May 2026 23:44:17 +0300 Subject: [PATCH] feat(report): group metrics by category in chart grid Closes #125 Adds metric grouping to the RunComparison chart grid. Metrics are now displayed under section headers instead of a flat list: - Latency: send_txs, update_fork_choice, get_payload, new_payload - Chain: inserts, account/storage reads/updates/commits, execution, validation, write, snapshot, triedb - Throughput: transactions/per_block, gas/per_block Changes: - Add optional group field to ChartConfig type - Annotate all metrics in CHART_CONFIG with their group - Refactor ChartGrid to group visible charts by category and render section headers between groups - Add CSS for .metric-group, .metric-group-title, .metric-group-charts --- report/src/components/ChartGrid.tsx | 78 +++++++++++++++++++---------- report/src/index.css | 20 ++++++++ report/src/metricDefinitions.ts | 17 +++++++ report/src/types.ts | 1 + 4 files changed, 89 insertions(+), 27 deletions(-) diff --git a/report/src/components/ChartGrid.tsx b/report/src/components/ChartGrid.tsx index bd525329..1c935df1 100644 --- a/report/src/components/ChartGrid.tsx +++ b/report/src/components/ChartGrid.tsx @@ -23,37 +23,61 @@ function resolveMetricKey( return primaryKey; } +const GROUP_ORDER = ["Latency", "Chain", "Throughput"]; + const ChartGrid: React.FC = ({ data, role }: ProvidedProps) => { + const chartData = data.flatMap((s) => s.data); + const thresholds = data[0]?.thresholds; + + const visibleCharts = SORTED_CHART_CONFIG.flatMap(([metricKey, config]) => { + const resolvedKey = resolveMetricKey(data, metricKey, config.aliases); + const executionMetrics = chartData + .map((d) => d.ExecutionMetrics[resolvedKey]) + .filter((v) => v !== undefined); + if (executionMetrics.length === 0) return []; + return [{ metricKey, resolvedKey, config }]; + }); + + const grouped = visibleCharts.reduce>( + (acc, item) => { + const group = item.config.group ?? "Other"; + if (!acc[group]) acc[group] = []; + acc[group].push(item); + return acc; + }, + {}, + ); + + const groupKeys = [ + ...GROUP_ORDER.filter((g) => grouped[g]), + ...Object.keys(grouped).filter((g) => !GROUP_ORDER.includes(g)), + ]; + return (
- {SORTED_CHART_CONFIG.map(([metricKey, config]) => { - const resolvedKey = resolveMetricKey(data, metricKey, config.aliases); - const thresholdKey = role ? `${role}/${metricKey}` : null; - const chartData = data.flatMap((s) => s.data); - const thresholds = data[0]?.thresholds; - const executionMetrics = chartData - .map((d) => d.ExecutionMetrics[resolvedKey]) - .filter((v) => v !== undefined); - - if (executionMetrics.length === 0) { - return null; - } - - const chartProps = { - series: data, - metricKey: resolvedKey, - title: config.title, - description: config.description, - unit: config.unit, - thresholds, - }; - - return ( -
- + {groupKeys.map((group) => ( +
+

{group}

+
+ {grouped[group].map(({ metricKey, resolvedKey, config }) => { + const thresholdKey = role ? `${role}/${metricKey}` : null; + return ( +
+ +
+ ); + })}
- ); - })} +
+ ))}
); }; diff --git a/report/src/index.css b/report/src/index.css index 904c229c..98c72d03 100644 --- a/report/src/index.css +++ b/report/src/index.css @@ -82,3 +82,23 @@ body { .filter-select { @apply p-2 rounded border border-gray-300 mt-1 bg-white; } + +/* Metric grouping */ +.metric-group { + margin-bottom: 2rem; +} + +.metric-group-title { + font-size: 1.25rem; + font-weight: 600; + color: #374151; + padding: 0.5rem 0; + margin-bottom: 1rem; + border-bottom: 2px solid #e5e7eb; +} + +.metric-group-charts { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(480px, 1fr)); + gap: 1rem; +} diff --git a/report/src/metricDefinitions.ts b/report/src/metricDefinitions.ts index 58085ebd..c08bc45a 100644 --- a/report/src/metricDefinitions.ts +++ b/report/src/metricDefinitions.ts @@ -2,30 +2,35 @@ import { ChartConfig } from "./types"; // Import from types.ts export const CHART_CONFIG = { "latency/send_txs": { type: "line", + group: "Latency", title: "Send Txs", description: "Shows the median time taken for send txs", unit: "ns", }, "latency/update_fork_choice": { type: "line", + group: "Latency", title: "Update Fork Choice", description: "Shows the median time taken for update fork choice", unit: "ns", }, "latency/get_payload": { type: "line", + group: "Latency", title: "Get Payload", description: "Shows the median time taken for get payload", unit: "ns", }, "latency/new_payload": { type: "line", + group: "Latency", title: "New Payload", description: "Shows the median time taken for new payload", unit: "ns", }, "chain/inserts.50-percentile": { type: "line", + group: "Chain", title: "Inserts", description: "Shows the median time taken for block processing and insertion (end-to-end)", @@ -41,6 +46,7 @@ export const CHART_CONFIG = { }, "chain/storage/reads.50-percentile": { type: "line", + group: "Chain", title: "Storage Reads", description: "Shows the median time taken for storage reads during block processing", @@ -56,6 +62,7 @@ export const CHART_CONFIG = { }, "chain/account/updates.50-percentile": { type: "line", + group: "Chain", title: "Account Updates", description: "Shows the median time taken for updating accounts during state validation", @@ -63,6 +70,7 @@ export const CHART_CONFIG = { }, "chain/account/hashes.50-percentile": { type: "line", + group: "Chain", title: "Account Hashes", description: "Shows the median time taken for hashing accounts during state validation", @@ -70,6 +78,7 @@ export const CHART_CONFIG = { }, "chain/storage/updates.50-percentile": { type: "line", + group: "Chain", title: "Storage Updates", // Renamed from 'Storage Writes' for consistency description: "Shows the median time taken for updating storage during state validation", @@ -77,6 +86,7 @@ export const CHART_CONFIG = { }, "chain/validation.50-percentile": { type: "line", + group: "Chain", title: "Validation (Misc)", description: "Shows the median time taken for miscellaneous block validation steps", @@ -92,6 +102,7 @@ export const CHART_CONFIG = { }, "chain/write.50-percentile": { type: "line", + group: "Chain", title: "Write (Misc)", description: "Shows the median time taken for miscellaneous block write operations (excluding commits)", @@ -99,6 +110,7 @@ export const CHART_CONFIG = { }, "chain/account/commits.50-percentile": { type: "line", + group: "Chain", title: "Account Commits", description: "Shows the median time taken for committing account changes to the DB", @@ -106,6 +118,7 @@ export const CHART_CONFIG = { }, "chain/storage/commits.50-percentile": { type: "line", + group: "Chain", title: "Storage Commits", description: "Shows the median time taken for committing storage changes to the DB", @@ -113,6 +126,7 @@ export const CHART_CONFIG = { }, "chain/snapshot/commits.50-percentile": { type: "line", + group: "Chain", title: "Snapshot Commits", description: "Shows the median time taken for committing snapshot changes to the DB", @@ -120,18 +134,21 @@ export const CHART_CONFIG = { }, "chain/triedb/commits.50-percentile": { type: "line", + group: "Chain", title: "TrieDB Commits", description: "Shows the median time taken for committing TrieDB changes", unit: "ns", }, "transactions/per_block": { type: "line", + group: "Throughput", title: "Transactions per Block", description: "Shows the number of transactions per block", unit: "count", }, "gas/per_block": { type: "line", + group: "Throughput", title: "Gas Per Block", description: "Shows the median gas per block", unit: "gas", diff --git a/report/src/types.ts b/report/src/types.ts index 321ad631..231d04dc 100644 --- a/report/src/types.ts +++ b/report/src/types.ts @@ -40,6 +40,7 @@ export interface ChartConfig { title: string; description: string; type: "line"; + group?: "Latency" | "Chain" | "Throughput"; unit?: | "ns" | "us"