<< All versions
Skill v1.0.1
currentAutomated scan100/100lichtblick-suite/lichtblick/performance
+3 new
──Details
PublishedAugust 18, 2026 at 11:05 PM
Content Hashsha256:55e1e504a6e6a5cc...
Git SHA355014d99402
Bump Typepatch
──Files
Files (1 file, 4.4 KB)
SKILL.md4.4 KBactive
SKILL.md · 122 lines · 4.4 KB
version: "1.0.1" name: "performance" description: "Deep performance optimization knowledge for the Lichtblick codebase. Covers profiling techniques, common bottlenecks, memory management patterns, and optimization strategies specific to real-time data visualization."
Performance Skill
Profiling Workflow
Chrome DevTools
- Performance tab: Record during playback, look for long tasks (>50ms)
- Memory tab: Take heap snapshots before/after operations, check for leaks
- Performance Monitor: Watch JS heap size, DOM nodes, layouts/sec in real-time
- Layers panel: Identify unnecessary compositing layers (GPU memory)
Key Metrics
- Frame budget: 16.6ms at 60fps — anything longer causes jank
- Tick budget: IterablePlayer caps at 300ms per tick
- GC pressure: Frequent minor GCs indicate excessive allocation
- Transfer size: Transferable objects (ArrayBuffer) should use zero-copy transfer
Common Bottlenecks
1. Message Processing (Player → Pipeline)
- Symptom: Dropped frames during high-rate playback
- Cause: Too many messages per tick, deserialization cost
- Fix: Batch processing, Worker-based deserialization, subscription filtering
2. Render State Building (Pipeline → Panel)
- Symptom: All panels re-render even when their data hasn't changed
- Cause: Missing memoization in
renderState.ts, non-stable references - Fix: Ensure
buildRenderStatereturns same reference when data unchanged
3. 3D Scene Updates (Panel rendering)
- Symptom: Low FPS in 3D panel with many objects
- Cause: Per-frame geometry creation, excessive draw calls
- Fix:
DynamicBufferGeometryreuse, instanced rendering, frustum culling
4. Chart Rendering (Plot panel)
- Symptom: Plot panel laggy with many data points
- Cause: Chart.js processing 50k+ points on main thread
- Fix: Worker-based dataset building (50k cap per series), OffscreenCanvas
5. Memory Pressure (Caching)
- Symptom: Browser tab crashes or becomes unresponsive
- Cause: Cache exceeds budget, large messages retained
- Fix: Respect the 600MB player-level message cache budget (
CachingIterableSource), evict behind read head, lazy deserialization. Note: this is separate from the 500MB default HTTP-layer cache inRemoteFileReadable/CachedFilelikeused for remote file reads.
Optimization Patterns
Zero-Copy Transfer
typescript
// Transfer ArrayBuffer to Worker (not copy)Comlink.transfer({ buffer: myArrayBuffer }, [myArrayBuffer]);// After transfer, myArrayBuffer.byteLength === 0 (detached)
Object Pooling (3D)
typescript
// Reuse Vector3 instances instead of creating new onesconst tempVec = new THREE.Vector3();function updatePosition(x: number, y: number, z: number) {tempVec.set(x, y, z);mesh.position.copy(tempVec);}
Structural Sharing (State)
typescript
// Only create new object if data actually changedconst newMessages = messages !== prevMessages ? [...messages, ...newBatch] : prevMessages;
Debounced Emission
typescript
// Coalesce rapid state updates#scheduleEmit() {if (this.#emitScheduled) return;this.#emitScheduled = true;queueMicrotask(() => {this.#emitScheduled = false;this.#emitStateImpl();});}
Subscription Filtering
typescript
// Only request data for topics panels actually needconst activeTopics = mergeSubscriptions(allPanelSubscriptions);player.setSubscriptions(activeTopics); // Player only iterates these
Memory Management
Identifying Leaks
- Take heap snapshot A (baseline)
- Perform operation (open/close panel, play/seek)
- Force GC (DevTools → Memory → Collect garbage)
- Take heap snapshot B
- Compare: Objects in B not in A = potential leaks
Common Leak Sources
- Unremoved event listeners (especially on
windowordocument) - Unreleased Comlink proxies (Worker not disposed)
- Retained message references in closed panels
- Subscription callbacks not unsubscribed on unmount
Prevention
FinalizationRegistryfor Worker proxy cleanup (seeComlinkWrap)useEffectcleanup functions for all subscriptionsWeakRef/WeakMapfor caches that shouldn't prevent GC- Explicit
.dispose()calls in panel unmount
Benchmarking
- Project benchmark suite:
benchmark/directory - Run:
cd benchmark && yarn start - Measures: message throughput, deserialization speed, render time
- Use for before/after comparison when optimizing