From 2f2a12eefa6d377a3469bbe552a6458148a366f4 Mon Sep 17 00:00:00 2001 From: scamiv <6170744+scamiv@users.noreply.github.com> Date: Tue, 25 Nov 2025 19:21:33 +0100 Subject: [PATCH] Add performance metrics for worker and render ticks - Introduced new metrics in ClientGameRunner to track worker simulation ticks and render tick calls per second. - Updated TickMetricsEvent to include these new metrics. - Enhanced PerformanceOverlay to display worker and render ticks per second, improving performance monitoring capabilities. - Adjusted minimum FPS in GameRenderer --- src/client/ClientGameRunner.ts | 24 +++++++++++++++++ src/client/InputHandler.ts | 6 ++++- src/client/graphics/GameRenderer.ts | 2 +- .../graphics/layers/PerformanceOverlay.ts | 26 +++++++++++++++++++ 4 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/client/ClientGameRunner.ts b/src/client/ClientGameRunner.ts index 91ead75a2..036a91161 100644 --- a/src/client/ClientGameRunner.ts +++ b/src/client/ClientGameRunner.ts @@ -233,6 +233,9 @@ export class ClientGameRunner { private backlogTurns: number = 0; private backlogGrowing: boolean = false; private lastRenderedTick: number = 0; + private workerTicksSinceSample: number = 0; + private renderTicksSinceSample: number = 0; + private metricsSampleStart: number = 0; private pendingUpdates: GameUpdateViewData[] = []; private pendingStart = 0; @@ -495,6 +498,7 @@ export class ClientGameRunner { while (this.pendingStart < this.pendingUpdates.length) { const gu = this.pendingUpdates[this.pendingStart++]; processedCount++; + this.workerTicksSinceSample++; batch.push(gu); this.transport.turnComplete(); @@ -545,6 +549,24 @@ export class ClientGameRunner { : lastTick - this.lastRenderedTick; this.lastRenderedTick = lastTick; + this.renderTicksSinceSample++; + + let workerTicksPerSecond: number | undefined; + let renderTicksPerSecond: number | undefined; + const now = performance.now(); + if (this.metricsSampleStart === 0) { + this.metricsSampleStart = now; + } else { + const elapsedSeconds = (now - this.metricsSampleStart) / 1000; + if (elapsedSeconds > 0) { + workerTicksPerSecond = this.workerTicksSinceSample / elapsedSeconds; + renderTicksPerSecond = this.renderTicksSinceSample / elapsedSeconds; + } + this.metricsSampleStart = now; + this.workerTicksSinceSample = 0; + this.renderTicksSinceSample = 0; + } + this.renderer.tick(); this.eventBus.emit( new TickMetricsEvent( @@ -552,6 +574,8 @@ export class ClientGameRunner { this.currentTickDelay, this.backlogTurns, ticksPerRender, + workerTicksPerSecond, + renderTicksPerSecond, ), ); diff --git a/src/client/InputHandler.ts b/src/client/InputHandler.ts index 85039015d..dbae066ee 100644 --- a/src/client/InputHandler.ts +++ b/src/client/InputHandler.ts @@ -131,8 +131,12 @@ export class TickMetricsEvent implements GameEvent { public readonly tickDelay?: number, // Number of turns the client is behind the server (if known) public readonly backlogTurns?: number, - // Number of ticks applied since last render + // Number of simulation ticks applied since last render public readonly ticksPerRender?: number, + // Approximate worker simulation ticks per second + public readonly workerTicksPerSecond?: number, + // Approximate render tick() calls per second + public readonly renderTicksPerSecond?: number, ) {} } diff --git a/src/client/graphics/GameRenderer.ts b/src/client/graphics/GameRenderer.ts index 94ad93785..d36ce8117 100644 --- a/src/client/graphics/GameRenderer.ts +++ b/src/client/graphics/GameRenderer.ts @@ -362,7 +362,7 @@ export class GameRenderer { if (this.backlogTurns > 0) { const BASE_FPS = 60; - const MIN_FPS = 20; + const MIN_FPS = 10; const BACKLOG_MAX_TURNS = 50; const scale = Math.min(1, this.backlogTurns / BACKLOG_MAX_TURNS); diff --git a/src/client/graphics/layers/PerformanceOverlay.ts b/src/client/graphics/layers/PerformanceOverlay.ts index 531f19f0b..64499024f 100644 --- a/src/client/graphics/layers/PerformanceOverlay.ts +++ b/src/client/graphics/layers/PerformanceOverlay.ts @@ -234,6 +234,8 @@ export class PerformanceOverlay extends LitElement implements Layer { event.tickDelay, event.backlogTurns, event.ticksPerRender, + event.workerTicksPerSecond, + event.renderTicksPerSecond, ); }); } @@ -429,11 +431,19 @@ export class PerformanceOverlay extends LitElement implements Layer { @state() private ticksPerRender: number = 0; + @state() + private workerTicksPerSecond: number = 0; + + @state() + private renderTicksPerSecond: number = 0; + updateTickMetrics( tickExecutionDuration?: number, tickDelay?: number, backlogTurns?: number, ticksPerRender?: number, + workerTicksPerSecond?: number, + renderTicksPerSecond?: number, ) { if (!this.isVisible || !this.userSettings.performanceOverlay()) return; @@ -479,6 +489,14 @@ export class PerformanceOverlay extends LitElement implements Layer { this.ticksPerRender = ticksPerRender; } + if (workerTicksPerSecond !== undefined) { + this.workerTicksPerSecond = workerTicksPerSecond; + } + + if (renderTicksPerSecond !== undefined) { + this.renderTicksPerSecond = renderTicksPerSecond; + } + this.requestUpdate(); } @@ -624,6 +642,14 @@ export class PerformanceOverlay extends LitElement implements Layer { ${this.tickDelayAvg.toFixed(2)}ms (max: ${this.tickDelayMax}ms) +
+ Worker ticks/s: + ${this.workerTicksPerSecond.toFixed(1)} +
+
+ Render ticks/s: + ${this.renderTicksPerSecond.toFixed(1)} +
Ticks per render: ${this.ticksPerRender}