Reduce allocation in HTTP/2 requests by ~30% (#32406)
authorStephen Toub <stoub@microsoft.com>
Tue, 18 Feb 2020 13:24:08 +0000 (08:24 -0500)
committerGitHub <noreply@github.com>
Tue, 18 Feb 2020 13:24:08 +0000 (08:24 -0500)
commit3701909085632f3ad7b09b756bd32fd1a7f98017
tree41cc501121e9a77fcde8157a871e2196316614a1
parent0f736f8cb81d63ce1d054adf919c19a20fe9827b
Reduce allocation in HTTP/2 requests by ~30% (#32406)

* Avoid forcing ExpectContinue / TransferEncodingChunked headers into existence

* Reduce cookie-related allocations

- Make CookieParser/CookieTokenizer into structs. CookieParser is just created as a helper with some state to help a loop do parsing; it's not passed around in any way.  And CookieTokenizer is just the implementation of CookieParser separated out for some reason.  They can both be structs.
- Remove enumerator allocations related to cookies. Also reduces interface method invocations.

* Remove often-unnecessary allocation in Uri.IdnHost

This is happening for every request.  But if the host is already all ASCII, we don't need to create a new string, and if it's already all lowercase, we don't need to create yet another new string. (This logic could stand to be cleaned up further; I just removed the allocations and some unnecessarily complex unsafe code along the way.)

* Combine ReadAtLeastAsync into EnsureIncomingBytesAsync

There's no need for them to be separate, and separating them leads to an extra async stack frame / state machine.

* Reduce calls to ReadFrameAsync that need to yield

Many frames either won't have a payload, or the act of waiting for the header will also end up waiting for the payload (in the same packet).  By pulling out the wait in the hot path, we significantly reduce the number of times ReadFrameAsync will need to yield.

* Override Http2ReadStream.CopyToAsync

Reduces allocation / improves throughput when using responseStream.CopyToAsync.

* Shrink EnsureIncomingBytesAsync state machine by 8 bytes

Remove two lifted Int32s.

* Shrink size of Http2Connection.SendAsync state machine

The order of a comparison operation is, based on C# required order of operations, forcing a temporary to be spilled and lifted to the state machine.

* Add additional values to known headers

Avoids string allocations when these common response values are used.

* Remove dead Uri code
src/libraries/Common/src/System/Net/CookieParser.cs
src/libraries/System.Net.Http/src/System/Net/Http/Headers/HttpRequestHeaders.cs
src/libraries/System.Net.Http/src/System/Net/Http/Headers/KnownHeaders.cs
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Stream.cs
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/RedirectHandler.cs
src/libraries/System.Net.Primitives/src/System/Net/CookieCollection.cs
src/libraries/System.Net.Primitives/src/System/Net/CookieContainer.cs
src/libraries/System.Private.Uri/src/System/DomainNameHelper.cs