GenerAI / worldmonitor /src /components /map /render-timing.ts
amogaddy's picture
Integra World Monitor (AGPL-3.0, self-hosted) nello Space: pagina, menu, e arricchimento notizie per la AI (part 7)
9d2d895 verified
Raw
History Blame Contribute Delete
2.85 kB
/**
* DEV-only render-frame timing attribution for DeckGLMap (#4558 / #4537).
*
* Pure, dependency-free so it is unit-testable under `tsx --test` without a
* DOM/WebGL context. `DeckGLMap.updateLayers()` feeds it the measured parts of a
* render frame; `summarizeRenderTiming` splits the cost into the JS-build bucket
* (our `buildLayers()` — layer construction + any Supercluster index rebuild that
* fires inside it) vs the deck.gl commit bucket (tessellation + attribute
* generation inside `setProps`). That distinction is the core #4558 question: is
* a slow frame our synchronous JS or deck.gl's intrinsic tessellation?
*/
/** The 16ms single-frame budget the existing DEV warning checks against. */
export const FRAME_BUDGET_MS = 16;
export interface RenderTimingParts {
/** Total wall-clock for the render frame (performance.now delta). */
total: number;
/** Time spent in `buildLayers()` (layer construction + in-build Supercluster rebuilds). */
jsBuild?: number;
/** Number of deck.gl layers committed this frame. */
layerCount?: number;
/** Heavy layers whose data changed this frame (e.g. conflict-zones, clusters). */
changedHeavyLayers?: string[];
}
export interface RenderTimingSummary {
total: number;
/** Our synchronous JS cost (`buildLayers`). */
jsBuild: number;
/** Remainder attributed to the deck.gl commit (tessellation + attributes). */
deckCommit: number;
layerCount: number;
changedHeavyLayers: string[];
/** True when the frame exceeded the single-frame budget. */
overBudget: boolean;
}
const clampNonNegative = (n: number | undefined): number =>
typeof n === 'number' && Number.isFinite(n) && n > 0 ? n : 0;
/**
* Split a measured render frame into attributable buckets. `deckCommit` is the
* remainder after the JS build, floored at 0 so a noisy measurement (build
* slightly exceeding total) never reports a negative bucket.
*/
export function summarizeRenderTiming(parts: RenderTimingParts): RenderTimingSummary {
const total = clampNonNegative(parts.total);
const jsBuild = Math.min(total, clampNonNegative(parts.jsBuild));
return {
total,
jsBuild,
deckCommit: Math.max(0, total - jsBuild),
layerCount: clampNonNegative(parts.layerCount),
changedHeavyLayers: parts.changedHeavyLayers ? [...parts.changedHeavyLayers] : [],
overBudget: total > FRAME_BUDGET_MS,
};
}
/** Compact one-line DEV log string for a slow frame. */
export function formatRenderTiming(summary: RenderTimingSummary): string {
const heavy = summary.changedHeavyLayers.length
? ` changed=[${summary.changedHeavyLayers.join(',')}]`
: '';
return (
`[DeckGLMap] render ${summary.total.toFixed(1)}ms ` +
`(jsBuild ${summary.jsBuild.toFixed(1)} / ` +
`deck ${summary.deckCommit.toFixed(1)}) layers=${summary.layerCount}${heavy}`
);
}