Skip to content

utils: cut ParallelExec per-call allocations#1664

Merged
boks1971 merged 1 commit into
mainfrom
parallel-exec-lowalloc
Jul 12, 2026
Merged

utils: cut ParallelExec per-call allocations#1664
boks1971 merged 1 commit into
mainfrom
parallel-exec-lowalloc

Conversation

@boks1971

@boks1971 boks1971 commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Human note:

The biggest impact for this would be live stream kind of cases where the fan out exceeds the threshold. Should be a good win for those cases in terms on reducing GC pressure.

Summary

ParallelExec runs on hot fan-out paths — most notably the SFU downtrack broadcast, which calls it once per forwarded packet. Its parallel branch allocated ~16 objects / ~1.1 KB per call:

  • atomic.NewUint64(0) — a heap-allocated counter,
  • an escaping sync.WaitGroup,
  • one funcval per spawned goroutine (each go func(){…}() on a generic function also carries the type dictionary).

At broadcast rates this is a steady source of garbage and GC pressure.

Change

Hoist all shared state (vals, fn, step, end, the atomic counter, the WaitGroup) into a single parallelState struct, and spawn a single reused worker funcval (a method value bound once) instead of a fresh closure per goroutine. A parallel call now allocates just that struct plus the one worker funcval.

The goroutine work-stealing model, step semantics, and observable behavior are unchangedfn is still invoked exactly once per element, and the serial path (below parallelThreshold) is untouched.

Benchmark

BenchmarkParallelExec, NumCPU=14, ~0.2 µs/item, 3 runs each (before → after):

case ns/op B/op allocs/op
single / fanout 50 8.54µs → 8.41µs 1144 → 104 16 → 2
single / fanout 200 23.16µs → 23.49µs 1144 → 104 16 → 2
concurrent / fanout 50 3.81µs → 3.63µs 1144 → 104 16 → 2
concurrent / fanout 200 14.56µs → 14.43µs 1144 → 104 16 → 2

Latency is unchanged within noise (marginally faster in 3 of 4 cases); allocations drop ~87% and allocated bytes ~91%, cutting GC pressure proportionally to the fan-out call rate.

Tests

  • Existing TestParallel (element coverage) still passes.
  • Added TestParallelExecConcurrent: 8 concurrent callers × 300 iterations, verifying every element is visited exactly once — passes under -race.

🤖 Generated with Claude Code

@changeset-bot

changeset-bot Bot commented Jul 12, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 9fb81ef

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

ParallelExec is on hot fan-out paths (e.g. the SFU downtrack broadcast,
one call per forwarded packet). The parallel branch allocated ~16 objects
/ ~1.1KB per call: a heap atomic counter, an escaping WaitGroup, and one
funcval per spawned goroutine (each carrying the generic type dictionary).

Hoist all shared state into a single struct and spawn a single reused
worker funcval (a method value bound once), so a parallel call allocates
just the struct plus that funcval. The goroutine work-stealing model,
step semantics, and behavior are unchanged.

Benchmark (NumCPU=14, ~0.2us/item, 3 runs; before -> after):

  single/f50        8.54us -> 8.41us   1144B/16 -> 104B/2 allocs
  single/f200      23.16us -> 23.49us  1144B/16 -> 104B/2 allocs
  concurrent/f50    3.81us ->  3.63us  1144B/16 -> 104B/2 allocs
  concurrent/f200  14.56us -> 14.43us  1144B/16 -> 104B/2 allocs

Latency is unchanged within noise; allocations drop ~87% and bytes ~91%,
reducing GC pressure proportionally to the fan-out call rate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@boks1971 boks1971 force-pushed the parallel-exec-lowalloc branch from ddd8fbf to 9fb81ef Compare July 12, 2026 08:41
@boks1971 boks1971 requested a review from a team July 12, 2026 08:42
@boks1971 boks1971 merged commit 8a3c109 into main Jul 12, 2026
10 checks passed
@boks1971 boks1971 deleted the parallel-exec-lowalloc branch July 12, 2026 08:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants