We’ve been developing several large and relatively heavy apps using ZIM, and as projects grow in complexity, it’s becoming more and more important for us to understand how our apps perform in real time.
Right now, ZIM’s Meter is great for showing FPS — but we’d love to have a more complete Performance Monitor built into ZIM.
Specifically, something that could help developers visualize and track:
- Memory usage (total, used, and maybe texture or asset memory)
- CPU or processing load (if possible to estimate via JS metrics)
- Number of active DisplayObjects / assets
- Frame render time or event loop performance
- Any other helpful performance stats accessible via JavaScript
It could be similar to a small overlay panel (like the current Meter), but switchable between “FPS view” and “Performance view”, or perhaps a modular debug dashboard developers can enable during testing.
This would help us identify performance bottlenecks, optimize memory usage, and keep our apps stable, especially on lower-end devices.
Thanks a lot for considering this — it would make a huge difference for developers working with large ZIM-based apps!
2 Likes
That's a great idea, @amihanya. If anyone has suggestions as to how this can be handled, or would like to work on parts or all of it, let us know and we can coordinate. We do have 019 coming up, so this could be part of that.
Maybe there’s a way to get a list of all the intervals that are running?
That’s what would have helped me with the bug I had.
I asked GPT, and this is what it created for me—definitely useful!
// PerformanceTools.js
class PerformanceTools {
constructor(stage, options = {}) {
this.stage = stage;
this.memoryHistory = [];
this.objectCounts = [];
this.listenersCount = [];
this.snapshots = [];
this.interval = options.interval || 2000; // מדידה כל 2 שניות
this.maxHistory = options.maxHistory || 50;
this._initOverlay();
this._startMonitoring();
}
// ----- יצירת overlay -----
_initOverlay() {
this.overlay = new zim.Container(this.stage);
this.overlay.addTo(this.stage);
this.overlay.setBounds(0,0,200,100);
this.overlay.x = 10;
this.overlay.y = 10;
this.fpsText = new zim.Label({text:"FPS: ", font:"14px Arial", color:"white"}).addTo(this.overlay).pos(0,0);
this.memoryText = new zim.Label({text:"Memory: ", font:"14px Arial", color:"white"}).addTo(this.overlay).pos(0,20);
this.objectsText = new zim.Label({text:"Objects: ", font:"14px Arial", color:"white"}).addTo(this.overlay).pos(0,40);
this.listenersText = new zim.Label({text:"Listeners: ", font:"14px Arial", color:"white"}).addTo(this.overlay).pos(0,60);
// אפשרות snapshot בלחיצה
this.overlay.on("click", ()=>this.takeSnapshot());
}
// ----- התחלת ניטור -----
_startMonitoring() {
this.lastFrame = performance.now();
this.fps = 0;
this.monitorInterval = setInterval(()=>{
this._updateMemory();
this._updateObjects();
this._updateListeners();
this._updateFPS();
this._updateOverlay();
}, this.interval);
// FPS בכל frame
this.stage.on("enterframe", ()=>{
let now = performance.now();
this.fps = Math.round(1000 / (now - this.lastFrame));
this.lastFrame = now;
});
}
// ----- עדכון מדדי זיכרון -----
_updateMemory() {
if(performance.memory){
const used = performance.memory.usedJSHeapSize / 1024 / 1024;
this.memoryHistory.push(used);
if(this.memoryHistory.length > this.maxHistory) this.memoryHistory.shift();
}
}
// ----- ספירת אובייקטים -----
_countObjects(container){
let count = 1; // עצמה
if(container.children){
container.children.forEach(child=>{
count += this._countObjects(child);
});
}
return count;
}
_updateObjects() {
const totalObjects = this._countObjects(this.stage);
this.objectCounts.push(totalObjects);
if(this.objectCounts.length > this.maxHistory) this.objectCounts.shift();
}
// ----- ניטור מאזינים (פשוטה - דוגמה) -----
_updateListeners() {
// בדיקה בסיסית - אפשר להרחיב לפי הצורך
this.listenersCount.push(0); // אפשר למלא פה ספירה אמיתית אם מוסיפים track בכל אירוע
if(this.listenersCount.length > this.maxHistory) this.listenersCount.shift();
}
// ----- עדכון FPS -----
_updateFPS() {
// כבר מתעדכן ב-enterframe
}
// ----- עדכון overlay -----
_updateOverlay() {
this.fpsText.text = "FPS: " + this.fps;
const mem = this.memoryHistory.length ? this.memoryHistory[this.memoryHistory.length-1].toFixed(2) : "?";
this.memoryText.text = "Memory: " + mem + " MB";
const objs = this.objectCounts.length ? this.objectCounts[this.objectCounts.length-1] : "?";
this.objectsText.text = "Objects: " + objs;
const listeners = this.listenersCount.length ? this.listenersCount[this.listenersCount.length-1] : "?";
this.listenersText.text = "Listeners: " + listeners;
}
// ----- Snapshot -----
takeSnapshot() {
const snapshot = {
time: new Date(),
memory: this.memoryHistory.slice(),
objects: this.objectCounts.slice(),
listeners: this.listenersCount.slice()
};
this.snapshots.push(snapshot);
console.log("Snapshot taken:", snapshot);
}
// ----- עצירה -----
stop() {
clearInterval(this.monitorInterval);
}
}
and this is how you use it:
new PerformanceTools(S, {interval:2000});
Cool - thanks - will try it out. Definitely looks like we will be able to add these to ZIM 019. Cheers.