Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a coalescing writer #1537

Merged
merged 1 commit into from
Dec 21, 2022
Merged

Add a coalescing writer #1537

merged 1 commit into from
Dec 21, 2022

Conversation

glbrntt
Copy link
Collaborator

@glbrntt glbrntt commented Dec 20, 2022

Motivation:

Creating frames in HTTP/2 isn't free: they incur one allocation for the frame payload and another for the data buffer. In addition to this HTTP/2 currently creates a promise per write, so we also have an additional write promise. On top of the allocations we have the repeated work for processing extra frames.

We can recover much of this cost by coalescing writes before a flush. For streaming RPCs this can have a fairly significant impact.

Modifications:

  • Add a coalescing length prefixed writer: serialized messages are appended and length prefixing (and compression) is done lazily on calls to next().
  • Add an internal 'one-or-many' queue which is a FIFO queue backed by either a single element on the stack or a deque. This avoids allocating a queue on the heap for the length prefixed writer when there is only one message appended before flushing.

Result:

Nothing changes yet, but we have a writer in place which we can adopt later.

@glbrntt glbrntt added the 🔨 semver/patch No public API change. label Dec 20, 2022
Motivation:

Creating frames in HTTP/2 isn't free: they incur one allocation for the
frame payload and another for the data buffer. In addition to this
HTTP/2 currently creates a promise per write, so we also have an
additional write promise. On top of the allocations we have the repeated
work for processing extra frames.

We can recover much of this cost by coalescing writes before a flush.
For streaming RPCs this can have a fairly significant impact.

Modifications:

- Add a coalescing length prefixed writer: serialized messages are
  appended and length prefixing (and compression) is done lazily on
  calls to `next()`.
- Add an internal 'one-or-many' queue which is a FIFO queue backed by
  either a single element on the stack or a deque. This avoids
  allocating a queue on the heap for the length prefixed writer when
  there is only one message appended before flushing.

Result:

Nothing changes yet, but we have a writer in place which we can adopt
later.
@glbrntt glbrntt force-pushed the gb-coalescing-writer branch from 0ff2fe9 to fbf33b4 Compare December 20, 2022 17:00
@glbrntt glbrntt requested a review from FranzBusch December 20, 2022 17:00
Copy link
Collaborator

@FranzBusch FranzBusch left a comment

Choose a reason for hiding this comment

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

LGTM! Can't wait to see how it slots into the current writing path.

@glbrntt glbrntt merged commit e710507 into grpc:main Dec 21, 2022
@glbrntt glbrntt deleted the gb-coalescing-writer branch December 21, 2022 11:34
WendellXY pushed a commit to sundayfun/grpc-swift that referenced this pull request Aug 24, 2023
Motivation:

Creating frames in HTTP/2 isn't free: they incur one allocation for the
frame payload and another for the data buffer. In addition to this
HTTP/2 currently creates a promise per write, so we also have an
additional write promise. On top of the allocations we have the repeated
work for processing extra frames.

We can recover much of this cost by coalescing writes before a flush.
For streaming RPCs this can have a fairly significant impact.

Modifications:

- Add a coalescing length prefixed writer: serialized messages are
  appended and length prefixing (and compression) is done lazily on
  calls to `next()`.
- Add an internal 'one-or-many' queue which is a FIFO queue backed by
  either a single element on the stack or a deque. This avoids
  allocating a queue on the heap for the length prefixed writer when
  there is only one message appended before flushing.

Result:

Nothing changes yet, but we have a writer in place which we can adopt
later.
pinlin168 pushed a commit to sundayfun/grpc-swift that referenced this pull request Aug 24, 2023
Motivation:

Creating frames in HTTP/2 isn't free: they incur one allocation for the
frame payload and another for the data buffer. In addition to this
HTTP/2 currently creates a promise per write, so we also have an
additional write promise. On top of the allocations we have the repeated
work for processing extra frames.

We can recover much of this cost by coalescing writes before a flush.
For streaming RPCs this can have a fairly significant impact.

Modifications:

- Add a coalescing length prefixed writer: serialized messages are
  appended and length prefixing (and compression) is done lazily on
  calls to `next()`.
- Add an internal 'one-or-many' queue which is a FIFO queue backed by
  either a single element on the stack or a deque. This avoids
  allocating a queue on the heap for the length prefixed writer when
  there is only one message appended before flushing.

Result:

Nothing changes yet, but we have a writer in place which we can adopt
later.
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.

2 participants