Skip to content

Keep retained capacity in FrameArray.add(frames:) - #196

Open
rnro wants to merge 1 commit into
apple:mainfrom
rnro:alloc/frame-array-keep-capacity
Open

rnro wants to merge 1 commit into
apple:mainfrom
rnro:alloc/frame-array-keep-capacity

Conversation

@rnro

@rnro rnro commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

A queue drained through drainArrayKeepingCapacity holds an empty buffer on
purpose. Adopting the incoming storage whenever this side is empty threw that
buffer away and took a smaller one, so the next batch reallocated. Adopt the
incoming storage only when this side would otherwise have to grow.

Measured on my Mac against main with the package's QUIC benchmark tools.
Allocation counts come from full malloc stack logging, which records every
allocation:

QUICTransfer -size 1200, per message      24.37 -> 23.38
QUICTransfer, per 500 KB transfer       6,187.6 -> 6,177.1
QUICHandshake, per connection           1,947.4 -> 1,944.9
QUICStreamLoad, per stream                111.8 -> 112.2

The saving depends on timing: it only applies when the queue has drained by the
time the next batch arrives, which happened about once per message here.

Wall-clock time comes from running main, this change and the other changes
measured alongside it in a rotating order for 9 rounds, and comparing each run
with main's in the same round. Changes moved paths they do not touch by up to
about 1.3%, so differences that size count as noise. Nothing changed beyond
noise.

A queue drained through `drainArrayKeepingCapacity` holds an empty buffer on
purpose. Adopting the incoming storage whenever this side is empty threw that
buffer away and took a smaller one, so the next batch reallocated. Adopt the
incoming storage only when this side would otherwise have to grow.

Measured on my Mac against `main` with the package's QUIC benchmark tools.
Allocation counts come from full malloc stack logging, which records every
allocation:

  QUICTransfer -size 1200, per message      24.37 -> 23.38
  QUICTransfer, per 500 KB transfer       6,187.6 -> 6,177.1
  QUICHandshake, per connection           1,947.4 -> 1,944.9
  QUICStreamLoad, per stream                111.8 -> 112.2

The saving depends on timing: it only applies when the queue has drained by the
time the next batch arrives, which happened about once per message here.

Wall-clock time comes from running `main`, this change and the other changes
measured alongside it in a rotating order for 9 rounds, and comparing each run
with `main`'s in the same round. Changes moved paths they do not touch by up to
about 1.3%, so differences that size count as noise. Nothing changed beyond
noise.

@agnosticdev agnosticdev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@rnro rnro added the 🔨 semver/patch No public API change. label Oct 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🔨 semver/patch No public API change.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants