Moving PlatformBenchmarks from aspnet/benchmarks (#2457)
This commit is contained in:
parent
7e5104573e
commit
e411cbf7e2
|
|
@ -126,6 +126,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SystemdTestApp", "samples\S
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlaintextApp", "samples\PlaintextApp\PlaintextApp.csproj", "{CE5523AE-6E38-4E20-998F-C64E02C5CC51}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlaintextApp", "samples\PlaintextApp\PlaintextApp.csproj", "{CE5523AE-6E38-4E20-998F-C64E02C5CC51}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PlatformBenchmarks", "benchmarkapps\PlatformBenchmarks\PlatformBenchmarks.csproj", "{7C24EAB8-57A9-4613-A8A6-4C21BB7D260D}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|
@ -364,6 +366,18 @@ Global
|
||||||
{CE5523AE-6E38-4E20-998F-C64E02C5CC51}.Release|x64.Build.0 = Release|Any CPU
|
{CE5523AE-6E38-4E20-998F-C64E02C5CC51}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{CE5523AE-6E38-4E20-998F-C64E02C5CC51}.Release|x86.ActiveCfg = Release|Any CPU
|
{CE5523AE-6E38-4E20-998F-C64E02C5CC51}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{CE5523AE-6E38-4E20-998F-C64E02C5CC51}.Release|x86.Build.0 = Release|Any CPU
|
{CE5523AE-6E38-4E20-998F-C64E02C5CC51}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{7C24EAB8-57A9-4613-A8A6-4C21BB7D260D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7C24EAB8-57A9-4613-A8A6-4C21BB7D260D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7C24EAB8-57A9-4613-A8A6-4C21BB7D260D}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{7C24EAB8-57A9-4613-A8A6-4C21BB7D260D}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{7C24EAB8-57A9-4613-A8A6-4C21BB7D260D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{7C24EAB8-57A9-4613-A8A6-4C21BB7D260D}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{7C24EAB8-57A9-4613-A8A6-4C21BB7D260D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7C24EAB8-57A9-4613-A8A6-4C21BB7D260D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7C24EAB8-57A9-4613-A8A6-4C21BB7D260D}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{7C24EAB8-57A9-4613-A8A6-4C21BB7D260D}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{7C24EAB8-57A9-4613-A8A6-4C21BB7D260D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{7C24EAB8-57A9-4613-A8A6-4C21BB7D260D}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
@ -390,6 +404,7 @@ Global
|
||||||
{7BC22A4A-15D2-44C2-AB45-049F0FB562FA} = {8A3D00B8-1CCF-4BE6-A060-11104CE2D9CE}
|
{7BC22A4A-15D2-44C2-AB45-049F0FB562FA} = {8A3D00B8-1CCF-4BE6-A060-11104CE2D9CE}
|
||||||
{A7994A41-CAF8-47A7-8975-F101F75B5BC1} = {8A3D00B8-1CCF-4BE6-A060-11104CE2D9CE}
|
{A7994A41-CAF8-47A7-8975-F101F75B5BC1} = {8A3D00B8-1CCF-4BE6-A060-11104CE2D9CE}
|
||||||
{CE5523AE-6E38-4E20-998F-C64E02C5CC51} = {8A3D00B8-1CCF-4BE6-A060-11104CE2D9CE}
|
{CE5523AE-6E38-4E20-998F-C64E02C5CC51} = {8A3D00B8-1CCF-4BE6-A060-11104CE2D9CE}
|
||||||
|
{7C24EAB8-57A9-4613-A8A6-4C21BB7D260D} = {A95C3BE1-B850-4265-97A0-777ADCCD437F}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {2D10D020-6770-47CA-BB8D-2C23FE3AE071}
|
SolutionGuid = {2D10D020-6770-47CA-BB8D-2C23FE3AE071}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
// 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.Text;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||||
|
|
||||||
|
namespace PlatformBenchmarks
|
||||||
|
{
|
||||||
|
public struct AsciiString : IEquatable<AsciiString>
|
||||||
|
{
|
||||||
|
private readonly byte[] _data;
|
||||||
|
|
||||||
|
public AsciiString(string s) => _data = Encoding.ASCII.GetBytes(s);
|
||||||
|
|
||||||
|
public int Length => _data.Length;
|
||||||
|
|
||||||
|
public ReadOnlySpan<byte> AsSpan() => _data;
|
||||||
|
|
||||||
|
public static implicit operator ReadOnlySpan<byte>(AsciiString str) => str._data;
|
||||||
|
public static implicit operator byte[] (AsciiString str) => str._data;
|
||||||
|
|
||||||
|
public static implicit operator AsciiString(string str) => new AsciiString(str);
|
||||||
|
|
||||||
|
public override string ToString() => HttpUtilities.GetAsciiStringNonNullCharacters(_data);
|
||||||
|
public static explicit operator string(AsciiString str) => str.ToString();
|
||||||
|
|
||||||
|
public bool Equals(AsciiString other) => ReferenceEquals(_data, other._data) || SequenceEqual(_data, other._data);
|
||||||
|
private bool SequenceEqual(byte[] data1, byte[] data2) => new Span<byte>(data1).SequenceEqual(data2);
|
||||||
|
|
||||||
|
public static bool operator ==(AsciiString a, AsciiString b) => a.Equals(b);
|
||||||
|
public static bool operator !=(AsciiString a, AsciiString b) => !a.Equals(b);
|
||||||
|
public override bool Equals(object other) => (other is AsciiString) && Equals((AsciiString)other);
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
// Copied from x64 version of string.GetLegacyNonRandomizedHashCode()
|
||||||
|
// https://github.com/dotnet/coreclr/blob/master/src/mscorlib/src/System/String.Comparison.cs
|
||||||
|
var data = _data;
|
||||||
|
int hash1 = 5381;
|
||||||
|
int hash2 = hash1;
|
||||||
|
foreach (int b in data)
|
||||||
|
{
|
||||||
|
hash1 = ((hash1 << 5) + hash1) ^ b;
|
||||||
|
}
|
||||||
|
return hash1 + (hash2 * 1566083941);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
// 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.Buffers;
|
||||||
|
using System.IO.Pipelines;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
||||||
|
using Utf8Json;
|
||||||
|
|
||||||
|
namespace PlatformBenchmarks
|
||||||
|
{
|
||||||
|
public class BenchmarkApplication : HttpConnection
|
||||||
|
{
|
||||||
|
private static AsciiString _crlf = "\r\n";
|
||||||
|
private static AsciiString _eoh = "\r\n\r\n"; // End Of Headers
|
||||||
|
private static AsciiString _http11OK = "HTTP/1.1 200 OK\r\n";
|
||||||
|
private static AsciiString _headerServer = "Server: Custom";
|
||||||
|
private static AsciiString _headerContentLength = "Content-Length: ";
|
||||||
|
private static AsciiString _headerContentLengthZero = "Content-Length: 0\r\n";
|
||||||
|
private static AsciiString _headerContentTypeText = "Content-Type: text/plain\r\n";
|
||||||
|
private static AsciiString _headerContentTypeJson = "Content-Type: application/json\r\n";
|
||||||
|
|
||||||
|
|
||||||
|
private static AsciiString _plainTextBody = "Hello, World!";
|
||||||
|
|
||||||
|
private static class Paths
|
||||||
|
{
|
||||||
|
public static AsciiString Plaintext = "/plaintext";
|
||||||
|
public static AsciiString Json = "/json";
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool _isPlainText;
|
||||||
|
private bool _isJson;
|
||||||
|
|
||||||
|
public override void OnStartLine(HttpMethod method, HttpVersion version, Span<byte> target, Span<byte> path, Span<byte> query, Span<byte> customMethod, bool pathEncoded)
|
||||||
|
{
|
||||||
|
if (path.StartsWith(Paths.Plaintext) && method == HttpMethod.Get)
|
||||||
|
{
|
||||||
|
_isPlainText = true;
|
||||||
|
}
|
||||||
|
else if (path.StartsWith(Paths.Json) && method == HttpMethod.Get)
|
||||||
|
{
|
||||||
|
_isJson = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_isPlainText = false;
|
||||||
|
_isJson = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnHeader(Span<byte> name, Span<byte> value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override ValueTask ProcessRequestAsync()
|
||||||
|
{
|
||||||
|
if (_isPlainText)
|
||||||
|
{
|
||||||
|
PlainText(Writer);
|
||||||
|
}
|
||||||
|
else if (_isJson)
|
||||||
|
{
|
||||||
|
Json(Writer);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Default(Writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async ValueTask OnReadCompletedAsync()
|
||||||
|
{
|
||||||
|
await Writer.FlushAsync();
|
||||||
|
}
|
||||||
|
private static void PlainText(PipeWriter pipeWriter)
|
||||||
|
{
|
||||||
|
var writer = new BufferWriter<PipeWriter>(pipeWriter);
|
||||||
|
// HTTP 1.1 OK
|
||||||
|
writer.Write(_http11OK);
|
||||||
|
|
||||||
|
// Server headers
|
||||||
|
writer.Write(_headerServer);
|
||||||
|
|
||||||
|
// Date header
|
||||||
|
writer.Write(DateHeader.HeaderBytes);
|
||||||
|
|
||||||
|
// Content-Type header
|
||||||
|
writer.Write(_headerContentTypeText);
|
||||||
|
|
||||||
|
// Content-Length header
|
||||||
|
writer.Write(_headerContentLength);
|
||||||
|
writer.WriteNumeric((ulong)_plainTextBody.Length);
|
||||||
|
|
||||||
|
// End of headers
|
||||||
|
writer.Write(_eoh);
|
||||||
|
|
||||||
|
// Body
|
||||||
|
writer.Write(_plainTextBody);
|
||||||
|
writer.Commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Json(PipeWriter pipeWriter)
|
||||||
|
{
|
||||||
|
var writer = new BufferWriter<PipeWriter>(pipeWriter);
|
||||||
|
|
||||||
|
// HTTP 1.1 OK
|
||||||
|
writer.Write(_http11OK);
|
||||||
|
|
||||||
|
// Server headers
|
||||||
|
writer.Write(_headerServer);
|
||||||
|
|
||||||
|
// Date header
|
||||||
|
writer.Write(DateHeader.HeaderBytes);
|
||||||
|
|
||||||
|
// Content-Type header
|
||||||
|
writer.Write(_headerContentTypeJson);
|
||||||
|
|
||||||
|
// Content-Length header
|
||||||
|
writer.Write(_headerContentLength);
|
||||||
|
var jsonPayload = JsonSerializer.SerializeUnsafe(new { message = "Hello, World!" });
|
||||||
|
writer.WriteNumeric((ulong)jsonPayload.Count);
|
||||||
|
|
||||||
|
// End of headers
|
||||||
|
writer.Write(_eoh);
|
||||||
|
|
||||||
|
// Body
|
||||||
|
writer.Write(jsonPayload);
|
||||||
|
writer.Commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Default(PipeWriter pipeWriter)
|
||||||
|
{
|
||||||
|
var writer = new BufferWriter<PipeWriter>(pipeWriter);
|
||||||
|
|
||||||
|
// HTTP 1.1 OK
|
||||||
|
writer.Write(_http11OK);
|
||||||
|
|
||||||
|
// Server headers
|
||||||
|
writer.Write(_headerServer);
|
||||||
|
|
||||||
|
// Date header
|
||||||
|
writer.Write(DateHeader.HeaderBytes);
|
||||||
|
|
||||||
|
// Content-Length 0
|
||||||
|
writer.Write(_headerContentLengthZero);
|
||||||
|
|
||||||
|
// End of headers
|
||||||
|
writer.Write(_crlf);
|
||||||
|
writer.Commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,81 @@
|
||||||
|
// 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.Net;
|
||||||
|
using Microsoft.AspNetCore;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
|
||||||
|
namespace PlatformBenchmarks
|
||||||
|
{
|
||||||
|
public static class BenchmarkConfigurationHelpers
|
||||||
|
{
|
||||||
|
public static IWebHostBuilder UseBenchmarksConfiguration(this IWebHostBuilder builder, IConfiguration configuration)
|
||||||
|
{
|
||||||
|
builder.UseConfiguration(configuration);
|
||||||
|
|
||||||
|
// Handle the transport type
|
||||||
|
var webHost = builder.GetSetting("KestrelTransport");
|
||||||
|
|
||||||
|
// Handle the thread count
|
||||||
|
var threadCountRaw = builder.GetSetting("threadCount");
|
||||||
|
int? theadCount = null;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(threadCountRaw) &&
|
||||||
|
Int32.TryParse(threadCountRaw, out var value))
|
||||||
|
{
|
||||||
|
theadCount = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (string.Equals(webHost, "Libuv", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
builder.UseLibuv(options =>
|
||||||
|
{
|
||||||
|
if (theadCount.HasValue)
|
||||||
|
{
|
||||||
|
options.ThreadCount = theadCount.Value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (string.Equals(webHost, "Sockets", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
builder.UseSockets(options =>
|
||||||
|
{
|
||||||
|
if (theadCount.HasValue)
|
||||||
|
{
|
||||||
|
options.IOQueueCount = theadCount.Value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IPEndPoint CreateIPEndPoint(this IConfiguration config)
|
||||||
|
{
|
||||||
|
var url = config["server.urls"] ?? config["urls"];
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(url))
|
||||||
|
{
|
||||||
|
return new IPEndPoint(IPAddress.Loopback, 8080);
|
||||||
|
}
|
||||||
|
|
||||||
|
var address = ServerAddress.FromUrl(url);
|
||||||
|
|
||||||
|
IPAddress ip;
|
||||||
|
|
||||||
|
if (string.Equals(address.Host, "localhost", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
ip = IPAddress.Loopback;
|
||||||
|
}
|
||||||
|
else if (!IPAddress.TryParse(address.Host, out ip))
|
||||||
|
{
|
||||||
|
ip = IPAddress.IPv6Any;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new IPEndPoint(ip, address.Port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
// 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.Buffers.Text;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO.Pipelines;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace System.Buffers
|
||||||
|
{
|
||||||
|
internal static class BufferWriterExtensions
|
||||||
|
{
|
||||||
|
private const int MaxULongByteLength = 20;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal static void WriteNumeric(ref this BufferWriter<PipeWriter> buffer, ulong number)
|
||||||
|
{
|
||||||
|
// Try to format directly
|
||||||
|
if (Utf8Formatter.TryFormat(number, buffer.Span, out int bytesWritten))
|
||||||
|
{
|
||||||
|
buffer.Advance(bytesWritten);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Ask for at least 20 bytes
|
||||||
|
buffer.Ensure(MaxULongByteLength);
|
||||||
|
|
||||||
|
Debug.Assert(buffer.Span.Length >= 20, "Buffer is < 20 bytes");
|
||||||
|
|
||||||
|
// Try again
|
||||||
|
if (Utf8Formatter.TryFormat(number, buffer.Span, out bytesWritten))
|
||||||
|
{
|
||||||
|
buffer.Advance(bytesWritten);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
// 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.Buffers.Text;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Manages the generation of the date header value.
|
||||||
|
/// </summary>
|
||||||
|
internal static class DateHeader
|
||||||
|
{
|
||||||
|
const int prefixLength = 8; // "\r\nDate: ".Length
|
||||||
|
const int dateTimeRLength = 29; // Wed, 14 Mar 2018 14:20:00 GMT
|
||||||
|
const int suffixLength = 2; // crlf
|
||||||
|
const int suffixIndex = dateTimeRLength + prefixLength;
|
||||||
|
|
||||||
|
private static readonly Timer s_timer = new Timer((s) => {
|
||||||
|
SetDateValues(DateTimeOffset.UtcNow);
|
||||||
|
}, null, 1000, 1000);
|
||||||
|
|
||||||
|
private static byte[] s_headerBytesMaster = new byte[prefixLength + dateTimeRLength + suffixLength];
|
||||||
|
private static byte[] s_headerBytesScratch = new byte[prefixLength + dateTimeRLength + suffixLength];
|
||||||
|
|
||||||
|
static DateHeader()
|
||||||
|
{
|
||||||
|
var utf8 = Encoding.ASCII.GetBytes("\r\nDate: ").AsSpan();
|
||||||
|
utf8.CopyTo(s_headerBytesMaster);
|
||||||
|
utf8.CopyTo(s_headerBytesScratch);
|
||||||
|
s_headerBytesMaster[suffixIndex] = (byte)'\r';
|
||||||
|
s_headerBytesMaster[suffixIndex + 1] = (byte)'\n';
|
||||||
|
s_headerBytesScratch[suffixIndex] = (byte)'\r';
|
||||||
|
s_headerBytesScratch[suffixIndex + 1] = (byte)'\n';
|
||||||
|
SetDateValues(DateTimeOffset.UtcNow);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ReadOnlySpan<byte> HeaderBytes => s_headerBytesMaster;
|
||||||
|
|
||||||
|
private static void SetDateValues(DateTimeOffset value)
|
||||||
|
{
|
||||||
|
lock (s_headerBytesScratch)
|
||||||
|
{
|
||||||
|
if (!Utf8Formatter.TryFormat(value, s_headerBytesScratch.AsSpan().Slice(prefixLength), out int written, 'R'))
|
||||||
|
{
|
||||||
|
throw new Exception("date time format failed");
|
||||||
|
}
|
||||||
|
Debug.Assert(written == dateTimeRLength);
|
||||||
|
var temp = s_headerBytesMaster;
|
||||||
|
s_headerBytesMaster = s_headerBytesScratch;
|
||||||
|
s_headerBytesScratch = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,161 @@
|
||||||
|
// 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.Buffers;
|
||||||
|
using System.IO.Pipelines;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Connections;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
||||||
|
|
||||||
|
namespace PlatformBenchmarks
|
||||||
|
{
|
||||||
|
public static class HttpApplicationConnectionBuilderExtensions
|
||||||
|
{
|
||||||
|
public static IConnectionBuilder UseHttpApplication<TConnection>(this IConnectionBuilder builder) where TConnection : HttpConnection, new()
|
||||||
|
{
|
||||||
|
return builder.Use(next => new HttpApplication<TConnection>().ExecuteAsync);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HttpApplication<TConnection> where TConnection : HttpConnection, new()
|
||||||
|
{
|
||||||
|
public Task ExecuteAsync(ConnectionContext connection)
|
||||||
|
{
|
||||||
|
var parser = new HttpParser<HttpConnection>();
|
||||||
|
|
||||||
|
var httpConnection = new TConnection
|
||||||
|
{
|
||||||
|
Parser = parser,
|
||||||
|
Reader = connection.Transport.Input,
|
||||||
|
Writer = connection.Transport.Output
|
||||||
|
};
|
||||||
|
return httpConnection.ExecuteAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HttpConnection : IHttpHeadersHandler, IHttpRequestLineHandler
|
||||||
|
{
|
||||||
|
private State _state;
|
||||||
|
|
||||||
|
public PipeReader Reader { get; set; }
|
||||||
|
public PipeWriter Writer { get; set; }
|
||||||
|
|
||||||
|
internal HttpParser<HttpConnection> Parser { get; set; }
|
||||||
|
|
||||||
|
public virtual void OnHeader(Span<byte> name, Span<byte> value)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void OnStartLine(HttpMethod method, HttpVersion version, Span<byte> target, Span<byte> path, Span<byte> query, Span<byte> customMethod, bool pathEncoded)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual ValueTask ProcessRequestAsync()
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual ValueTask OnReadCompletedAsync()
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ExecuteAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ProcessRequestsAsync();
|
||||||
|
|
||||||
|
Reader.Complete();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Reader.Complete(ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Writer.Complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProcessRequestsAsync()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var task = Reader.ReadAsync();
|
||||||
|
|
||||||
|
if (!task.IsCompleted)
|
||||||
|
{
|
||||||
|
// No more data in the input
|
||||||
|
await OnReadCompletedAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = await task;
|
||||||
|
var buffer = result.Buffer;
|
||||||
|
var consumed = buffer.Start;
|
||||||
|
var examined = buffer.End;
|
||||||
|
|
||||||
|
if (!buffer.IsEmpty)
|
||||||
|
{
|
||||||
|
ParseHttpRequest(buffer, out consumed, out examined);
|
||||||
|
|
||||||
|
if (_state != State.Body && result.IsCompleted)
|
||||||
|
{
|
||||||
|
ThrowUnexpectedEndOfData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (result.IsCompleted)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Reader.AdvanceTo(consumed, examined);
|
||||||
|
|
||||||
|
if (_state == State.Body)
|
||||||
|
{
|
||||||
|
await ProcessRequestAsync();
|
||||||
|
|
||||||
|
_state = State.StartLine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseHttpRequest(in ReadOnlySequence<byte> buffer, out SequencePosition consumed, out SequencePosition examined)
|
||||||
|
{
|
||||||
|
consumed = buffer.Start;
|
||||||
|
examined = buffer.End;
|
||||||
|
|
||||||
|
var parsingStartLine = _state == State.StartLine;
|
||||||
|
if (parsingStartLine)
|
||||||
|
{
|
||||||
|
if (Parser.ParseRequestLine(this, buffer, out consumed, out examined))
|
||||||
|
{
|
||||||
|
_state = State.Headers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_state == State.Headers)
|
||||||
|
{
|
||||||
|
if (Parser.ParseHeaders(this, parsingStartLine ? buffer.Slice(consumed) : buffer, out consumed, out examined, out int consumedBytes))
|
||||||
|
{
|
||||||
|
_state = State.Body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ThrowUnexpectedEndOfData()
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Unexpected end of data!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum State
|
||||||
|
{
|
||||||
|
StartLine,
|
||||||
|
Headers,
|
||||||
|
Body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<LangVersion>latest</LangVersion>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Utf8Json" Version="$(Utf8JsonPackageVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- These references are used when running locally -->
|
||||||
|
<ItemGroup Condition="'$(BenchmarksTargetFramework)' == ''">
|
||||||
|
<ProjectReference Include="..\..\src\Kestrel\Kestrel.csproj" />
|
||||||
|
<ProjectReference Include="..\..\src\Kestrel.Transport.Libuv\Kestrel.Transport.Libuv.csproj" />
|
||||||
|
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Buffers.Sources" PrivateAssets="All" Version="$(MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="$(MicrosoftExtensionsConfigurationCommandLinePackageVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- These references are used when running on the Benchmarks Server -->
|
||||||
|
<ItemGroup Condition="'$(BenchmarksTargetFramework)' != ''">
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.All" Version="$(MicrosoftAspNetCoreAllPackageVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Buffers.Sources" Version="$(MicrosoftAspNetCoreAllPackageVersion)" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
// 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.Net;
|
||||||
|
using Microsoft.AspNetCore;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Transport.Abstractions.Internal;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace PlatformBenchmarks
|
||||||
|
{
|
||||||
|
public class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
BuildWebHost(args).Run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IWebHost BuildWebHost(string[] args)
|
||||||
|
{
|
||||||
|
var config = new ConfigurationBuilder()
|
||||||
|
.AddEnvironmentVariables(prefix: "ASPNETCORE_")
|
||||||
|
.AddCommandLine(args)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var host = new WebHostBuilder()
|
||||||
|
.UseBenchmarksConfiguration(config)
|
||||||
|
.UseKestrel((context, options) =>
|
||||||
|
{
|
||||||
|
IPEndPoint endPoint = context.Configuration.CreateIPEndPoint();
|
||||||
|
|
||||||
|
options.Listen(endPoint, builder =>
|
||||||
|
{
|
||||||
|
builder.UseHttpApplication<BenchmarkApplication>();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.UseStartup<Startup>()
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
// 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.Net.WebSockets;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
|
||||||
|
namespace PlatformBenchmarks
|
||||||
|
{
|
||||||
|
public class Startup
|
||||||
|
{
|
||||||
|
public void Configure(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"Default": {
|
||||||
|
"Client": "Wrk",
|
||||||
|
"PresetHeaders": "Json",
|
||||||
|
|
||||||
|
"Source": {
|
||||||
|
"Repository": "https://github.com/aspnet/KestrelHttpServer.git",
|
||||||
|
"BranchOrCommit": "dev",
|
||||||
|
"Project": "benchmarkapps/PlatformBenchmarks/PlatformBenchmarks.csproj"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"JsonPlatform": {
|
||||||
|
"Path": "/json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
{
|
||||||
|
"Default": {
|
||||||
|
"Client": "Wrk",
|
||||||
|
"PresetHeaders": "Plaintext",
|
||||||
|
"ClientProperties": {
|
||||||
|
"ScriptName": "pipeline",
|
||||||
|
"PipelineDepth": 16
|
||||||
|
},
|
||||||
|
"Source": {
|
||||||
|
"Repository": "https://github.com/aspnet/KestrelHttpServer.git",
|
||||||
|
"BranchOrCommit": "dev",
|
||||||
|
"Project": "benchmarkapps/PlatformBenchmarks/PlatformBenchmarks.csproj"
|
||||||
|
},
|
||||||
|
"Port": 8080
|
||||||
|
},
|
||||||
|
"PlaintextPlatform": {
|
||||||
|
"Path": "/plaintext"
|
||||||
|
},
|
||||||
|
"PlaintextNonPipelinedPlatform": {
|
||||||
|
"Path": "/plaintext",
|
||||||
|
"ClientProperties": {
|
||||||
|
"ScriptName": "",
|
||||||
|
"PipelineDepth": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
<BenchmarkDotNetPackageVersion>0.10.13</BenchmarkDotNetPackageVersion>
|
<BenchmarkDotNetPackageVersion>0.10.13</BenchmarkDotNetPackageVersion>
|
||||||
<InternalAspNetCoreSdkPackageVersion>2.1.0-preview3-17002</InternalAspNetCoreSdkPackageVersion>
|
<InternalAspNetCoreSdkPackageVersion>2.1.0-preview3-17002</InternalAspNetCoreSdkPackageVersion>
|
||||||
<LibuvPackageVersion>1.10.0</LibuvPackageVersion>
|
<LibuvPackageVersion>1.10.0</LibuvPackageVersion>
|
||||||
|
<MicrosoftAspNetCoreAllPackageVersion>2.1.0-preview3-32110</MicrosoftAspNetCoreAllPackageVersion>
|
||||||
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.1.0-preview3-32110</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
|
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.1.0-preview3-32110</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
|
||||||
<MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion>2.1.0-preview3-32110</MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion>
|
<MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion>2.1.0-preview3-32110</MicrosoftAspNetCoreCertificatesGenerationSourcesPackageVersion>
|
||||||
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.1.0-preview3-32110</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
|
<MicrosoftAspNetCoreHostingAbstractionsPackageVersion>2.1.0-preview3-32110</MicrosoftAspNetCoreHostingAbstractionsPackageVersion>
|
||||||
|
|
@ -20,6 +21,7 @@
|
||||||
<MicrosoftExtensionsBuffersSourcesPackageVersion>2.1.0-preview3-32110</MicrosoftExtensionsBuffersSourcesPackageVersion>
|
<MicrosoftExtensionsBuffersSourcesPackageVersion>2.1.0-preview3-32110</MicrosoftExtensionsBuffersSourcesPackageVersion>
|
||||||
<MicrosoftExtensionsBuffersTestingSourcesPackageVersion>2.1.0-preview3-32110</MicrosoftExtensionsBuffersTestingSourcesPackageVersion>
|
<MicrosoftExtensionsBuffersTestingSourcesPackageVersion>2.1.0-preview3-32110</MicrosoftExtensionsBuffersTestingSourcesPackageVersion>
|
||||||
<MicrosoftExtensionsConfigurationBinderPackageVersion>2.1.0-preview3-32110</MicrosoftExtensionsConfigurationBinderPackageVersion>
|
<MicrosoftExtensionsConfigurationBinderPackageVersion>2.1.0-preview3-32110</MicrosoftExtensionsConfigurationBinderPackageVersion>
|
||||||
|
<MicrosoftExtensionsConfigurationCommandLinePackageVersion>2.1.0-preview3-32037</MicrosoftExtensionsConfigurationCommandLinePackageVersion>
|
||||||
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.1.0-preview3-32110</MicrosoftExtensionsConfigurationJsonPackageVersion>
|
<MicrosoftExtensionsConfigurationJsonPackageVersion>2.1.0-preview3-32110</MicrosoftExtensionsConfigurationJsonPackageVersion>
|
||||||
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.1.0-preview3-32110</MicrosoftExtensionsDependencyInjectionPackageVersion>
|
<MicrosoftExtensionsDependencyInjectionPackageVersion>2.1.0-preview3-32110</MicrosoftExtensionsDependencyInjectionPackageVersion>
|
||||||
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.1.0-preview3-32110</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
|
<MicrosoftExtensionsLoggingAbstractionsPackageVersion>2.1.0-preview3-32110</MicrosoftExtensionsLoggingAbstractionsPackageVersion>
|
||||||
|
|
@ -40,6 +42,7 @@
|
||||||
<SystemRuntimeCompilerServicesUnsafePackageVersion>4.5.0-preview3-26331-02</SystemRuntimeCompilerServicesUnsafePackageVersion>
|
<SystemRuntimeCompilerServicesUnsafePackageVersion>4.5.0-preview3-26331-02</SystemRuntimeCompilerServicesUnsafePackageVersion>
|
||||||
<SystemSecurityCryptographyCngPackageVersion>4.5.0-preview3-26331-02</SystemSecurityCryptographyCngPackageVersion>
|
<SystemSecurityCryptographyCngPackageVersion>4.5.0-preview3-26331-02</SystemSecurityCryptographyCngPackageVersion>
|
||||||
<SystemThreadingTasksExtensionsPackageVersion>4.5.0-preview3-26331-02</SystemThreadingTasksExtensionsPackageVersion>
|
<SystemThreadingTasksExtensionsPackageVersion>4.5.0-preview3-26331-02</SystemThreadingTasksExtensionsPackageVersion>
|
||||||
|
<Utf8JsonPackageVersion>1.3.7</Utf8JsonPackageVersion>
|
||||||
<XunitAnalyzersPackageVersion>0.8.0</XunitAnalyzersPackageVersion>
|
<XunitAnalyzersPackageVersion>0.8.0</XunitAnalyzersPackageVersion>
|
||||||
<XunitPackageVersion>2.3.1</XunitPackageVersion>
|
<XunitPackageVersion>2.3.1</XunitPackageVersion>
|
||||||
<XunitRunnerVisualStudioPackageVersion>2.4.0-beta.1.build3945</XunitRunnerVisualStudioPackageVersion>
|
<XunitRunnerVisualStudioPackageVersion>2.4.0-beta.1.build3945</XunitRunnerVisualStudioPackageVersion>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue