Copy Kestrel perf changes (#7480)

This commit is contained in:
BrennanConroy 2019-02-13 16:31:37 -08:00 committed by GitHub
parent d1aa53721b
commit 9de42d516e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 63 additions and 28 deletions

View File

@ -13,6 +13,7 @@
<Compile Include="$(SignalRSharedSourceRoot)PipeWriterStream.cs" Link="PipeWriterStream.cs" />
<Compile Include="$(SignalRSharedSourceRoot)ReflectionHelper.cs" Link="ReflectionHelper.cs" />
<Compile Include="$(SignalRSharedSourceRoot)TimerAwaitable.cs" Link="Internal\TimerAwaitable.cs" />
<Compile Include="$(SignalRSharedSourceRoot)ValueTaskExtensions.cs" Link="Internal\ValueTaskExtensions.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -15,8 +15,8 @@ namespace Microsoft.AspNetCore.Http.Connections.Client.Internal
private const byte ByteLF = (byte)'\n';
private const byte ByteColon = (byte)':';
private static readonly byte[] _dataPrefix = Encoding.UTF8.GetBytes("data: ");
private static readonly byte[] _sseLineEnding = Encoding.UTF8.GetBytes("\r\n");
private static ReadOnlySpan<byte> _dataPrefix => new byte[] { (byte)'d', (byte)'a', (byte)'t', (byte)'a', (byte)':', (byte)' ' };
private static ReadOnlySpan<byte> _sseLineEnding => new byte[] { (byte)'\r', (byte)'\n' };
private static readonly byte[] _newLine = Encoding.UTF8.GetBytes(Environment.NewLine);
private InternalParseState _internalParserState = InternalParseState.ReadMessagePayload;

View File

@ -13,24 +13,25 @@ namespace Microsoft.AspNetCore.Http.Connections
{
public static class NegotiateProtocol
{
// Use C#7.3's ReadOnlySpan<byte> optimization for static data https://vcsjones.com/2019/02/01/csharp-readonly-span-bytes-static/
private const string ConnectionIdPropertyName = "connectionId";
private static readonly byte[] ConnectionIdPropertyNameBytes = Encoding.UTF8.GetBytes(ConnectionIdPropertyName);
private static ReadOnlySpan<byte> ConnectionIdPropertyNameBytes => new byte[] { (byte)'c', (byte)'o', (byte)'n', (byte)'n', (byte)'e', (byte)'c', (byte)'t', (byte)'i', (byte)'o', (byte)'n', (byte)'I', (byte)'d' };
private const string UrlPropertyName = "url";
private static readonly byte[] UrlPropertyNameBytes = Encoding.UTF8.GetBytes(UrlPropertyName);
private static ReadOnlySpan<byte> UrlPropertyNameBytes => new byte[] { (byte)'u', (byte)'r', (byte)'l' };
private const string AccessTokenPropertyName = "accessToken";
private static readonly byte[] AccessTokenPropertyNameBytes = Encoding.UTF8.GetBytes(AccessTokenPropertyName);
private static ReadOnlySpan<byte> AccessTokenPropertyNameBytes => new byte[] { (byte)'a', (byte)'c', (byte)'c', (byte)'e', (byte)'s', (byte)'s', (byte)'T', (byte)'o', (byte)'k', (byte)'e', (byte)'n' };
private const string AvailableTransportsPropertyName = "availableTransports";
private static readonly byte[] AvailableTransportsPropertyNameBytes = Encoding.UTF8.GetBytes(AvailableTransportsPropertyName);
private static ReadOnlySpan<byte> AvailableTransportsPropertyNameBytes => new byte[] { (byte)'a', (byte)'v', (byte)'a', (byte)'i', (byte)'l', (byte)'a', (byte)'b', (byte)'l', (byte)'e', (byte)'T', (byte)'r', (byte)'a', (byte)'n', (byte)'s', (byte)'p', (byte)'o', (byte)'r', (byte)'t', (byte)'s' };
private const string TransportPropertyName = "transport";
private static readonly byte[] TransportPropertyNameBytes = Encoding.UTF8.GetBytes(TransportPropertyName);
private static ReadOnlySpan<byte> TransportPropertyNameBytes => new byte[] { (byte)'t', (byte)'r', (byte)'a', (byte)'n', (byte)'s', (byte)'p', (byte)'o', (byte)'r', (byte)'t' };
private const string TransferFormatsPropertyName = "transferFormats";
private static readonly byte[] TransferFormatsPropertyNameBytes = Encoding.UTF8.GetBytes(TransferFormatsPropertyName);
private static ReadOnlySpan<byte> TransferFormatsPropertyNameBytes => new byte[] { (byte)'t', (byte)'r', (byte)'a', (byte)'n', (byte)'s', (byte)'f', (byte)'e', (byte)'r', (byte)'F', (byte)'o', (byte)'r', (byte)'m', (byte)'a', (byte)'t', (byte)'s' };
private const string ErrorPropertyName = "error";
private static readonly byte[] ErrorPropertyNameBytes = Encoding.UTF8.GetBytes(ErrorPropertyName);
private static ReadOnlySpan<byte> ErrorPropertyNameBytes => new byte[] { (byte)'e', (byte)'r', (byte)'r', (byte)'o', (byte)'r' };
// Used to detect ASP.NET SignalR Server connection attempt
private const string ProtocolVersionPropertyName = "ProtocolVersion";
private static readonly byte[] ProtocolVersionPropertyNameBytes = Encoding.UTF8.GetBytes(ProtocolVersionPropertyName);
private static ReadOnlySpan<byte> ProtocolVersionPropertyNameBytes => new byte[] { (byte)'P', (byte)'r', (byte)'o', (byte)'t', (byte)'o', (byte)'c', (byte)'o', (byte)'l', (byte)'V', (byte)'e', (byte)'r', (byte)'s', (byte)'i', (byte)'o', (byte)'n' };
public static void WriteResponse(NegotiationResponse response, IBufferWriter<byte> output)
{
@ -114,15 +115,15 @@ namespace Microsoft.AspNetCore.Http.Connections
if (memberName.SequenceEqual(UrlPropertyNameBytes))
{
url = reader.ReadAsString(UrlPropertyNameBytes);
url = reader.ReadAsString(UrlPropertyName);
}
else if (memberName.SequenceEqual(AccessTokenPropertyNameBytes))
{
accessToken = reader.ReadAsString(AccessTokenPropertyNameBytes);
accessToken = reader.ReadAsString(AccessTokenPropertyName);
}
else if (memberName.SequenceEqual(ConnectionIdPropertyNameBytes))
{
connectionId = reader.ReadAsString(ConnectionIdPropertyNameBytes);
connectionId = reader.ReadAsString(ConnectionIdPropertyName);
}
else if (memberName.SequenceEqual(AvailableTransportsPropertyNameBytes))
{
@ -144,7 +145,7 @@ namespace Microsoft.AspNetCore.Http.Connections
}
else if (memberName.SequenceEqual(ErrorPropertyNameBytes))
{
error = reader.ReadAsString(ErrorPropertyNameBytes);
error = reader.ReadAsString(ErrorPropertyName);
}
else if (memberName.SequenceEqual(ProtocolVersionPropertyNameBytes))
{
@ -215,7 +216,7 @@ namespace Microsoft.AspNetCore.Http.Connections
if (memberName.SequenceEqual(TransportPropertyNameBytes))
{
availableTransport.Transport = reader.ReadAsString(TransportPropertyNameBytes);
availableTransport.Transport = reader.ReadAsString(TransportPropertyName);
}
else if (memberName.SequenceEqual(TransferFormatsPropertyNameBytes))
{

View File

@ -14,6 +14,7 @@
<Compile Include="$(SignalRSharedSourceRoot)WebSocketExtensions.cs" Link="WebSocketExtensions.cs" />
<Compile Include="$(SignalRSharedSourceRoot)StreamExtensions.cs" Link="StreamExtensions.cs" />
<Compile Include="$(SignalRSharedSourceRoot)DuplexPipe.cs" Link="DuplexPipe.cs" />
<Compile Include="$(SignalRSharedSourceRoot)ValueTaskExtensions.cs" Link="ValueTaskExtensions.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -6,6 +6,7 @@ using System.Buffers;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Internal;
namespace System.IO.Pipelines
{

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Text;
using System.Text.Json;
@ -70,19 +71,19 @@ namespace Microsoft.AspNetCore.Internal
}
}
public static string ReadAsString(this ref Utf8JsonReader reader, byte[] propertyName)
public static string ReadAsString(this ref Utf8JsonReader reader, string propertyName)
{
reader.Read();
if (reader.TokenType != JsonTokenType.String)
{
throw new InvalidDataException($"Expected '{Encoding.UTF8.GetString(propertyName)}' to be of type {JsonTokenType.String}.");
throw new InvalidDataException($"Expected '{propertyName}' to be of type {JsonTokenType.String}.");
}
return reader.GetString();
}
public static int? ReadAsInt32(this ref Utf8JsonReader reader, byte[] propertyName)
public static int? ReadAsInt32(this ref Utf8JsonReader reader, string propertyName)
{
reader.Read();
@ -93,7 +94,7 @@ namespace Microsoft.AspNetCore.Internal
if (reader.TokenType != JsonTokenType.Number)
{
throw new InvalidDataException($"Expected '{Encoding.UTF8.GetString(propertyName)}' to be of type {JsonTokenType.Number}.");
throw new InvalidDataException($"Expected '{propertyName}' to be of type {JsonTokenType.Number}.");
}
return reader.GetInt32();

View File

@ -0,0 +1,28 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.IO.Pipelines;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Internal
{
internal static class ValueTaskExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Task GetAsTask(this in ValueTask<FlushResult> valueTask)
{
// Try to avoid the allocation from AsTask
if (valueTask.IsCompletedSuccessfully)
{
// Signal consumption to the IValueTaskSource
valueTask.GetAwaiter().GetResult();
return Task.CompletedTask;
}
else
{
return valueTask.AsTask();
}
}
}
}

View File

@ -17,16 +17,17 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
/// </summary>
public static class HandshakeProtocol
{
// Use C#7.3's ReadOnlySpan<byte> optimization for static data https://vcsjones.com/2019/02/01/csharp-readonly-span-bytes-static/
private const string ProtocolPropertyName = "protocol";
private static readonly byte[] ProtocolPropertyNameBytes = Encoding.UTF8.GetBytes(ProtocolPropertyName);
private static ReadOnlySpan<byte> ProtocolPropertyNameBytes => new byte[] { (byte)'p', (byte)'r', (byte)'o', (byte)'t', (byte)'o', (byte)'c', (byte)'o', (byte)'l' };
private const string ProtocolVersionPropertyName = "version";
private static readonly byte[] ProtocolVersionPropertyNameBytes = Encoding.UTF8.GetBytes(ProtocolVersionPropertyName);
private static ReadOnlySpan<byte> ProtocolVersionPropertyNameBytes => new byte[] { (byte)'v', (byte)'e', (byte)'r', (byte)'s', (byte)'i', (byte)'o', (byte)'n' };
private const string MinorVersionPropertyName = "minorVersion";
private static readonly byte[] MinorVersionPropertyNameBytes = Encoding.UTF8.GetBytes(MinorVersionPropertyName);
private static ReadOnlySpan<byte> MinorVersionPropertyNameBytes => new byte[] { (byte)'m', (byte)'i', (byte)'n', (byte)'o', (byte)'r', (byte)'V', (byte)'e', (byte)'r', (byte)'s', (byte)'i', (byte)'o', (byte)'n' };
private const string ErrorPropertyName = "error";
private static readonly byte[] ErrorPropertyNameBytes = Encoding.UTF8.GetBytes(ErrorPropertyName);
private static ReadOnlySpan<byte> ErrorPropertyNameBytes => new byte[] { (byte)'e', (byte)'r', (byte)'r', (byte)'o', (byte)'r' };
private const string TypePropertyName = "type";
private static readonly byte[] TypePropertyNameBytes = Encoding.UTF8.GetBytes(TypePropertyName);
private static ReadOnlySpan<byte> TypePropertyNameBytes => new byte[] { (byte)'t', (byte)'y', (byte)'p', (byte)'e' };
private static ConcurrentDictionary<IHubProtocol, ReadOnlyMemory<byte>> _messageCache = new ConcurrentDictionary<IHubProtocol, ReadOnlyMemory<byte>>();
@ -128,11 +129,11 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
}
else if (memberName.SequenceEqual(ErrorPropertyNameBytes))
{
error = reader.ReadAsString(ErrorPropertyNameBytes);
error = reader.ReadAsString(ErrorPropertyName);
}
else if (memberName.SequenceEqual(MinorVersionPropertyNameBytes))
{
minorVersion = reader.ReadAsInt32(MinorVersionPropertyNameBytes);
minorVersion = reader.ReadAsInt32(MinorVersionPropertyName);
}
else
{
@ -183,11 +184,11 @@ namespace Microsoft.AspNetCore.SignalR.Protocol
if (memberName.SequenceEqual(ProtocolPropertyNameBytes))
{
protocol = reader.ReadAsString(ProtocolPropertyNameBytes);
protocol = reader.ReadAsString(ProtocolPropertyName);
}
else if (memberName.SequenceEqual(ProtocolVersionPropertyNameBytes))
{
protocolVersion = reader.ReadAsInt32(ProtocolVersionPropertyNameBytes);
protocolVersion = reader.ReadAsInt32(ProtocolVersionPropertyName);
}
else
{

View File

@ -8,6 +8,7 @@ using System.Linq;
using System.Reflection;
using System.Threading.Channels;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Internal;
using Microsoft.AspNetCore.SignalR.Protocol;
namespace Microsoft.AspNetCore.SignalR