Files
brittle/src-tauri/assets/viewer/performance-manager.js
2026-04-01 01:27:51 +02:00

115 lines
4.1 KiB
JavaScript

// performance-manager.ts — Performance monitoring and optimization system
// TypeScript rewrite with proper type safety
class PerformanceManager {
constructor() {
this.frameTimes = [];
this.maxFrameHistory = 60;
this.lastFrameTime = 0;
this.fps = 60;
this.memoryWarnings = 0;
this.renderQuality = 1.0;
this.adaptiveMode = false;
this.setupMonitoring();
}
setupMonitoring() {
let lastTime = performance.now();
let frameCount = 0;
const monitorLoop = (currentTime) => {
frameCount++;
if (frameCount % 10 === 0) {
const delta = currentTime - lastTime;
const avgFrameTime = delta / 10;
this.fps = Math.round(1000 / avgFrameTime);
this.frameTimes.push(avgFrameTime);
if (this.frameTimes.length > this.maxFrameHistory) {
this.frameTimes.shift();
}
this.analyzePerformance();
lastTime = currentTime;
}
requestAnimationFrame(monitorLoop);
};
requestAnimationFrame(monitorLoop);
if (window.performance && performance.memory) {
setInterval(() => this.checkMemory(), 2000);
}
}
analyzePerformance() {
if (this.frameTimes.length < 10)
return;
const sorted = [...this.frameTimes].sort((a, b) => a - b);
const avgFrameTime = sorted.reduce((a, b) => a + b, 0) / sorted.length;
const p90FrameTime = sorted[Math.floor(sorted.length * 0.9)];
const frameBudget = 16; // 16ms for 60fps
if (p90FrameTime > frameBudget * 1.5) {
this.setRenderQuality(Math.max(0.5, this.renderQuality - 0.2));
this.adaptiveMode = true;
}
else if (p90FrameTime > frameBudget * 1.2) {
this.setRenderQuality(Math.max(0.7, this.renderQuality - 0.1));
}
else if (avgFrameTime < frameBudget * 0.8 && this.adaptiveMode) {
this.setRenderQuality(Math.min(1.0, this.renderQuality + 0.05));
if (this.renderQuality >= 0.95) {
this.adaptiveMode = false;
}
}
}
checkMemory() {
try {
// Use type assertion for non-standard memory API
const perf = performance;
const memory = perf.memory;
if (!memory) {
throw new Error('Memory API not available');
}
const usedHeap = memory.usedJSHeapSize;
const heapLimit = memory.jsHeapSizeLimit;
const usageRatio = usedHeap / heapLimit;
if (usageRatio > 0.8) {
this.memoryWarnings++;
if (this.memoryWarnings > 3) {
this.triggerMemoryCleanup();
this.memoryWarnings = 0;
}
this.setRenderQuality(Math.max(0.6, this.renderQuality - 0.1));
}
else {
this.memoryWarnings = Math.max(0, this.memoryWarnings - 0.5);
}
}
catch (e) {
console.warn('Memory monitoring not available:', e);
}
}
triggerMemoryCleanup() {
if (window.gc) {
window.gc();
}
}
setRenderQuality(quality) {
this.renderQuality = Math.max(0.3, Math.min(1.0, quality));
console.debug(`[Perf] Render quality adjusted to: ${(this.renderQuality * 100).toFixed(0)}%`);
}
getCurrentQuality() {
return this.renderQuality;
}
isPerformanceCritical() {
return this.adaptiveMode || this.fps < 45;
}
getPerformanceStats() {
return {
fps: this.fps,
avgFrameTime: this.frameTimes.length > 0
? this.frameTimes.reduce((a, b) => a + b, 0) / this.frameTimes.length
: 0,
renderQuality: this.renderQuality,
adaptiveMode: this.adaptiveMode
};
}
cleanup() {
this.frameTimes = [];
}
}
export { PerformanceManager };
//# sourceMappingURL=performance-manager.js.map