Skip to content

Reuse the encoder analysis scratch buffers - #211

Merged
thomas-vilte merged 1 commit into
pion:mainfrom
thomas-vilte:perf/encoder-allocs
Aug 13, 2026
Merged

Reuse the encoder analysis scratch buffers#211
thomas-vilte merged 1 commit into
pion:mainfrom
thomas-vilte:perf/encoder-allocs

Conversation

@thomas-vilte

Copy link
Copy Markdown
Member

Description

EncodeFrame was allocating 15 buffers and 11 KB per frame. At 50 frames per second, that's approximately 550 KB/s of garbage per stream, and the encoder's hot path had zero allocations before I touched it: the pitch search and tf_analysis ports broke it.

Profiling the stereo frame, the allocations came from:

origin part
bandEncodeState.floatScratch 46%
celtLPC 17%
pitchSearch 14%
tfAnalysis 11%
removeDoubling 4%

These are all bounded buffers that can be resized once. This PR adds encoderScratch—the same pattern as the decoderScratch already present in synthesis.go—and gives the band state its own persistent scratch instead of starting it null at the beginning of each frame.

The sizes are outside the limits of the mode, not the run: the worst case of pitchSearch is the window decimated by four, that of tfAnalysis is the widest band at the longest frame, and that of removeDoubling is half the maximum period of the comb filter.

Measurement

before after
mono 11185 B, 15 allocs 0 B, 0 allocs
estéreo 11185 B, 15 allocs 0 B, 0 allocs

The frame time doesn't change appreciably (320 µs stereo before and after on this machine); what changes is the pressure on the GC.

Nothing else changes

The output is byte by byte identical to that of main: I compared the decoded PCM of 60 seconds of music at 96 kb/s CBR and 24 kb/s VBR, and the files are the same. Reusing memory is precisely the type of change where an uncleaned buffer silently alters the result, so the check is the key: celtLPC and the correlation accumulator of pitchSearch are explicitly cleaned because their code assumes a zero starting state; the rest is written entirely before being read.

Reference issue

Part of #34.

@thomas-vilte
thomas-vilte requested a review from FrantaBOT August 13, 2026 18:48
@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.16%. Comparing base (d371ab7) to head (904f981).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #211   +/-   ##
=======================================
  Coverage   93.16%   93.16%           
=======================================
  Files          58       58           
  Lines       10476    10481    +5     
=======================================
+ Hits         9760     9765    +5     
  Misses        505      505           
  Partials      211      211           
Flag Coverage Δ
go 93.16% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@thomas-vilte
thomas-vilte merged commit c1f0a53 into pion:main Aug 13, 2026
20 checks passed
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.

2 participants