mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 14:35:41 +00:00
2224ddbe78
* feat(perf): add on-demand (ui) throughput to cover pipeline cpm Cover cpm previously measured only the native backfill (lib) via the cover:library-progress done delta. Add a parallel UI series: every completed on-demand Rust cover ensure (grid / now-playing) records a timestamp, surfaced as a covers-per-minute rate. Both are exposed in the live cover diag, shown as separate Backfill (lib) / On-demand (ui) cards in the Monitor tab (each pinnable to the overlay) and as lib/ui rows in the Cover pipeline overlay block. * docs(changelog): note cover on-demand (ui) throughput (PR #947) Add CHANGELOG entry and credits line for the UI cover cpm metric. * fix(perf): source on-demand (ui) cpm from backend produced-cover count The JS ensure-queue counter never tracked: produced covers return hit:true (only misses/errors are hit:false), and ensure-queue dedup/HMR made client counting unreliable. Count on-demand covers natively in ensure_inner on the produce path (non-bulk, past the cache-hit gate), expose a cumulative uiEnsuredTotal in the pipeline stats, and derive the per-minute rate on the frontend from polled deltas — mirroring the lib backfill series. * perf(cover): measure cpm over trailing 5s instead of full minute A 60s rolling average added too much inertia, flattening real bursts and stalls in both the lib backfill and on-demand (ui) cover throughput. Compute the rate from the trailing 5s of samples (still extrapolated to per-minute), so the figure reacts promptly and decays to 0 within the window when idle.
120 lines
3.8 KiB
TypeScript
120 lines
3.8 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { acquirePerfLivePoll, patchPerfLiveAnalysis } from '../utils/perf/perfLiveStore';
|
|
import { setPerfProbeTelemetryActive } from '../utils/perf/perfTelemetry';
|
|
import { useAnalysisPerfLast } from '../utils/perf/analysisPerfStore';
|
|
import { useAnalysisPerfListener } from './useAnalysisPerfListener';
|
|
import { useCoverPerfListener, useCoverUiThroughputPoll } from './useCoverPerfListener';
|
|
import {
|
|
getPerfProbeFlags,
|
|
subscribePerfProbeFlags,
|
|
} from '../utils/perf/perfFlags';
|
|
import { hasAnyLiveMetricPollNeed, usePerfLiveOverlayPins } from '../utils/perf/perfOverlayPins';
|
|
import { useSyncExternalStore } from 'react';
|
|
|
|
interface Result {
|
|
perfProbeOpen: boolean;
|
|
setPerfProbeOpen: (open: boolean) => void;
|
|
}
|
|
|
|
function useNeedAnalysisTelemetry(perfProbeOpen: boolean, livePins: ReadonlySet<string>): boolean {
|
|
return useSyncExternalStore(
|
|
subscribePerfProbeFlags,
|
|
() => {
|
|
const flags = getPerfProbeFlags();
|
|
return (
|
|
perfProbeOpen
|
|
|| flags.showAnalysisPerfOverlay
|
|
|| livePins.has('analysis:tpm')
|
|
|| livePins.has('analysis:last')
|
|
);
|
|
},
|
|
() => perfProbeOpen,
|
|
);
|
|
}
|
|
|
|
function useNeedCoverTelemetry(perfProbeOpen: boolean, livePins: ReadonlySet<string>): boolean {
|
|
return useSyncExternalStore(
|
|
subscribePerfProbeFlags,
|
|
() => (
|
|
perfProbeOpen
|
|
|| getPerfProbeFlags().showCoverPerfOverlay
|
|
|| livePins.has('cover:cpm')
|
|
|| livePins.has('cover:cpm:ui')
|
|
),
|
|
() => perfProbeOpen,
|
|
);
|
|
}
|
|
|
|
/** Wires Ctrl+Shift+D probe modal and shared live metric polling. */
|
|
export function useSidebarPerfProbe(): Result {
|
|
const [perfProbeOpen, setPerfProbeOpen] = useState(false);
|
|
const livePins = usePerfLiveOverlayPins();
|
|
const analysisLast = useAnalysisPerfLast();
|
|
const needAnalysis = useNeedAnalysisTelemetry(perfProbeOpen, livePins);
|
|
const needCover = useNeedCoverTelemetry(perfProbeOpen, livePins);
|
|
|
|
useAnalysisPerfListener(needAnalysis);
|
|
useCoverPerfListener(needCover);
|
|
useCoverUiThroughputPoll(needCover);
|
|
|
|
useEffect(() => {
|
|
setPerfProbeTelemetryActive(perfProbeOpen);
|
|
return () => setPerfProbeTelemetryActive(false);
|
|
}, [perfProbeOpen]);
|
|
|
|
useEffect(() => {
|
|
if (!perfProbeOpen) return;
|
|
const onKey = (e: KeyboardEvent) => {
|
|
if (e.key === 'Escape') setPerfProbeOpen(false);
|
|
};
|
|
window.addEventListener('keydown', onKey);
|
|
return () => window.removeEventListener('keydown', onKey);
|
|
}, [perfProbeOpen]);
|
|
|
|
useEffect(() => {
|
|
const releases: Array<() => void> = [];
|
|
if (perfProbeOpen) releases.push(acquirePerfLivePoll('modal'));
|
|
if (hasAnyLiveMetricPollNeed()) releases.push(acquirePerfLivePoll('overlay-pins'));
|
|
if (releases.length === 0) return;
|
|
return () => releases.forEach(release => release());
|
|
}, [perfProbeOpen, livePins.size]);
|
|
|
|
useEffect(() => {
|
|
patchPerfLiveAnalysis({
|
|
lastTotalMs: analysisLast?.totalMs ?? null,
|
|
lastFetchMs: analysisLast?.fetchMs ?? null,
|
|
lastSeedMs: analysisLast?.seedMs ?? null,
|
|
lastBpmMs: analysisLast?.bpmMs ?? null,
|
|
});
|
|
}, [
|
|
analysisLast?.at,
|
|
analysisLast?.totalMs,
|
|
analysisLast?.fetchMs,
|
|
analysisLast?.seedMs,
|
|
analysisLast?.bpmMs,
|
|
]);
|
|
|
|
useEffect(() => {
|
|
const onKey = (e: KeyboardEvent) => {
|
|
if (!(e.ctrlKey && e.shiftKey && !e.altKey && !e.metaKey)) return;
|
|
if (e.key.toLowerCase() !== 'd') return;
|
|
const target = e.target as HTMLElement | null;
|
|
if (target && (
|
|
target.tagName === 'INPUT'
|
|
|| target.tagName === 'TEXTAREA'
|
|
|| target.tagName === 'SELECT'
|
|
|| target.isContentEditable
|
|
)) return;
|
|
e.preventDefault();
|
|
setPerfProbeOpen(true);
|
|
};
|
|
window.addEventListener('keydown', onKey);
|
|
return () => window.removeEventListener('keydown', onKey);
|
|
}, []);
|
|
|
|
return {
|
|
perfProbeOpen,
|
|
setPerfProbeOpen,
|
|
};
|
|
}
|