-
Notifications
You must be signed in to change notification settings - Fork 3
Performance Forensics
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.
Basis uses a hybrid memory model: static buffers for high-frequency signal recording, sparse maps for topological analysis.
To avoid GC pressure during state updates, Basis never creates new objects for signal tracking.
-
Implementation: Pre-allocated
Uint8Arrayring 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
Uint8Arrayconstructors stayed at 0 bytes.
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.
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.
v0.6 introduces Eigenvector Centrality (Power Iteration) to identify "Prime Movers." This is a heavy operation at
We benchmarked the ranking algorithm against different graph sizes to make sure it scales linearly.
- 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 -----------------------------------
- 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 -----------------------------------
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.
Instead of comparing every variable against every other variable on every frame (
- 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%.
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 |
Performance trace during a 50-hook simultaneous burst. The 48ms INP means the app stays within the "Good" interaction threshold even under extreme load.