import type { PerformanceTrack, SetPageVisibility } from '../messages'; import ListWalker from '../../common/ListWalker'; export type PerformanceChartPoint = { time: number; usedHeap: number; totalHeap: number; fps: number | null; cpu: number | null; nodesCount: number; }; export default class PerformanceTrackManager extends ListWalker { private chart: Array = []; private isHidden: boolean = false; private timeCorrection: number = 0; private heapAvailable: boolean = false; private fpsAvailable: boolean = false; private cpuAvailable: boolean = false; private prevTime: number | null = null; private prevNodesCount: number = 0; append(msg: PerformanceTrack): void { let fps: number | null = null; let cpu: number | null = null; if (!this.isHidden && this.prevTime != null) { const timePassed = msg.time - this.prevTime + this.timeCorrection; if (timePassed > 0 && msg.frames >= 0) { if (msg.frames > 0) { this.fpsAvailable = true; } fps = (msg.frames * 1e3) / timePassed; // Multiply by 1e3 as time in ms; fps = Math.min(fps, 60); // What if 120? TODO: alert if more than 60 if (this.chart.length === 1) { this.chart[0].fps = fps; } } if (timePassed > 0 && msg.ticks >= 0) { this.cpuAvailable = true; let tickRate = (msg.ticks * 30) / timePassed; if (tickRate > 1) { tickRate = 1; } cpu = Math.round(100 - tickRate * 100); if (this.chart.length === 1) { this.chart[0].cpu = cpu; } } } this.prevTime = msg.time; this.timeCorrection = 0; this.heapAvailable = this.heapAvailable || msg.usedJSHeapSize > 0; this.chart.push({ usedHeap: msg.usedJSHeapSize, totalHeap: msg.totalJSHeapSize, fps, cpu, time: msg.time, nodesCount: this.prevNodesCount, }); super.append(msg); } // TODO: refactor me private prevNCTime = 0; addNodeCountPointIfNeed(time: number) { if ( (this.prevTime && time - this.prevTime < 200) || time - this.prevNCTime < 200 ) { return; } const lastPoint = this.chart[this.chart.length - 1]; if (lastPoint && lastPoint.nodesCount === this.prevNodesCount) { return; } const newPoint = { usedHeap: 0, totalHeap: 0, fps: null, cpu: null, ...lastPoint, }; newPoint.time = time; newPoint.nodesCount = this.prevNodesCount; this.chart.push(newPoint); this.prevNCTime = time; } setCurrentNodesCount(count: number) { this.prevNodesCount = count; // if (this.chart.length > 0) { // this.chart[ this.chart.length - 1 ].nodesCount = count; // } } handleVisibility(msg: SetPageVisibility): void { if (!this.isHidden && msg.hidden && this.prevTime != null) { this.timeCorrection = msg.time - this.prevTime; } if (this.isHidden && !msg.hidden) { this.prevTime = msg.time; } this.isHidden = msg.hidden; } get chartData(): Array { return this.chart; } get availability(): { cpu: boolean; fps: boolean; heap: boolean; nodes: boolean; } { return { cpu: this.cpuAvailable, fps: this.fpsAvailable, heap: this.heapAvailable, nodes: true, }; } }