From 592cea6a2b66eac1079c25114bfb6bee21b571c4 Mon Sep 17 00:00:00 2001 From: James Newton-King Date: Tue, 18 Aug 2020 19:37:48 +1200 Subject: [PATCH] Optimize writing single segment sequences (#24929) --- .../Http/Http1ChunkedEncodingMessageBody.cs | 17 +-------------- .../src/Internal/Http2/Http2FrameWriter.cs | 5 +---- .../Core/src/Internal/Http2/Http2Stream.cs | 5 +---- .../ServerInfrastructure/BufferExtensions.cs | 21 +++++++++++++++++++ 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/Http1ChunkedEncodingMessageBody.cs b/src/Servers/Kestrel/Core/src/Internal/Http/Http1ChunkedEncodingMessageBody.cs index 815ebc284b..aff3004fb0 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/Http1ChunkedEncodingMessageBody.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/Http1ChunkedEncodingMessageBody.cs @@ -218,21 +218,6 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http _requestBodyPipe.Reset(); } - private void Copy(in ReadOnlySequence readableBuffer, PipeWriter writableBuffer) - { - if (readableBuffer.IsSingleSegment) - { - writableBuffer.Write(readableBuffer.FirstSpan); - } - else - { - foreach (var memory in readableBuffer) - { - writableBuffer.Write(memory.Span); - } - } - } - protected override void OnReadStarted() { _pumpTask = PumpAsync(); @@ -442,7 +427,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http consumed = buffer.GetPosition(actual); examined = consumed; - Copy(buffer.Slice(0, actual), writableBuffer); + buffer.Slice(0, actual).CopyTo(writableBuffer); _inputLength -= actual; AddAndCheckObservedBytes(actual); diff --git a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs index a4932de60f..9f9cd89aae 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2FrameWriter.cs @@ -357,10 +357,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 WriteHeaderUnsynchronized(); - foreach (var buffer in data) - { - _outputWriter.Write(buffer.Span); - } + data.CopyTo(_outputWriter); // Plus padding return; diff --git a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Stream.cs b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Stream.cs index c3a90279f6..84b3e28743 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Stream.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http2/Http2Stream.cs @@ -440,10 +440,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http2 // Ignore data frames for aborted streams, but only after counting them for purposes of connection level flow control. if (!IsAborted) { - foreach (var segment in dataPayload) - { - RequestBodyPipe.Writer.Write(segment.Span); - } + dataPayload.CopyTo(RequestBodyPipe.Writer); // If the stream is completed go ahead and call RequestBodyPipe.Writer.Complete(). // Data will still be available to the reader. diff --git a/src/Shared/ServerInfrastructure/BufferExtensions.cs b/src/Shared/ServerInfrastructure/BufferExtensions.cs index 0ba5911c0a..3bbf8e08b4 100644 --- a/src/Shared/ServerInfrastructure/BufferExtensions.cs +++ b/src/Shared/ServerInfrastructure/BufferExtensions.cs @@ -26,6 +26,27 @@ namespace System.Buffers return buffer.ToArray(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void CopyTo(in this ReadOnlySequence buffer, PipeWriter pipeWriter) + { + if (buffer.IsSingleSegment) + { + pipeWriter.Write(buffer.FirstSpan); + } + else + { + CopyToMultiSegment(buffer, pipeWriter); + } + } + + private static void CopyToMultiSegment(in ReadOnlySequence buffer, PipeWriter pipeWriter) + { + foreach (var item in buffer) + { + pipeWriter.Write(item.Span); + } + } + public static ArraySegment GetArray(this Memory buffer) { return ((ReadOnlyMemory)buffer).GetArray();