Agent Skills
› lichtblick-suite/lichtblick
› performance
performance
GitHub提供Lichtblick代码库的性能优化指南,涵盖Chrome DevTools剖析流程、常见瓶颈(消息处理、渲染、内存)及零拷贝、对象池等优化模式。
Trigger Scenarios
性能分析与调优
解决卡顿或帧率问题
内存泄漏排查
实时数据可视化性能优化
Install
npx skills add lichtblick-suite/lichtblick --skill performance -g -y
SKILL.md
Frontmatter
{
"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
// Transfer ArrayBuffer to Worker (not copy)
Comlink.transfer({ buffer: myArrayBuffer }, [myArrayBuffer]);
// After transfer, myArrayBuffer.byteLength === 0 (detached)
Object Pooling (3D)
// Reuse Vector3 instances instead of creating new ones
const tempVec = new THREE.Vector3();
function updatePosition(x: number, y: number, z: number) {
tempVec.set(x, y, z);
mesh.position.copy(tempVec);
}
Structural Sharing (State)
// Only create new object if data actually changed
const newMessages = messages !== prevMessages ? [...messages, ...newBatch] : prevMessages;
Debounced Emission
// Coalesce rapid state updates
#scheduleEmit() {
if (this.#emitScheduled) return;
this.#emitScheduled = true;
queueMicrotask(() => {
this.#emitScheduled = false;
this.#emitStateImpl();
});
}
Subscription Filtering
// Only request data for topics panels actually need
const 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
Version History
- cab9317 Current 2026-07-24 12:17


