-
Notifications
You must be signed in to change notification settings - Fork 82
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
Remove unnecessary state CoWs. #104
Conversation
The unfortunate irony here is that the net performance gain of this patch in a more real-world benchmark is pretty small: about 1.5%. The reality is that in that benchmark we just aren't copying too much state around, so the CoWs don't hurt too badly. |
var settingsState = HTTP2SettingsState(localState: true) | ||
settingsState.emitSettings(settings) | ||
self.state = .prefaceSent(.init(fromIdle: state, localSettings: settingsState)) | ||
self.avoidingStateMachineCoW { [] newState in |
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.
mind removing the left-over []
?
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.
It's there on purpose to avoid me ever accidentally capturing in this block.
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.
@Lukasa that doesn't work. [...]
has no effect on things that are not listed
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.
I complain for years that Swift needs a mode where I can specify an exhaustive capture list, but still not there :(
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 only thing [
does is to create a by-value copy of all the listed things, optionally with renaming
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.
Fixed. 😁
Motivation: When benchmarking the HTTP/2 implementation I noticed that we were performing a large number of CoW operations on the Dictionary that backs the ConnectionStreamState structure: specifically, once per frame sent or received. This is substantial and unnecessary allocation overhead that drags down the performance of the program, sprays the heap with small allocations, and generally just leads to nasty performance costs with no gain. Sadly, this turns out not to be the easiest CoW to get rid of, because the ConnectionStreamState structure is stored in associated data on the connection state machine state enumeration. This means that our usual tricks for avoiding the CoW (such as swap()) no longer work. The only solution is to add a new state that corresponds to no state at all so that we can make the connection state go away while we mutate it. This is all a bit gross, frankly. Unfortunately, the act of making this simple change leads to a huge diff as we have to tweak basically every state machine function in order to ensure that it does the right thing. Modifications: - Added a function to control CoWing the state machine. - Used that function basically everywhere. - Made sure that function had assertions. - Annoyingly had to increase the visibility of a bunch of structs. Result: Fewer CoWs, better performance, sadder code reviewers.
36a9df9
to
2af3eb8
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" to me. Cory 1; Swift 0
Oh god, I hope I don't get retained, I don't need a cow. |
It's fine, you just killed a lot of cows. Enjoy 🥩 |
I think in the real world under allocator pressure this could have a much bigger impact. but who knows... |
Indeed, I'm still strongly in favour of removing it: it's just not a really heavy hitter. |
Motivation: This is basically a similar issue to apple#104: we have a CoW data structure (ByteBuffer) in some of these states, and when calling append on them they force an unnecessary CoW. We can reproduce the fix from that patch, which is to define an empty state and swap into it before we run the append. We also define a helper that ensures that we don't screw this up. Modifications: - Added new appending state to HTTP2FrameDecoder - Added helpers for avoiding a CoW - Avoided CoW in HTTP2FrameDecoder. Result: Fewer unnecessary copies
Motivation: This is basically a similar issue to #104: we have a CoW data structure (ByteBuffer) in some of these states, and when calling append on them they force an unnecessary CoW. We can reproduce the fix from that patch, which is to define an empty state and swap into it before we run the append. We also define a helper that ensures that we don't screw this up. Modifications: - Added new appending state to HTTP2FrameDecoder - Added helpers for avoiding a CoW - Avoided CoW in HTTP2FrameDecoder. Result: Fewer unnecessary copies
Motivation:
When benchmarking the HTTP/2 implementation I noticed that we were
performing a large number of CoW operations on the Dictionary that backs
the ConnectionStreamState structure: specifically, once per frame sent or
received.
This is substantial and unnecessary allocation overhead that drags down
the performance of the program, sprays the heap with small allocations, and
generally just leads to nasty performance costs with no gain.
Sadly, this turns out not to be the easiest CoW to get rid of, because
the ConnectionStreamState structure is stored in associated data on the
connection state machine state enumeration. This means that our usual tricks
for avoiding the CoW (such as swap()) no longer work.
The only solution is to add a new state that corresponds to no state at all
so that we can make the connection state go away while we mutate it. This is
all a bit gross, frankly. Unfortunately, the act of making this simple change
leads to a huge diff as we have to tweak basically every state machine
function in order to ensure that it does the right thing.
Modifications:
Result:
Fewer CoWs, better performance, sadder code reviewers.