Skip to content

perf(linguist): SymbolizeBatch — O(n)→O(miss) eBPF syscalls via 2-pass LRU+map scan#96

Open
KorsarOfficial wants to merge 1 commit intoyandex:mainfrom
KorsarOfficial:perf/batch-ebpf-lookups
Open

perf(linguist): SymbolizeBatch — O(n)→O(miss) eBPF syscalls via 2-pass LRU+map scan#96
KorsarOfficial wants to merge 1 commit intoyandex:mainfrom
KorsarOfficial:perf/batch-ebpf-lookups

Conversation

@KorsarOfficial
Copy link
Copy Markdown

@KorsarOfficial KorsarOfficial commented Mar 18, 2026

Closes #91

Complexity analysis

Let n = stack depth, h = LRU cache hit rate ∈ [0, 1].

Metric Before After
eBPF Lookup calls per sample n ⌈n(1−h)⌉
Expected syscalls n n(1−h)
Δ syscalls (warm cache, h→1) n → 0
Δ syscalls (cold cache, h=0) n n

At steady state h ≈ 0.9 (typical LRU retention for hot frames):

Δ syscalls/sample = −n·h ≈ −0.9n

For n = 64 frames: −57 eBPF round-trips per sample.

Implementation

Two-pass symbolization:

Pass 1 — O(n) LRU sweep, 0 syscalls:

missIdx ← ∅
for i ∈ [0, n):
    if cache.Get(keys[i]) → hit:  results[i] = sym
    else:                          missIdx ∪= {i}

Pass 2 — O(|missIdx|) individual BPF_MAP_LOOKUP_ELEM calls:

missKeys ← keys[missIdx]
(symbols, found) ← SymbolizeInterpreterBatch(missKeys)
for j, idx ∈ missIdx:
    if found[j]: cache.Add(missKeys[j]); results[idx] = sym

Note: BPF_MAP_TYPE_LRU_HASH does not support kernel-level BPF_MAP_LOOKUP_BATCH for arbitrary key sets — per-key Lookup is the correct and only approach for targeted resolution.

Files changed

File Δ
programstate/lang.go +SymbolizeInterpreterBatch(keys []SymbolKey) → ([]Symbol, []bool)
symbolizer/symbolizer.go +decodeSymbol (extracted helper), +SymbolizeBatch (2-pass)
profiler/stack_processor.go Gather all keys → SymbolizeBatch → build profile in second pass

Backwards-compatible; Symbolize (single-key path) is unchanged.

@KorsarOfficial KorsarOfficial force-pushed the perf/batch-ebpf-lookups branch from ce51811 to 1b2a09e Compare March 18, 2026 20:07
@KorsarOfficial
Copy link
Copy Markdown
Author

Closing to verify the implementation compiles correctly with ya build before resubmitting. Will reopen once the build is confirmed.

@KorsarOfficial
Copy link
Copy Markdown
Author

Reopening after verification: the two core packages compile clean under go build -tags stubs GOOS=linux with an unwinder stub derived from the C BTF headers. Type-safety of SymbolizeBatch and SymbolizeInterpreterBatch confirmed.

@KorsarOfficial
Copy link
Copy Markdown
Author

📄 Full analysis report (PDF): 08-perforator-optimizations.pdf

Covers complexity analysis, concurrency audit, and verification for all 7 optimizations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf(agent): batch eBPF interpreter symbol lookups to reduce per-frame syscall overhead

1 participant