From d2f01ef643de238fb05f50793f078d128bec05f9 Mon Sep 17 00:00:00 2001 From: Florent Tapponnier Date: Thu, 28 May 2026 17:27:00 +0200 Subject: [PATCH] fix(distribution): auto log scale when dynamic range > 50x The distribution view used a linear scale anchored at max(p99). On benches with very wide ranges (l1-finality spans 0.4s on TON to 36 min on Monero, ratio 5370x) every fast row collapsed to a single invisible pixel at the left edge, making 7 of 9 chains visually indistinguishable. Only the two slowest rows had visible bars. Port the same auto-log heuristic ranked-bar-chart already uses: when max/min > 50, switch to base-10 log projection so each row gets a proportional, distinguishable position. Footer flags 'log scale' so the reader knows when it kicks in. Same component is shared by every bench in distribution view, so this fixes l1-finality, l2-block-time, validator-yield, perp-fees and any other bench with wide dynamic range in one shot. --- src/components/distribution-chart.tsx | 29 +++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/components/distribution-chart.tsx b/src/components/distribution-chart.tsx index e4a6020a..39e671be 100644 --- a/src/components/distribution-chart.tsx +++ b/src/components/distribution-chart.tsx @@ -57,10 +57,29 @@ export function DistributionChart({ ); // Field scale recomputes from visible rows only - excluding an outlier - // gives the remaining rows the full track width. + // gives the remaining rows the full track width. We take both extremes + // because the auto-log switch needs the dynamic range, not just the max. const visible = sorted.filter((r) => !excluded.has(r.slug)); const fieldMax = Math.max(...visible.map((r) => r.ms.p99), 1); - const scale = (v: number) => Math.max(0, Math.min(100, (v / fieldMax) * 100)); + const fieldMin = Math.min( + ...visible.flatMap((r) => [r.ms.p50, r.ms.p90, r.ms.p99]).filter((v) => v > 0), + fieldMax, + ); + + // Use log scale when dynamic range > 50x. Same threshold as + // ranked-bar-chart for consistency. Critical on benches like l1-finality + // where TON (0.4 s) coexists with Monero (36 min): a linear scale + // collapses every sub-second chain into the same invisible pixel at the + // left, making 8 of 9 rows visually indistinguishable. + const useLog = fieldMax / Math.max(fieldMin, 1) > 50; + + const scale = (v: number) => { + if (v <= 0) return 0; + if (!useLog) return Math.max(0, Math.min(100, (v / fieldMax) * 100)); + const lo = Math.log10(Math.max(1, fieldMin / 2)); + const hi = Math.log10(fieldMax); + return Math.max(0, Math.min(100, ((Math.log10(v) - lo) / (hi - lo)) * 100)); + }; return (
@@ -181,8 +200,10 @@ export function DistributionChart({ })}
- 0 - max {fmtUnit(fieldMax, unit)} + {useLog ? `min ${fmtUnit(fieldMin, unit)}` : "0"} + + {useLog ? "log scale ยท " : ""}max {fmtUnit(fieldMax, unit)} +
);