/** * dashboard-client/src/components/PerfChart.tsx — perf stat chart. * * The /api/perf endpoint returns rolling-window aggregates (not time-series), * so this renders a stat-card "chart": p50/p95 latency bars, TPS, cache hit %, * db recompute + disk write. Each metric shows a normalized bar + numeric. */ import type React from "react"; import type { PerfResponse } from "@contracts"; import { Card, CardContent, CardHeader, CardTitle } from "../components/ui/card"; export interface PerfChartProps { perf: PerfResponse; } function fmtMs(n: number): string { return n >= 1000 ? `${(n / 1000).toFixed(1)}s` : `${n.toFixed(0)}ms`; } interface BarProps { /** Current value. */ value: number; /** Value that represents 100% bar fill (the "max" reference). */ max: number; /** Color class. */ colorClass: string; } function Bar({ value, max, colorClass }: BarProps): React.ReactElement { const pct = max > 0 ? Math.max(0, Math.min(100, (value / max) * 100)) : 0; return (
); } export function PerfChart({ perf }: PerfChartProps): React.ReactElement { // Reference maxes: p95 is the upper bound for latency bars; rates scale to a // reasonable reference (tok/s) so bars are visually meaningful even with // small samples. cache_hit_pct is already 0-100. const latencyMax = Math.max( perf.turn_latency_ms.p95, perf.provider_latency_ms.p95, 1, ); const tpsRef = Math.max(perf.tps.avg, 1); return ( Performance {perf.windowMinutes}min window · {perf.sampleCount} samples
Turn latency p50 / p95 {fmtMs(perf.turn_latency_ms.p50)} /{" "} {fmtMs(perf.turn_latency_ms.p95)}
Provider latency p50 / p95 {fmtMs(perf.provider_latency_ms.p50)} /{" "} {fmtMs(perf.provider_latency_ms.p95)}
Tokens/sec (avg) {perf.tps.avg.toFixed(1)}
Cache hit (avg / latest) {perf.cache_hit_pct.avg.toFixed(1)}% /{" "} {perf.cache_hit_pct.latest.toFixed(1)}%
DB recompute p95 {fmtMs(perf.db_recompute_ms.p95)}
Disk write p95 {fmtMs(perf.disk_write_ms.p95)}
RSS {perf.rss_mb.latest.toFixed(0)} MB
Heap {perf.heap_mb.latest.toFixed(0)} MB
CPU user {(perf.cpu_user_ms.latest / 1000).toFixed(1)}s
CPU sys {(perf.cpu_sys_ms.latest / 1000).toFixed(1)}s
{perf.diag && (
Fast-gate fires: {perf.diag.ctxFastGate} Live trim fires: {perf.diag.liveTrimFires} Live trim replays: {perf.diag.liveTrimReplays}
)}
); }