extract WorkerProfiler + remove dead helpers

- Move profiling/metrics logic out of Worker.worker.ts into WorkerProfiler.ts
- Drop unused MAX_TICKS_PER_HEARTBEAT and TransformHandler.viewOffset()
- Simplify TerritoryLayer overlay parenting; remove unused markTile() wrapper
This commit is contained in:
scamiv
2026-02-05 02:37:13 +01:00
parent 3137d8b6e0
commit 813c5020f7
4 changed files with 368 additions and 375 deletions
-4
View File
@@ -45,10 +45,6 @@ export class TransformHandler {
return this._boundingRect;
}
viewOffset(): { x: number; y: number } {
return { x: this.offsetX, y: this.offsetY };
}
getOffsetX(): number {
return this.offsetX;
}
+4 -9
View File
@@ -242,8 +242,8 @@ export class TerritoryLayer implements Layer {
canvas.style.display = "block";
}
const parent = mainCanvas.parentElement;
if (!parent) {
const currentParent = mainCanvas.parentElement;
if (!currentParent) {
// Fallback: if the canvas isn't in the DOM yet, append to body.
if (!canvas.isConnected) {
document.body.appendChild(canvas);
@@ -254,8 +254,7 @@ export class TerritoryLayer implements Layer {
// Ensure the main canvas is wrapped in a positioned container so the
// territory canvas can overlay it without mirroring computed styles.
let wrapper: HTMLElement;
const currentParent = mainCanvas.parentElement;
if (currentParent && currentParent.dataset.territoryOverlay === "1") {
if (currentParent.dataset.territoryOverlay === "1") {
wrapper = currentParent;
} else {
wrapper = document.createElement("div");
@@ -265,7 +264,7 @@ export class TerritoryLayer implements Layer {
wrapper.style.lineHeight = "0";
// Replace mainCanvas with wrapper, then re-insert mainCanvas inside wrapper.
parent.replaceChild(wrapper, mainCanvas);
currentParent.replaceChild(wrapper, mainCanvas);
wrapper.appendChild(mainCanvas);
}
@@ -303,10 +302,6 @@ export class TerritoryLayer implements Layer {
if (h > 0) wrapper.style.height = `${h}px`;
}
private markTile(tile: TileRef) {
this.territoryRenderer?.markTile(tile);
}
private updateHoverHighlight() {
if (!this.territoryRenderer) {
return;
+2 -362
View File
@@ -30,8 +30,8 @@ import {
TileContextResultMessage,
TransportShipSpawnResultMessage,
WorkerMessage,
WorkerMetricsMessage,
} from "./WorkerMessages";
import { WorkerProfiler } from "./WorkerProfiler";
import { WorkerTerritoryRenderer } from "./WorkerTerritoryRenderer";
const ctx: Worker = self as any;
@@ -39,373 +39,13 @@ let gameRunner: Promise<GameRunner> | null = null;
let gameStartInfo: GameStartInfo | null = null;
let myClientID: ClientID | null = null;
const mapLoader = new FetchGameMapLoader(`/maps`, version);
const MAX_TICKS_PER_HEARTBEAT = 4;
let renderer: WorkerTerritoryRenderer | WorkerCanvas2DRenderer | null = null;
let dirtyTiles: DirtyTileQueue | null = null;
let dirtyTilesOverflow = false;
let renderTileState: Uint16Array | null = null;
const pendingTurns: Turn[] = [];
type WorkerDebugConfig = {
enabled: boolean;
intervalMs: number;
includeTrace: boolean;
};
class WorkerProfiler {
public config: WorkerDebugConfig = {
enabled: false,
intervalMs: 1000,
includeTrace: false,
};
private reportTimer: any = null;
private lastReportWallMs = 0;
private eventLoopLagSum = 0;
private eventLoopLagCount = 0;
private eventLoopLagMax = 0;
private simDelaySum = 0;
private simDelayCount = 0;
private simDelayMax = 0;
private simExecSum = 0;
private simExecCount = 0;
private simExecMax = 0;
private readonly msgCounts = new Map<string, number>();
private readonly msgHandlerSum = new Map<string, number>();
private readonly msgQueueSum = new Map<string, number>();
private readonly msgHandlerMax = new Map<string, number>();
private readonly msgQueueMax = new Map<string, number>();
private traceRing: string[] = [];
private traceHead = 0;
private readonly traceCap = 160;
private renderSubmittedCount = 0;
private renderNoopCount = 0;
private renderGetTextureSum = 0;
private renderGetTextureMax = 0;
private renderFrameComputeSum = 0;
private renderFrameComputeMax = 0;
private renderTerritoryPassSum = 0;
private renderTerritoryPassMax = 0;
private renderTemporalResolveSum = 0;
private renderTemporalResolveMax = 0;
private renderSubmitSum = 0;
private renderSubmitMax = 0;
private renderCpuTotalSum = 0;
private renderCpuTotalMax = 0;
start(): void {
if (this.reportTimer) return;
this.lastReportWallMs = Date.now();
// Event-loop lag sampler (low overhead).
let expected = Date.now() + 100;
setInterval(() => {
if (!this.config.enabled) return;
const now = Date.now();
const lag = Math.max(0, now - expected);
expected = now + 100;
this.eventLoopLagSum += lag;
this.eventLoopLagCount++;
this.eventLoopLagMax = Math.max(this.eventLoopLagMax, lag);
}, 100);
this.reportTimer = setInterval(() => this.report(), this.config.intervalMs);
}
configure(next: Partial<WorkerDebugConfig>): void {
const prevInterval = this.config.intervalMs;
this.config = {
enabled: next.enabled ?? this.config.enabled,
intervalMs: Math.max(
100,
(next.intervalMs ?? this.config.intervalMs) | 0,
),
includeTrace: next.includeTrace ?? this.config.includeTrace,
};
if (this.config.enabled && !this.reportTimer) {
this.start();
}
if (this.reportTimer && this.config.intervalMs !== prevInterval) {
clearInterval(this.reportTimer);
this.reportTimer = setInterval(
() => this.report(),
this.config.intervalMs,
);
}
}
recordMessage(type: string, queueMs: number | null, handlerMs: number): void {
if (!this.config.enabled) return;
this.msgCounts.set(type, (this.msgCounts.get(type) ?? 0) + 1);
this.msgHandlerSum.set(
type,
(this.msgHandlerSum.get(type) ?? 0) + handlerMs,
);
this.msgHandlerMax.set(
type,
Math.max(this.msgHandlerMax.get(type) ?? 0, handlerMs),
);
if (queueMs !== null) {
this.msgQueueSum.set(type, (this.msgQueueSum.get(type) ?? 0) + queueMs);
this.msgQueueMax.set(
type,
Math.max(this.msgQueueMax.get(type) ?? 0, queueMs),
);
}
if (handlerMs > 25 || (queueMs !== null && queueMs > 250)) {
this.trace(
`${new Date().toISOString()} msg ${type} queue=${queueMs ?? "?"}ms handler=${Math.round(handlerMs)}ms`,
);
}
}
recordSimExec(execMs: number): void {
if (!this.config.enabled) return;
this.simExecSum += execMs;
this.simExecCount++;
this.simExecMax = Math.max(this.simExecMax, execMs);
if (execMs > 25) {
this.trace(
`${new Date().toISOString()} sim executeNextTick ${Math.round(execMs)}ms`,
);
}
}
recordSimDelay(delayMs: number): void {
if (!this.config.enabled) return;
this.simDelaySum += delayMs;
this.simDelayCount++;
this.simDelayMax = Math.max(this.simDelayMax, delayMs);
if (delayMs > 25) {
this.trace(
`${new Date().toISOString()} sim scheduleDelay ${Math.round(delayMs)}ms`,
);
}
}
recordRenderBreakdown(b: {
submitted: boolean;
getTextureMs?: number;
frameComputeMs?: number;
territoryPassMs?: number;
temporalResolveMs?: number;
submitMs?: number;
cpuTotalMs?: number;
}): void {
if (!this.config.enabled) return;
if (!b.submitted) {
this.renderNoopCount++;
return;
}
this.renderSubmittedCount++;
if (typeof b.getTextureMs === "number") {
this.renderGetTextureSum += b.getTextureMs;
this.renderGetTextureMax = Math.max(
this.renderGetTextureMax,
b.getTextureMs,
);
}
if (typeof b.frameComputeMs === "number") {
this.renderFrameComputeSum += b.frameComputeMs;
this.renderFrameComputeMax = Math.max(
this.renderFrameComputeMax,
b.frameComputeMs,
);
}
if (typeof b.territoryPassMs === "number") {
this.renderTerritoryPassSum += b.territoryPassMs;
this.renderTerritoryPassMax = Math.max(
this.renderTerritoryPassMax,
b.territoryPassMs,
);
}
if (typeof b.temporalResolveMs === "number") {
this.renderTemporalResolveSum += b.temporalResolveMs;
this.renderTemporalResolveMax = Math.max(
this.renderTemporalResolveMax,
b.temporalResolveMs,
);
}
if (typeof b.submitMs === "number") {
this.renderSubmitSum += b.submitMs;
this.renderSubmitMax = Math.max(this.renderSubmitMax, b.submitMs);
}
if (typeof b.cpuTotalMs === "number") {
this.renderCpuTotalSum += b.cpuTotalMs;
this.renderCpuTotalMax = Math.max(this.renderCpuTotalMax, b.cpuTotalMs);
}
}
trace(line: string): void {
if (!this.config.enabled || !this.config.includeTrace) return;
if (this.traceRing.length < this.traceCap) {
this.traceRing.push(line);
return;
}
this.traceRing[this.traceHead] = line;
this.traceHead = (this.traceHead + 1) % this.traceCap;
}
private flushTrace(): string[] {
if (!this.config.includeTrace || this.traceRing.length === 0) {
return [];
}
if (this.traceRing.length < this.traceCap) {
return [...this.traceRing];
}
return [
...this.traceRing.slice(this.traceHead),
...this.traceRing.slice(0, this.traceHead),
];
}
private report(): void {
if (!this.config.enabled) return;
const now = Date.now();
const intervalMs = Math.max(1, now - this.lastReportWallMs);
this.lastReportWallMs = now;
const toAvgRecord = (
sumMap: Map<string, number>,
countMap: Map<string, number>,
) => {
const out: Record<string, number> = {};
for (const [k, sum] of sumMap) {
const c = countMap.get(k) ?? 0;
if (c > 0) {
out[k] = sum / c;
}
}
return out;
};
const toMaxRecord = (maxMap: Map<string, number>) => {
const out: Record<string, number> = {};
for (const [k, v] of maxMap) {
out[k] = v;
}
return out;
};
const msgCountsObj: Record<string, number> = {};
for (const [k, c] of this.msgCounts) {
msgCountsObj[k] = c;
}
const renderTotal = this.renderSubmittedCount + this.renderNoopCount;
const rAvg = (sum: number): number =>
this.renderSubmittedCount > 0 ? sum / this.renderSubmittedCount : 0;
const metrics: WorkerMetricsMessage = {
type: "worker_metrics",
intervalMs,
eventLoopLagMsAvg:
this.eventLoopLagCount > 0
? this.eventLoopLagSum / this.eventLoopLagCount
: 0,
eventLoopLagMsMax: this.eventLoopLagMax,
simPumpDelayMsAvg:
this.simDelayCount > 0 ? this.simDelaySum / this.simDelayCount : 0,
simPumpDelayMsMax: this.simDelayMax,
simPumpExecMsAvg:
this.simExecCount > 0 ? this.simExecSum / this.simExecCount : 0,
simPumpExecMsMax: this.simExecMax,
renderSubmittedCount:
renderTotal > 0 ? this.renderSubmittedCount : undefined,
renderNoopCount: renderTotal > 0 ? this.renderNoopCount : undefined,
renderGetTextureMsAvg:
this.renderSubmittedCount > 0
? rAvg(this.renderGetTextureSum)
: undefined,
renderGetTextureMsMax:
this.renderSubmittedCount > 0 ? this.renderGetTextureMax : undefined,
renderFrameComputeMsAvg:
this.renderSubmittedCount > 0
? rAvg(this.renderFrameComputeSum)
: undefined,
renderFrameComputeMsMax:
this.renderSubmittedCount > 0 ? this.renderFrameComputeMax : undefined,
renderTerritoryPassMsAvg:
this.renderSubmittedCount > 0
? rAvg(this.renderTerritoryPassSum)
: undefined,
renderTerritoryPassMsMax:
this.renderSubmittedCount > 0 ? this.renderTerritoryPassMax : undefined,
renderTemporalResolveMsAvg:
this.renderSubmittedCount > 0
? rAvg(this.renderTemporalResolveSum)
: undefined,
renderTemporalResolveMsMax:
this.renderSubmittedCount > 0
? this.renderTemporalResolveMax
: undefined,
renderSubmitMsAvg:
this.renderSubmittedCount > 0 ? rAvg(this.renderSubmitSum) : undefined,
renderSubmitMsMax:
this.renderSubmittedCount > 0 ? this.renderSubmitMax : undefined,
renderCpuTotalMsAvg:
this.renderSubmittedCount > 0
? rAvg(this.renderCpuTotalSum)
: undefined,
renderCpuTotalMsMax:
this.renderSubmittedCount > 0 ? this.renderCpuTotalMax : undefined,
msgCounts: msgCountsObj,
msgHandlerMsAvg: toAvgRecord(this.msgHandlerSum, this.msgCounts),
msgHandlerMsMax: toMaxRecord(this.msgHandlerMax),
msgQueueMsAvg: toAvgRecord(this.msgQueueSum, this.msgCounts),
msgQueueMsMax: toMaxRecord(this.msgQueueMax),
trace: this.config.includeTrace ? this.flushTrace() : undefined,
};
sendMessage(metrics);
// Reset per-interval counters.
this.eventLoopLagSum = 0;
this.eventLoopLagCount = 0;
this.eventLoopLagMax = 0;
this.simDelaySum = 0;
this.simDelayCount = 0;
this.simDelayMax = 0;
this.simExecSum = 0;
this.simExecCount = 0;
this.simExecMax = 0;
this.renderSubmittedCount = 0;
this.renderNoopCount = 0;
this.renderGetTextureSum = 0;
this.renderGetTextureMax = 0;
this.renderFrameComputeSum = 0;
this.renderFrameComputeMax = 0;
this.renderTerritoryPassSum = 0;
this.renderTerritoryPassMax = 0;
this.renderTemporalResolveSum = 0;
this.renderTemporalResolveMax = 0;
this.renderSubmitSum = 0;
this.renderSubmitMax = 0;
this.renderCpuTotalSum = 0;
this.renderCpuTotalMax = 0;
this.msgCounts.clear();
this.msgHandlerSum.clear();
this.msgHandlerMax.clear();
this.msgQueueSum.clear();
this.msgQueueMax.clear();
if (this.config.includeTrace) {
this.traceRing = [];
this.traceHead = 0;
}
}
}
const profiler = new WorkerProfiler();
const profiler = new WorkerProfiler(sendMessage);
let simPumpScheduled = false;
+362
View File
@@ -0,0 +1,362 @@
import { WorkerMetricsMessage } from "./WorkerMessages";
export type WorkerDebugConfig = {
enabled: boolean;
intervalMs: number;
includeTrace: boolean;
};
export class WorkerProfiler {
public config: WorkerDebugConfig = {
enabled: false,
intervalMs: 1000,
includeTrace: false,
};
private reportTimer: any = null;
private lastReportWallMs = 0;
private eventLoopLagSum = 0;
private eventLoopLagCount = 0;
private eventLoopLagMax = 0;
private simDelaySum = 0;
private simDelayCount = 0;
private simDelayMax = 0;
private simExecSum = 0;
private simExecCount = 0;
private simExecMax = 0;
private readonly msgCounts = new Map<string, number>();
private readonly msgHandlerSum = new Map<string, number>();
private readonly msgQueueSum = new Map<string, number>();
private readonly msgHandlerMax = new Map<string, number>();
private readonly msgQueueMax = new Map<string, number>();
private traceRing: string[] = [];
private traceHead = 0;
private readonly traceCap = 160;
private renderSubmittedCount = 0;
private renderNoopCount = 0;
private renderGetTextureSum = 0;
private renderGetTextureMax = 0;
private renderFrameComputeSum = 0;
private renderFrameComputeMax = 0;
private renderTerritoryPassSum = 0;
private renderTerritoryPassMax = 0;
private renderTemporalResolveSum = 0;
private renderTemporalResolveMax = 0;
private renderSubmitSum = 0;
private renderSubmitMax = 0;
private renderCpuTotalSum = 0;
private renderCpuTotalMax = 0;
constructor(private send: (message: WorkerMetricsMessage) => void) {}
start(): void {
if (this.reportTimer) return;
this.lastReportWallMs = Date.now();
// Event-loop lag sampler (low overhead).
let expected = Date.now() + 100;
setInterval(() => {
if (!this.config.enabled) return;
const now = Date.now();
const lag = Math.max(0, now - expected);
expected = now + 100;
this.eventLoopLagSum += lag;
this.eventLoopLagCount++;
this.eventLoopLagMax = Math.max(this.eventLoopLagMax, lag);
}, 100);
this.reportTimer = setInterval(() => this.report(), this.config.intervalMs);
}
configure(next: Partial<WorkerDebugConfig>): void {
const prevInterval = this.config.intervalMs;
this.config = {
enabled: next.enabled ?? this.config.enabled,
intervalMs: Math.max(
100,
(next.intervalMs ?? this.config.intervalMs) | 0,
),
includeTrace: next.includeTrace ?? this.config.includeTrace,
};
if (this.config.enabled && !this.reportTimer) {
this.start();
}
if (this.reportTimer && this.config.intervalMs !== prevInterval) {
clearInterval(this.reportTimer);
this.reportTimer = setInterval(
() => this.report(),
this.config.intervalMs,
);
}
}
recordMessage(type: string, queueMs: number | null, handlerMs: number): void {
if (!this.config.enabled) return;
this.msgCounts.set(type, (this.msgCounts.get(type) ?? 0) + 1);
this.msgHandlerSum.set(
type,
(this.msgHandlerSum.get(type) ?? 0) + handlerMs,
);
this.msgHandlerMax.set(
type,
Math.max(this.msgHandlerMax.get(type) ?? 0, handlerMs),
);
if (queueMs !== null) {
this.msgQueueSum.set(type, (this.msgQueueSum.get(type) ?? 0) + queueMs);
this.msgQueueMax.set(
type,
Math.max(this.msgQueueMax.get(type) ?? 0, queueMs),
);
}
if (handlerMs > 25 || (queueMs !== null && queueMs > 250)) {
this.trace(
`${new Date().toISOString()} msg ${type} queue=${queueMs ?? "?"}ms handler=${Math.round(handlerMs)}ms`,
);
}
}
recordSimExec(execMs: number): void {
if (!this.config.enabled) return;
this.simExecSum += execMs;
this.simExecCount++;
this.simExecMax = Math.max(this.simExecMax, execMs);
if (execMs > 25) {
this.trace(
`${new Date().toISOString()} sim executeNextTick ${Math.round(execMs)}ms`,
);
}
}
recordSimDelay(delayMs: number): void {
if (!this.config.enabled) return;
this.simDelaySum += delayMs;
this.simDelayCount++;
this.simDelayMax = Math.max(this.simDelayMax, delayMs);
if (delayMs > 25) {
this.trace(
`${new Date().toISOString()} sim scheduleDelay ${Math.round(delayMs)}ms`,
);
}
}
recordRenderBreakdown(b: {
submitted: boolean;
getTextureMs?: number;
frameComputeMs?: number;
territoryPassMs?: number;
temporalResolveMs?: number;
submitMs?: number;
cpuTotalMs?: number;
}): void {
if (!this.config.enabled) return;
if (!b.submitted) {
this.renderNoopCount++;
return;
}
this.renderSubmittedCount++;
if (typeof b.getTextureMs === "number") {
this.renderGetTextureSum += b.getTextureMs;
this.renderGetTextureMax = Math.max(
this.renderGetTextureMax,
b.getTextureMs,
);
}
if (typeof b.frameComputeMs === "number") {
this.renderFrameComputeSum += b.frameComputeMs;
this.renderFrameComputeMax = Math.max(
this.renderFrameComputeMax,
b.frameComputeMs,
);
}
if (typeof b.territoryPassMs === "number") {
this.renderTerritoryPassSum += b.territoryPassMs;
this.renderTerritoryPassMax = Math.max(
this.renderTerritoryPassMax,
b.territoryPassMs,
);
}
if (typeof b.temporalResolveMs === "number") {
this.renderTemporalResolveSum += b.temporalResolveMs;
this.renderTemporalResolveMax = Math.max(
this.renderTemporalResolveMax,
b.temporalResolveMs,
);
}
if (typeof b.submitMs === "number") {
this.renderSubmitSum += b.submitMs;
this.renderSubmitMax = Math.max(this.renderSubmitMax, b.submitMs);
}
if (typeof b.cpuTotalMs === "number") {
this.renderCpuTotalSum += b.cpuTotalMs;
this.renderCpuTotalMax = Math.max(this.renderCpuTotalMax, b.cpuTotalMs);
}
}
trace(line: string): void {
if (!this.config.enabled || !this.config.includeTrace) return;
if (this.traceRing.length < this.traceCap) {
this.traceRing.push(line);
return;
}
this.traceRing[this.traceHead] = line;
this.traceHead = (this.traceHead + 1) % this.traceCap;
}
private flushTrace(): string[] {
if (!this.config.includeTrace || this.traceRing.length === 0) {
return [];
}
if (this.traceRing.length < this.traceCap) {
return [...this.traceRing];
}
return [
...this.traceRing.slice(this.traceHead),
...this.traceRing.slice(0, this.traceHead),
];
}
private report(): void {
if (!this.config.enabled) return;
const now = Date.now();
const intervalMs = Math.max(1, now - this.lastReportWallMs);
this.lastReportWallMs = now;
const toAvgRecord = (
sumMap: Map<string, number>,
countMap: Map<string, number>,
) => {
const out: Record<string, number> = {};
for (const [k, sum] of sumMap) {
const c = countMap.get(k) ?? 0;
if (c > 0) {
out[k] = sum / c;
}
}
return out;
};
const toMaxRecord = (maxMap: Map<string, number>) => {
const out: Record<string, number> = {};
for (const [k, v] of maxMap) {
out[k] = v;
}
return out;
};
const msgCountsObj: Record<string, number> = {};
for (const [k, c] of this.msgCounts) {
msgCountsObj[k] = c;
}
const renderTotal = this.renderSubmittedCount + this.renderNoopCount;
const rAvg = (sum: number): number =>
this.renderSubmittedCount > 0 ? sum / this.renderSubmittedCount : 0;
const metrics: WorkerMetricsMessage = {
type: "worker_metrics",
intervalMs,
eventLoopLagMsAvg:
this.eventLoopLagCount > 0
? this.eventLoopLagSum / this.eventLoopLagCount
: 0,
eventLoopLagMsMax: this.eventLoopLagMax,
simPumpDelayMsAvg:
this.simDelayCount > 0 ? this.simDelaySum / this.simDelayCount : 0,
simPumpDelayMsMax: this.simDelayMax,
simPumpExecMsAvg:
this.simExecCount > 0 ? this.simExecSum / this.simExecCount : 0,
simPumpExecMsMax: this.simExecMax,
renderSubmittedCount:
renderTotal > 0 ? this.renderSubmittedCount : undefined,
renderNoopCount: renderTotal > 0 ? this.renderNoopCount : undefined,
renderGetTextureMsAvg:
this.renderSubmittedCount > 0
? rAvg(this.renderGetTextureSum)
: undefined,
renderGetTextureMsMax:
this.renderSubmittedCount > 0 ? this.renderGetTextureMax : undefined,
renderFrameComputeMsAvg:
this.renderSubmittedCount > 0
? rAvg(this.renderFrameComputeSum)
: undefined,
renderFrameComputeMsMax:
this.renderSubmittedCount > 0 ? this.renderFrameComputeMax : undefined,
renderTerritoryPassMsAvg:
this.renderSubmittedCount > 0
? rAvg(this.renderTerritoryPassSum)
: undefined,
renderTerritoryPassMsMax:
this.renderSubmittedCount > 0 ? this.renderTerritoryPassMax : undefined,
renderTemporalResolveMsAvg:
this.renderSubmittedCount > 0
? rAvg(this.renderTemporalResolveSum)
: undefined,
renderTemporalResolveMsMax:
this.renderSubmittedCount > 0
? this.renderTemporalResolveMax
: undefined,
renderSubmitMsAvg:
this.renderSubmittedCount > 0 ? rAvg(this.renderSubmitSum) : undefined,
renderSubmitMsMax:
this.renderSubmittedCount > 0 ? this.renderSubmitMax : undefined,
renderCpuTotalMsAvg:
this.renderSubmittedCount > 0
? rAvg(this.renderCpuTotalSum)
: undefined,
renderCpuTotalMsMax:
this.renderSubmittedCount > 0 ? this.renderCpuTotalMax : undefined,
msgCounts: msgCountsObj,
msgHandlerMsAvg: toAvgRecord(this.msgHandlerSum, this.msgCounts),
msgHandlerMsMax: toMaxRecord(this.msgHandlerMax),
msgQueueMsAvg: toAvgRecord(this.msgQueueSum, this.msgCounts),
msgQueueMsMax: toMaxRecord(this.msgQueueMax),
trace: this.config.includeTrace ? this.flushTrace() : undefined,
};
this.send(metrics);
// Reset per-interval counters.
this.eventLoopLagSum = 0;
this.eventLoopLagCount = 0;
this.eventLoopLagMax = 0;
this.simDelaySum = 0;
this.simDelayCount = 0;
this.simDelayMax = 0;
this.simExecSum = 0;
this.simExecCount = 0;
this.simExecMax = 0;
this.renderSubmittedCount = 0;
this.renderNoopCount = 0;
this.renderGetTextureSum = 0;
this.renderGetTextureMax = 0;
this.renderFrameComputeSum = 0;
this.renderFrameComputeMax = 0;
this.renderTerritoryPassSum = 0;
this.renderTerritoryPassMax = 0;
this.renderTemporalResolveSum = 0;
this.renderTemporalResolveMax = 0;
this.renderSubmitSum = 0;
this.renderSubmitMax = 0;
this.renderCpuTotalSum = 0;
this.renderCpuTotalMax = 0;
this.msgCounts.clear();
this.msgHandlerSum.clear();
this.msgHandlerMax.clear();
this.msgQueueSum.clear();
this.msgQueueMax.clear();
if (this.config.includeTrace) {
this.traceRing = [];
this.traceHead = 0;
}
}
}