Skip to content

Performance Forensics

lpetronika edited this page Feb 16, 2026 · 6 revisions

Performance Benchmarks & Methodology (v0.6.x)

The main design goal for Basis is to have negligible impact on the host application's main thread, even while maintaining a complex topological graph. This page covers the memory architecture and stress test results for the v0.6.x Graph Engine.

1. Memory Architecture: Hybrid Static/Sparse

Basis uses a hybrid memory model: static buffers for high-frequency signal recording, sparse maps for topological analysis.

A. Signal Storage (Ring Buffers)

To avoid GC pressure during state updates, Basis never creates new objects for signal tracking.

  • Implementation: Pre-allocated Uint8Array ring buffers.
  • Update Mechanism: A rotating head pointer overwrites the oldest data point in $O(1)$. Zero heap allocations during the render cycle.
  • Observed: In a 20-minute endurance test, the memory delta for Uint8Array constructors stayed at 0 bytes.

B. Topology Storage (Sparse Graph & Pruning)

In v0.6, Basis builds a directed graph of all causal links. Since every user interaction creates a unique event node, this graph would grow forever without cleanup. The engine handles this with Lazy Graph Garbage Collection.

  • Implementation: Map<string, Map<string, number>> representing a Sparse Adjacency Matrix.
  • Cleanup: Event nodes older than the interaction window (default 10s) are automatically pruned.
  • Result: The graph size stabilizes around the active interaction context. No memory leaks, even in sessions that run for hours.
image image

Heap Snapshot comparison before and after a 20-minute stress test. The stability of Map and String objects confirms that graph pruning prevents topological memory leaks.

2. Spectral Analysis Benchmarks (The Ranker)

v0.6 introduces Eigenvector Centrality (Power Iteration) to identify "Prime Movers." This is a heavy operation at $O(k \cdot E)$, so it only runs on-demand when you generate a report. It never runs in the background loop.

We benchmarked the ranking algorithm against different graph sizes to make sure it scales linearly.

Baseline (Typical App)

  • Graph Size: 18 nodes
  • Execution Time: ~0.31ms
  • Impact: About 1.8% of a single frame budget. Effectively invisible.
Starting Benchmark on Graph size: 18 nodes...
VM114:38 -----------------------------------
VM114:39 Graph Size: 18 nodes
VM114:40 Total Time (100 runs): 30.70ms
VM114:41 Average Math Latency: 0.3070ms per report
VM114:42 -----------------------------------
image

Extreme Stress (30k Nodes)

  • Graph Size: 29,997 nodes (synthetic torture test)
  • Execution Time: ~27.38ms
  • Impact: Even with a graph larger than most enterprise apps, the analysis finishes in under 30ms. The algorithm scales linearly and doesn't freeze the browser.
benchmarkRanker();
VM580:6 Starting Benchmark on Graph size: 29997 nodes...
VM580:35 -----------------------------------
VM580:36 Graph Size: 29997 nodes
VM580:37 Total Time (100 runs): 2737.90ms
VM580:38 Average Math Latency: 27.3790ms per report
VM580:39 -----------------------------------
image image

3. Execution Scheduling

Basis separates Data Collection from Analysis to protect the frame budget.

  • Sampling (rAF): The heartbeat runs on requestAnimationFrame. State gets sampled at the monitor's native refresh rate.
  • Analysis (rIC): Correlation math and graph traversal run inside requestIdleCallback. The heavy math only happens when the browser has nothing else to do.

4. Computational Efficiency $O(D \times N)$

Instead of comparing every variable against every other variable on every frame ($N^2$), the engine uses Dirty-Set Tracking.

  • How it works: Only variables that updated in the current frame get marked as "dirty."
  • The optimization: Cross-correlation only runs for pairs where at least one variable is dirty. In a typical interaction where 2 hooks update out of 30, this cuts total comparisons by >90%.

5. Measured Impact on Interaction (INP)

Interaction to Next Paint (INP) was measured with Chrome DevTools during a "Burst" stress test (50 concurrent hooks updating at 60 FPS).

Metric Result
Logic Execution per Frame ~0.1ms - 0.3ms
Spectral Analysis (On Demand) ~0.3ms - 9.0ms
Total INP (Under Stress) 48ms
image

Performance trace during a 50-hook simultaneous burst. The 48ms INP means the app stays within the "Good" interaction threshold even under extreme load.

Clone this wiki locally