diff --git a/KestrelHttpServer.sln b/KestrelHttpServer.sln index d78ceec5ad..4280909874 100644 --- a/KestrelHttpServer.sln +++ b/KestrelHttpServer.sln @@ -39,10 +39,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{0EF2AC test\shared\LifetimeNotImplemented.cs = test\shared\LifetimeNotImplemented.cs test\shared\MockConnection.cs = test\shared\MockConnection.cs test\shared\MockFrameControl.cs = test\shared\MockFrameControl.cs + test\shared\MockSocketOutput.cs = test\shared\MockSocketOutput.cs test\shared\MockSystemClock.cs = test\shared\MockSystemClock.cs test\shared\SocketInputExtensions.cs = test\shared\SocketInputExtensions.cs test\shared\TestApplicationErrorLogger.cs = test\shared\TestApplicationErrorLogger.cs test\shared\TestConnection.cs = test\shared\TestConnection.cs + test\shared\TestFrame.cs = test\shared\TestFrame.cs test\shared\TestKestrelTrace.cs = test\shared\TestKestrelTrace.cs test\shared\TestServer.cs = test\shared\TestServer.cs test\shared\TestServiceContext.cs = test\shared\TestServiceContext.cs diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.Performance/Program.cs b/test/Microsoft.AspNetCore.Server.Kestrel.Performance/Program.cs index b627755d76..3e2d92774b 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.Performance/Program.cs +++ b/test/Microsoft.AspNetCore.Server.Kestrel.Performance/Program.cs @@ -2,11 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using BenchmarkDotNet.Environments; -using BenchmarkDotNet.Jobs; -using BenchmarkDotNet.Properties; using BenchmarkDotNet.Running; -using BenchmarkDotNet.Toolchains; namespace Microsoft.AspNetCore.Server.Kestrel.Performance { @@ -36,6 +32,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance { BenchmarkRunner.Run(); } + if (type.HasFlag(BenchmarkType.Writing)) + { + BenchmarkRunner.Run(); + } } } @@ -43,6 +43,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance public enum BenchmarkType : uint { RequestParsing = 1, + Writing = 2, // add new ones in powers of two - e.g. 2,4,8,16... All = uint.MaxValue diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.Performance/Readme.md b/test/Microsoft.AspNetCore.Server.Kestrel.Performance/Readme.md index b98f36ff5c..4088c38007 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.Performance/Readme.md +++ b/test/Microsoft.AspNetCore.Server.Kestrel.Performance/Readme.md @@ -2,10 +2,10 @@ To run a specific benchmark add it as parameter ``` -dotnet run RequestParsing +dotnet run -c Release RequestParsing ``` To run all use `All` as parameter ``` -dotnet run All +dotnet run -c Release All ``` Using no parameter will list all available benchmarks \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.Performance/Writing.cs b/test/Microsoft.AspNetCore.Server.Kestrel.Performance/Writing.cs new file mode 100644 index 0000000000..07d8c9a3bc --- /dev/null +++ b/test/Microsoft.AspNetCore.Server.Kestrel.Performance/Writing.cs @@ -0,0 +1,117 @@ +// 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.Threading; +using System.Threading.Tasks; +using BenchmarkDotNet.Attributes; +using Microsoft.AspNetCore.Server.Kestrel.Internal; +using Microsoft.AspNetCore.Server.Kestrel.Internal.Http; +using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure; +using Microsoft.AspNetCore.Testing; +using Moq; + +namespace Microsoft.AspNetCore.Server.Kestrel.Performance +{ + public class Writing + { + private readonly TestFrame _frame; + private readonly TestFrame _frameChunked; + private readonly byte[] _writeData; + + public Writing() + { + _frame = MakeFrame(); + _frameChunked = MakeFrame(); + _writeData = new byte[1]; + } + + [Setup] + public void Setup() + { + _frame.Reset(); + _frame.RequestHeaders.Add("Content-Length", "1073741824"); + + _frameChunked.Reset(); + _frameChunked.RequestHeaders.Add("Transfer-Encoding", "chunked"); + } + + [Benchmark] + public void Write() + { + _frame.Write(new ArraySegment(_writeData)); + } + + [Benchmark] + public void WriteChunked() + { + _frameChunked.Write(new ArraySegment(_writeData)); + } + + [Benchmark] + public async Task WriteAsync() + { + await _frame.WriteAsync(new ArraySegment(_writeData), default(CancellationToken)); + } + + [Benchmark] + public async Task WriteAsyncChunked() + { + await _frameChunked.WriteAsync(new ArraySegment(_writeData), default(CancellationToken)); + } + + [Benchmark] + public async Task WriteAsyncAwaited() + { + await _frame.WriteAsyncAwaited(new ArraySegment(_writeData), default(CancellationToken)); + } + + [Benchmark] + public async Task WriteAsyncAwaitedChunked() + { + await _frameChunked.WriteAsyncAwaited(new ArraySegment(_writeData), default(CancellationToken)); + } + + [Benchmark] + public async Task ProduceEnd() + { + await _frame.ProduceEndAsync(); + } + + [Benchmark] + public async Task ProduceEndChunked() + { + await _frameChunked.ProduceEndAsync(); + } + + private TestFrame MakeFrame() + { + var ltp = new LoggingThreadPool(Mock.Of()); + var pool = new MemoryPool(); + var socketInput = new SocketInput(pool, ltp); + + var serviceContext = new ServiceContext + { + DateHeaderValueManager = new DateHeaderValueManager(), + ServerOptions = new KestrelServerOptions(), + Log = Mock.Of() + }; + var listenerContext = new ListenerContext(serviceContext) + { + ServerAddress = ServerAddress.FromUrl("http://localhost:5000") + }; + var connectionContext = new ConnectionContext(listenerContext) + { + Input = socketInput, + Output = new MockSocketOutput(), + ConnectionControl = Mock.Of() + }; + + var frame = new TestFrame(application: null, context: connectionContext); + frame.Reset(); + frame.InitializeHeaders(); + + return frame; + } + } +} diff --git a/test/Microsoft.AspNetCore.Server.Kestrel.Performance/project.json b/test/Microsoft.AspNetCore.Server.Kestrel.Performance/project.json index a74be5fefb..4871d8a63c 100644 --- a/test/Microsoft.AspNetCore.Server.Kestrel.Performance/project.json +++ b/test/Microsoft.AspNetCore.Server.Kestrel.Performance/project.json @@ -1,14 +1,15 @@ { "version": "1.0.0-*", "dependencies": { - "BenchmarkDotNet": "0.10.0", - "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*" + "BenchmarkDotNet": "0.10.1", + "Microsoft.AspNetCore.Server.Kestrel": "1.2.0-*", + "Moq": "4.6.36-*" }, "frameworks": { - "netcoreapp1.0": { + "netcoreapp1.1": { "dependencies": { "Microsoft.NETCore.App": { - "version": "1.0.1-*", + "version": "1.1.0-*", "type": "platform" } } @@ -18,16 +19,18 @@ "emitEntryPoint": true, "compile": { "include": [ - "../shared/SocketInputExtensions.cs", - "../shared/TestKestrelTrace.cs", "../shared/TestApplicationErrorLogger.cs", - "../shared/MockConnection.cs" + "../shared/TestFrame.cs", + "../shared/TestKestrelTrace.cs", + "../shared/MockConnection.cs", + "../shared/MockSocketOutput.cs", + "../shared/SocketInputExtensions.cs" ] }, "keyFile": "../../tools/Key.snk", "copyToOutput": { "include": "TestResources/testCert.pfx" - } + }, }, "runtimeOptions": { "configProperties": { diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs index efed448cfe..b9444c0f79 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs +++ b/test/Microsoft.AspNetCore.Server.KestrelTests/FrameTests.cs @@ -11,7 +11,6 @@ using Microsoft.AspNetCore.Server.Kestrel; using Microsoft.AspNetCore.Server.Kestrel.Internal; using Microsoft.AspNetCore.Server.Kestrel.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure; -using Microsoft.AspNetCore.Server.KestrelTests.TestHelpers; using Microsoft.AspNetCore.Testing; using Microsoft.Extensions.Internal; using Moq; @@ -47,7 +46,7 @@ namespace Microsoft.AspNetCore.Server.KestrelTests _connectionContext = new ConnectionContext(listenerContext) { Input = _socketInput, - Output = new MockSocketOuptut(), + Output = new MockSocketOutput(), ConnectionControl = Mock.Of() }; diff --git a/test/Microsoft.AspNetCore.Server.KestrelTests/TestHelpers/MockSocketOuptut.cs b/test/shared/MockSocketOutput.cs similarity index 90% rename from test/Microsoft.AspNetCore.Server.KestrelTests/TestHelpers/MockSocketOuptut.cs rename to test/shared/MockSocketOutput.cs index b5f65900b4..19c115d94e 100644 --- a/test/Microsoft.AspNetCore.Server.KestrelTests/TestHelpers/MockSocketOuptut.cs +++ b/test/shared/MockSocketOutput.cs @@ -8,9 +8,9 @@ using Microsoft.AspNetCore.Server.Kestrel.Internal.Http; using Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure; using Microsoft.Extensions.Internal; -namespace Microsoft.AspNetCore.Server.KestrelTests.TestHelpers +namespace Microsoft.AspNetCore.Testing { - public class MockSocketOuptut : ISocketOutput + public class MockSocketOutput : ISocketOutput { public void ProducingComplete(MemoryPoolIterator end) { diff --git a/test/shared/TestFrame.cs b/test/shared/TestFrame.cs new file mode 100644 index 0000000000..4ccba9bd4a --- /dev/null +++ b/test/shared/TestFrame.cs @@ -0,0 +1,22 @@ +// 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.Threading.Tasks; +using Microsoft.AspNetCore.Hosting.Server; +using Microsoft.AspNetCore.Server.Kestrel.Internal.Http; + +namespace Microsoft.AspNetCore.Testing +{ + public class TestFrame : Frame + { + public TestFrame(IHttpApplication application, ConnectionContext context) + : base(application, context) + { + } + + public Task ProduceEndAsync() + { + return ProduceEnd(); + } + } +} \ No newline at end of file