Save slicing HTTP 2 headers & data#13783
Conversation
|
@normanmaurer I'm not quite sure i could reuse the promise, so please take a look if I'm not assuming anything wrong... The cutoff value has been decided by summing the required bytes for both a new sliced buffer (around 40 bytes ) + outbound buffer's entries (64 or 64 * 2 bytes, depending if headers/data paths) + promise aggregator (64 bytes), which means > 128 bytes. From what I can see, encoded response headers below 128 bytes are quite common, while for the data, depends, but it is still a possible scenario, although more typical in benchmarks IMO. |
cb324a0 to
bcfaf83
Compare
|
This is just a preliminary example of the improvement, given that it doesn't account for the saving of the aggregate promise (which translate in less morphism of call-sites around the promises handling): before: now: which is already ~10-20% improvement just on headers/data writing. |
|
An additional benefit (specific to Vertx, but can really happen regardless), is that the data written by users could uses heap-based this code path just disappear with this PR, given that no heap buffer is passed to the transport. I've added 003d1e29350c47fe50d40456312b25d5e91720da to ignore the cutoff limits if the data is held in an array buffer, so we would perform the copy earlier, saving creating the aggregate promise and the additional pipeline traversal |
3faca11 to
003d1e2
Compare
|
I think I have a leak when the data buffer is not sent anymore across the transport, and be released after flushed. I should release it right after copied |
|
@ejona86 @carl-mastrangelo do you have any chance (or any pointer to make me try it) to verify/validate some of the changes I am sending recently, performance-wise? I'm thinking about gRpc over HTTP 2 and having something different from our Quarkus/Vertx stack would help a lot |
83232f4 to
4438bed
Compare
|
@bryce-anderson this is using a very similar optimization although I couldn't push it as far as http 1.1 and make it produce a single buffer overall (we don't even presize the header here :/) |
|
Alas, I have moved on from the gRPC team, and don't have access to sample http2 traffic. |
|
Thanks @carl-mastrangelo to have answered; if there is some Google users interested into grpc Netty, please reach me out here |
|
@franz1981 Please let me know once this is ready again for review |
|
Yep, @normanmaurer this should be ready to go as well |
66cca39 to
157a4a4
Compare
|
mmm @normanmaurer what happened for 33f5c56? :P |
|
@franz1981 what you mean ? |
|
@normanmaurer I've received notification of |
|
@franz1981 ah this was just to bring it up to date with current 4.1 |
|
@normanmaurer there is something more you want me to take a look for this before getting another review round? As said, I am not very confident the original code was correctly handling leaks here, but is really tons of code and we should address it separately (eg all the header retained slices around, the thrown you noticed in some earlier comment) - ideally first, if we think them to be critic. What I could do is to try address them already for the fast-paths I've introduced, but will create the weird situation, where the optimized (although common enough, I suppose) new stuff is more correct than what exists from some time already... |
|
@franz1981 just hold of a bit... I will try to find time to review this one first |
|
@bryce-anderson if you want to give it another shot, I have tried implementing your suggestion to further reduce the number of allocations |
|
Any other concerns @bryce-anderson or @normanmaurer ? |
|
@normanmaurer @chrisvest any news for this folks? |
|
@ejona86 @idelpivnitskiy @bryce-anderson can you check again ? |
|
As soon as I return from holidays I would like to proceed on this... @bryce-anderson @ejona86 @idelpivnitskiy wdyt about the approach? Any other concern? |
|
I can rebase this and retry - resolving conflicts. |
|
sure lets do it |
|
@franz1981 do we want to rebase and get this in ? |
|
Try it if you can @normanmaurer it was a good improvement at the time I have done it I will be back next week so cannot 🙏 |
|
I tried cherry-picking this to 4.2, but it doesn't look beneficial on the face of it: Current 4.2: This PR cherry-picked: |
|
This was beneficial with POSIX writev last time I checked it and due to pipeline traversal, which:
And the other reason was to save aggregate promises; IDK if that benchmark stress it. I suggest you try a simple real benchmark (a la plaintext techempower) with H2load. I remember it was what I have used when I created it But I see in some prior comments I've used |
|
@chrisvest Running the JMH benchmark with the existing implementation (not this PR) I see few interesting things
This is where I have highlighted the allocation of the promise aggregator; it's very tiny in the benchmark, so i can see why it is not that important. |
|
|
I've just tried @chrisvest
while this is what you got with the
still not good as it create on the flight a direct instance... I would stick with the I think it's something we have to think about... |
|
FYI @chrisvest I've applied a small patch to the adaptive byte buf (explained at #15723 (comment)) in order to make more evident the improvement on this PR: after: which is similar to what I was claiming at the beginning for this PR. NOTE: |
|
@chrisvest I could revamp this WDYT? |





Motivation:
DefaultHttp2FrameWriter's always create aggregate promises and slices out of headers and data: both could be saved while reducing the amount of pipeline traversals in case the additional cost of creating a sliced buffer surpass the data to be written.
Modifications:
Small header and data could be copied directly in a single buffer, without any need to create aggregate promises.
Result:
Faster small data's writes