-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Several allocation reductions in SocketsHttpHandler #34724
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
Conversation
|
Tagging @dotnet/ncl as an area owner |
|
looks suspicious. |
|
hmm. I see the linked issue. that make sense. |
Just manually inline the tiny helper that's only used from one call site.
For the common case of a raw string, let the dictionary store the raw string directly rather than always wrapping it in a HeaderStoreItemInfo.
For Server, we expect it to be the same for every request on the same connection. For Date, if we're making lots of requests in a high-throughput fashion, we expect many responses on the same connection to have the same value. In both cases, we compare the received value against the last one received, and if it's the same, reuse the same string.
|
/azp list |
|
/azp run runtime-libraries outerloop |
|
Azure Pipelines successfully started running 1 pipeline(s). |
| return true; | ||
| } | ||
|
|
||
| internal static bool EqualsOrdinalAscii(string left, ReadOnlySpan<byte> right) |
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.
Can always pick up BytesOrdinalEqualsStringAndAscii from aspnetcore's ServerInfrastructure/StringUtilities
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.
Presumably @GrabYourPitchforks will have
https://github.com/dotnet/runtime/pull/34724/files/9d35e5ea0dbf79c474e97c9521f4cb4038beee7b#diff-5643273c2df7053c5ef81c7d9ec49e7cR11-R12
done soon and this can/should just use that.
For a request like this (which I created just by looking at what headers my browser is sending):
to a default web api application, this PR reduces allocation by ~20%. This is a benchmark.net run of doing the above 100K times in parallel per iteration (and with the server on the same machine, so grain of salt on the timings... the most interesting numbers are the GC/allocation-related ones):
Commit 1: Just manually inlines a small async method. This removes its state machine allocation in the common case, but it also really didn't need to be its own method.
Commit 2: Today whenever a header is added to a header collection with TryAddWithoutValidation, it's wrapped in a HeaderStoreItemInfo, even though we could just store the raw string directly. This PR changes it so that we store the raw string, and only upgrade it to being wrapped when necessary, e.g. whenever we actually parse it, if we need to. I'm interested in feedback as to whether folks think it makes the code too complicated / whether it's worthwhile.
Commit 3: Caches the Date and Server header values on a connection. Since Server should generally never change for all requests on a connection, and Date should only change once a second-ish, we can avoid those string allocations in the typical high-throughput case. Again, I'm interested in feedback on whether folks see a better way to do this.
I tried this with the ASP.NET HttpClient benchmark, and it had a small but repeatable positive impact of around 1-2% on RPS.
Depends on #34667
cc: @scalablecory, @davidsh, @dotnet/ncl