summaryrefslogtreecommitdiff
path: root/web-timeplot/src/metrics.js
diff options
context:
space:
mode:
authorgrothedev <grothedev@gmail.com>2025-10-02 20:13:46 -0400
committergrothedev <grothedev@gmail.com>2025-10-02 20:13:46 -0400
commit39124e6854b2740e9f30c058e873355dfd739a4e (patch)
tree5cd1fb7986b1aebbde79ce478ecfc0b077690414 /web-timeplot/src/metrics.js
parent836459dce3f50767d41978be4a2f7ac788e6a9ba (diff)
starting with pixijs implementation
Diffstat (limited to 'web-timeplot/src/metrics.js')
-rw-r--r--web-timeplot/src/metrics.js142
1 files changed, 142 insertions, 0 deletions
diff --git a/web-timeplot/src/metrics.js b/web-timeplot/src/metrics.js
new file mode 100644
index 0000000..fdda10a
--- /dev/null
+++ b/web-timeplot/src/metrics.js
@@ -0,0 +1,142 @@
+/**
+ * RollingAverage - Maintains a rolling window of values for smooth averaging
+ */
+class RollingAverage {
+ constructor(capacity) {
+ this.values = [];
+ this.capacity = capacity;
+ this.sum = 0;
+ }
+
+ push(value) {
+ if (this.values.length >= this.capacity) {
+ const old = this.values.shift();
+ this.sum -= old;
+ }
+ this.values.push(value);
+ this.sum += value;
+ }
+
+ average() {
+ return this.values.length > 0 ? this.sum / this.values.length : 0;
+ }
+
+ min() {
+ return this.values.length > 0 ? Math.min(...this.values) : 0;
+ }
+
+ max() {
+ return this.values.length > 0 ? Math.max(...this.values) : 0;
+ }
+}
+
+/**
+ * PerformanceMetrics - Tracks and analyzes frame performance
+ */
+export class PerformanceMetrics {
+ constructor(rollingWindow = 60, historyCapacity = 10000) {
+ // Rolling averages
+ this.frameTime = new RollingAverage(rollingWindow);
+ this.updateTime = new RollingAverage(rollingWindow);
+ this.renderTime = new RollingAverage(rollingWindow);
+ this.vertexCount = new RollingAverage(rollingWindow);
+ this.lineCount = new RollingAverage(rollingWindow);
+
+ // History for export
+ this.history = [];
+ this.historyCapacity = historyCapacity;
+
+ // Frame timing
+ this.frameStart = 0;
+ this.updateStart = 0;
+ this.renderStart = 0;
+
+ this.totalFrames = 0;
+ }
+
+ beginFrame() {
+ this.frameStart = performance.now();
+ }
+
+ beginUpdate() {
+ this.updateStart = performance.now();
+ }
+
+ endUpdate() {
+ const duration = performance.now() - this.updateStart;
+ return duration;
+ }
+
+ beginRender() {
+ this.renderStart = performance.now();
+ }
+
+ endRender() {
+ const duration = performance.now() - this.renderStart;
+ return duration;
+ }
+
+ endFrame(updateMs, renderMs, vertexCount, lineCount) {
+ const totalMs = performance.now() - this.frameStart;
+
+ // Update rolling averages
+ this.frameTime.push(totalMs);
+ this.updateTime.push(updateMs);
+ this.renderTime.push(renderMs);
+ this.vertexCount.push(vertexCount);
+ this.lineCount.push(lineCount);
+
+ // Store in history
+ const record = {
+ frame: this.totalFrames,
+ totalMs,
+ updateMs,
+ renderMs,
+ vertexCount,
+ lineCount,
+ fps: totalMs > 0 ? 1000 / totalMs : 0,
+ };
+
+ if (this.history.length >= this.historyCapacity) {
+ this.history.shift();
+ }
+ this.history.push(record);
+
+ this.totalFrames++;
+ }
+
+ getFPS() {
+ const avg = this.frameTime.average();
+ return avg > 0 ? 1000 / avg : 0;
+ }
+
+ getMinFPS() {
+ const max = this.frameTime.max();
+ return max > 0 ? 1000 / max : 0;
+ }
+
+ getMaxFPS() {
+ const min = this.frameTime.min();
+ return min > 0 ? 1000 / min : 0;
+ }
+
+ formatSummary() {
+ return `FPS: ${this.getFPS().toFixed(1)} (min: ${this.getMinFPS().toFixed(1)}, max: ${this.getMaxFPS().toFixed(1)}) | ` +
+ `Frame: ${this.frameTime.average().toFixed(2)}ms | ` +
+ `Update: ${this.updateTime.average().toFixed(2)}ms | ` +
+ `Render: ${this.renderTime.average().toFixed(2)}ms | ` +
+ `Vertices: ${Math.round(this.vertexCount.average())} | ` +
+ `Lines: ${Math.round(this.lineCount.average())}`;
+ }
+
+ exportToCSV() {
+ let csv = 'frame,total_ms,update_ms,render_ms,vertex_count,line_count,fps\n';
+
+ for (const record of this.history) {
+ csv += `${record.frame},${record.totalMs},${record.updateMs},${record.renderMs},` +
+ `${record.vertexCount},${record.lineCount},${record.fps}\n`;
+ }
+
+ return csv;
+ }
+}