-
Notifications
You must be signed in to change notification settings - Fork 84
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
Improve bulk stream teardown. #261
Conversation
4d69e08
to
39ace2d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
let freeSpace = self.effectiveCapacity - self.count | ||
|
||
if newElementCount >= self.effectiveCapacity { | ||
// We need to completely replace the storage, and then only insert `self.capacity` elements. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// We need to completely replace the storage, and then only insert `self.capacity` elements. | |
// We need to completely replace the storage, and then only insert `self.effectiveCapacity` elements. |
Sources/NIOHTTP2/StreamMap.swift
Outdated
} | ||
} | ||
|
||
// ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a confidence inspiring comment!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hah! I left that for myself when I was unsure if the logic was quite right. I convinced myself it was.
Motivation: The logic for doing bulk stream teardown in the ConnectionStreamsState was always a bit janky: we'd grab all the stream IDs out of the map, filter out anything that was too small, insert them one-by-one into a circular buffer, and then report back. I basically just translated that directly into StreamMap, but on StreamMap this potentially performs very poorly, as attempting to find the pivot point becomes a linear scan through the stream data even when there are _loads_ of streams. This patch swaps over to add a specialized function for bulk-removal of streams. The specialized function passes the slice of data to be removed to the caller so that they can compute on it. It does this by a closure to try to avoid a CoW where possible. While we're here I tried to address the loop over the CircularBuffer of recently reset streams. This flushed out an awkward bug that has existed in our recently reset streams logic for a very long time, which is that while we _tried_ to maintain the size of the circular buffer, in practice we misunderstood the CircularBuffer invariants and so this never worked. I've added a bunch of unit tests for that logic and fixed it up. These two changes together will improve performance in stream bulk teardown. This is an uncommon case (it only happens on GOAWAY), but it's still good to make that faster. Modifications: - New operation on StreamMap - New prependWithoutExpanding(contentsOf:) operation - Unit tests for the circular buffer and stream map logic. Result: Better performance on bulk stream teardown.
39ace2d
to
06a2cb7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good.
case .server: | ||
let index = self.serverInitiated.findIndexForFirstStreamIDLargerThan(streamID) | ||
block(self.serverInitiated[index...]) | ||
self.serverInitiated.removeSubrange(index...) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The duplication in places like this does look pretty sad.
Motivation:
The logic for doing bulk stream teardown in the ConnectionStreamsState
was always a bit janky: we'd grab all the stream IDs out of the map,
filter out anything that was too small, insert them one-by-one into a
circular buffer, and then report back. I basically just translated that
directly into StreamMap, but on StreamMap this potentially performs very
poorly, as attempting to find the pivot point becomes a linear scan
through the stream data even when there are loads of streams.
This patch swaps over to add a specialized function for bulk-removal of
streams. The specialized function passes the slice of data to be removed
to the caller so that they can compute on it. It does this by a closure
to try to avoid a CoW where possible.
While we're here I tried to address the loop over the CircularBuffer of
recently reset streams. This flushed out an awkward bug that has existed
in our recently reset streams logic for a very long time, which is that
while we tried to maintain the size of the circular buffer, in
practice we misunderstood the CircularBuffer invariants and so this
never worked. I've added a bunch of unit tests for that logic and fixed
it up.
These two changes together will improve performance in stream bulk
teardown. This is an uncommon case (it only happens on GOAWAY), but it's
still good to make that faster.
Modifications:
Result:
Better performance on bulk stream teardown. Improves instructions executed in the stream teardown benchmark by 0.2%.