@awesome-ecs/workers
Version:
The Workers package for Awesome ECS. Provides basic implementation for the Worker communication using ECS.
1 lines • 13 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/utils/worker-performance-tracker.ts"],"sourcesContent":["import { PerformanceTimeEntry } from '@awesome-ecs/abstract/utils';\nimport {\n WorkerMetricEntry,\n WorkerMetricsSummary,\n WorkerSnapshot\n} from '../abstract/worker-performance';\n\ntype AccEntry = {\n count: number;\n totalMs: number;\n minMs: number;\n maxMs: number;\n lastMs: number;\n};\n\n/**\n * Tracks performance metrics for worker operations, allowing for aggregation and analysis of execution times across different worker tasks.\n * Metrics are sampled at regular intervals and can be retrieved in summary form for overall or per-worker insights.\n *\n * @injectable\n */\nexport class WorkerPerformanceTracker {\n static readonly MAX_SNAPSHOTS = 120;\n static readonly SAMPLE_INTERVAL_MS = 250;\n\n private readonly _snapshots: WorkerSnapshot[] = [];\n private readonly _pendingMetrics = new Map<string, WorkerMetricEntry>();\n private readonly _perWorkerPending = new Map<string, Map<string, WorkerMetricEntry>>();\n\n private readonly _aggregate = new Map<string, AccEntry>();\n private readonly _perWorkerAggregate = new Map<string, Map<string, AccEntry>>();\n\n private _pendingMaxQueueSize = 0;\n private _pendingStalledCount = 0;\n private _pendingWaitTimes: number[] = [];\n private _lastSampleTime = 0;\n private _enabled = false;\n\n private _aggregateDirty = true;\n private _cachedSummaries: WorkerMetricsSummary[] = [];\n private _perWorkerDirty = true;\n private _cachedPerWorker = new Map<string, WorkerMetricsSummary[]>();\n\n get snapshots(): ReadonlyArray<WorkerSnapshot> {\n return this._snapshots;\n }\n\n get enabled(): boolean {\n return this._enabled;\n }\n\n set enabled(value: boolean) {\n this._enabled = value;\n }\n\n get queueHistory(): number[] {\n return this._snapshots.map((s) => s.queueSize);\n }\n\n get stalledHistory(): number[] {\n return this._snapshots.map((s) => s.stalledCount);\n }\n\n get waitTimeHistory(): number[] {\n return this._snapshots.map((s) => s.avgWaitTimeMs);\n }\n\n get eventTypeHistories(): Map<string, number[]> {\n const allNames = new Set<string>();\n for (const snap of this._snapshots) {\n for (const m of snap.metrics) allNames.add(m.name);\n }\n\n const result = new Map<string, number[]>();\n for (const name of allNames) {\n result.set(\n name,\n this._snapshots.map((snap) => {\n const m = snap.metrics.find((e) => e.name === name);\n return m && m.count > 0 ? m.totalMs / m.count : 0;\n })\n );\n }\n return result;\n }\n\n get summaries(): WorkerMetricsSummary[] {\n if (!this._aggregateDirty) return this._cachedSummaries;\n\n const result: WorkerMetricsSummary[] = [];\n for (const [name, data] of this._aggregate) {\n result.push({\n name,\n count: data.count,\n totalMs: data.totalMs,\n avgMs: data.count > 0 ? data.totalMs / data.count : 0,\n minMs: data.minMs,\n maxMs: data.maxMs,\n lastMs: data.lastMs\n });\n }\n result.sort((a, b) => b.totalMs - a.totalMs);\n this._cachedSummaries = result;\n this._aggregateDirty = false;\n return result;\n }\n\n get perWorkerSummaries(): Map<string, WorkerMetricsSummary[]> {\n if (!this._perWorkerDirty) return this._cachedPerWorker;\n\n const result = new Map<string, WorkerMetricsSummary[]>();\n for (const [uid, aggMap] of this._perWorkerAggregate) {\n const entries: WorkerMetricsSummary[] = [];\n for (const [name, data] of aggMap) {\n entries.push({\n name,\n count: data.count,\n totalMs: data.totalMs,\n avgMs: data.count > 0 ? data.totalMs / data.count : 0,\n minMs: data.minMs,\n maxMs: data.maxMs,\n lastMs: data.lastMs\n });\n }\n entries.sort((a, b) => b.totalMs - a.totalMs);\n result.set(uid, entries);\n }\n this._cachedPerWorker = result;\n this._perWorkerDirty = false;\n return result;\n }\n\n recordQueueSize(size: number): void {\n if (!this._enabled) return;\n this._pendingMaxQueueSize = Math.max(this._pendingMaxQueueSize, size);\n }\n\n recordStalledCount(count: number): void {\n if (!this._enabled) return;\n this._pendingStalledCount = Math.max(this._pendingStalledCount, count);\n }\n\n recordWaitTimes(times: number[]): void {\n if (!this._enabled) return;\n for (const t of times) {\n this._pendingWaitTimes.push(t);\n }\n }\n\n addMetric(workerUid: string, entry: PerformanceTimeEntry): void {\n if (!this._enabled) return;\n const ms = entry.msPassed ?? 0;\n const name = entry.name;\n\n // Aggregate pending\n const existing = this._pendingMetrics.get(name);\n if (existing) {\n existing.totalMs += ms;\n existing.count += 1;\n } else {\n this._pendingMetrics.set(name, { name, totalMs: ms, count: 1 });\n }\n\n // Per-worker pending\n let workerMap = this._perWorkerPending.get(workerUid);\n if (!workerMap) {\n workerMap = new Map();\n this._perWorkerPending.set(workerUid, workerMap);\n }\n const workerExisting = workerMap.get(name);\n if (workerExisting) {\n workerExisting.totalMs += ms;\n workerExisting.count += 1;\n } else {\n workerMap.set(name, { name, totalMs: ms, count: 1 });\n }\n }\n\n addMetrics(workerUid: string, entries: PerformanceTimeEntry[]): void {\n for (const entry of entries) {\n this.addMetric(workerUid, entry);\n }\n }\n\n sample(now?: number): void {\n if (!this._enabled) return;\n const timestamp = now ?? performance.now();\n\n if (\n this._lastSampleTime !== 0 &&\n timestamp - this._lastSampleTime < WorkerPerformanceTracker.SAMPLE_INTERVAL_MS\n ) {\n return;\n }\n\n const metrics = Array.from(this._pendingMetrics.values());\n\n const avgWaitTimeMs =\n this._pendingWaitTimes.length > 0\n ? this._pendingWaitTimes.reduce((s, t) => s + t, 0) / this._pendingWaitTimes.length\n : 0;\n\n const snapshot: WorkerSnapshot = {\n timestamp,\n queueSize: this._pendingMaxQueueSize,\n stalledCount: this._pendingStalledCount,\n avgWaitTimeMs,\n metrics\n };\n\n this._snapshots.push(snapshot);\n if (this._snapshots.length > WorkerPerformanceTracker.MAX_SNAPSHOTS) {\n this._snapshots.shift();\n }\n\n // Merge into aggregate summaries\n this.mergeIntoAggregate(metrics);\n this.mergePerWorkerAggregate();\n\n // Reset pending\n this._pendingMetrics.clear();\n this._perWorkerPending.clear();\n this._pendingMaxQueueSize = 0;\n this._pendingStalledCount = 0;\n this._pendingWaitTimes = [];\n this._lastSampleTime = timestamp;\n }\n\n clear(): void {\n this._snapshots.length = 0;\n this._pendingMetrics.clear();\n this._perWorkerPending.clear();\n this._aggregate.clear();\n this._perWorkerAggregate.clear();\n this._pendingMaxQueueSize = 0;\n this._pendingStalledCount = 0;\n this._pendingWaitTimes = [];\n this._lastSampleTime = 0;\n this._aggregateDirty = true;\n this._perWorkerDirty = true;\n this._cachedSummaries = [];\n this._cachedPerWorker = new Map();\n }\n\n private mergeIntoAggregate(metrics: WorkerMetricEntry[]): void {\n for (const m of metrics) {\n this.mergeEntry(this._aggregate, m.name, m);\n }\n this._aggregateDirty = true;\n }\n\n private mergePerWorkerAggregate(): void {\n for (const [uid, workerMap] of this._perWorkerPending) {\n const aggMap = this.getOrCreateWorkerAgg(uid);\n for (const [name, m] of workerMap) {\n this.mergeEntry(aggMap, name, m);\n }\n }\n this._perWorkerDirty = true;\n }\n\n private getOrCreateWorkerAgg(uid: string): Map<string, AccEntry> {\n let aggMap = this._perWorkerAggregate.get(uid);\n if (!aggMap) {\n aggMap = new Map();\n this._perWorkerAggregate.set(uid, aggMap);\n }\n return aggMap;\n }\n\n private mergeEntry(aggMap: Map<string, AccEntry>, name: string, m: WorkerMetricEntry): void {\n const avg = m.count > 0 ? m.totalMs / m.count : 0;\n const existing = aggMap.get(name);\n if (existing) {\n existing.count += m.count;\n existing.totalMs += m.totalMs;\n existing.minMs = Math.min(avg, existing.minMs);\n existing.maxMs = Math.max(avg, existing.maxMs);\n existing.lastMs = avg;\n } else {\n aggMap.set(name, { count: m.count, totalMs: m.totalMs, minMs: avg, maxMs: avg, lastMs: avg });\n }\n }\n}\n"],"mappings":"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"}