Browse Source

ASP.NET Core Platform Sync (#5579)

* ASP.NET Core Platform Sync

* Remove redundant read

* Combine preamble

* fix default
Ben Adams 5 years ago
parent
commit
0e0a0e5edb
22 changed files with 242 additions and 198 deletions
  1. 10 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/AsciiString.cs
  2. 9 17
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Fortunes.cs
  3. 87 17
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.HttpConnection.cs
  4. 15 23
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Json.cs
  5. 4 17
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.MultipleQueries.cs
  6. 8 22
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Plaintext.cs
  7. 4 17
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.SingleQuery.cs
  8. 4 17
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Updates.cs
  9. 65 42
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.cs
  10. 3 3
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkConfigurationHelpers.cs
  11. 0 2
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BufferExtensions.cs
  12. 3 1
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BufferWriter.cs
  13. 9 3
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/DateHeader.cs
  14. 0 1
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/IHttpConnection.cs
  15. 4 5
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/PlatformBenchmarks.csproj
  16. 8 2
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Program.cs
  17. 1 1
      frameworks/CSharp/aspnetcore/aspcore-ado-my.dockerfile
  18. 1 1
      frameworks/CSharp/aspnetcore/aspcore-ado-pg-up.dockerfile
  19. 1 1
      frameworks/CSharp/aspnetcore/aspcore-ado-pg.dockerfile
  20. 1 1
      frameworks/CSharp/aspnetcore/aspcore-rhtx-pg-up.dockerfile
  21. 1 1
      frameworks/CSharp/aspnetcore/aspcore-rhtx-pg.dockerfile
  22. 4 4
      frameworks/CSharp/aspnetcore/benchmark_config.json

+ 10 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/AsciiString.cs

@@ -12,6 +12,8 @@ namespace PlatformBenchmarks
 
 
         public AsciiString(string s) => _data = Encoding.ASCII.GetBytes(s);
         public AsciiString(string s) => _data = Encoding.ASCII.GetBytes(s);
 
 
+        private AsciiString(byte[] b) => _data = b;
+
         public int Length => _data.Length;
         public int Length => _data.Length;
 
 
         public ReadOnlySpan<byte> AsSpan() => _data;
         public ReadOnlySpan<byte> AsSpan() => _data;
@@ -31,6 +33,14 @@ namespace PlatformBenchmarks
         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 bool Equals(object other) => (other is AsciiString) && Equals((AsciiString)other);
 
 
+        public static AsciiString operator +(AsciiString a, AsciiString b)
+        {
+            var result = new byte[a.Length + b.Length];
+            a._data.CopyTo(result, 0);
+            b._data.CopyTo(result, a.Length);
+            return new AsciiString(result);
+        }
+
         public override int GetHashCode()
         public override int GetHashCode()
         {
         {
             // Copied from x64 version of string.GetLegacyNonRandomizedHashCode()
             // Copied from x64 version of string.GetLegacyNonRandomizedHashCode()

+ 9 - 17
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Fortunes.cs

@@ -5,12 +5,17 @@ using System.Collections.Generic;
 using System.IO.Pipelines;
 using System.IO.Pipelines;
 using System.Text.Encodings.Web;
 using System.Text.Encodings.Web;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
 
 
 namespace PlatformBenchmarks
 namespace PlatformBenchmarks
 {
 {
     public partial class BenchmarkApplication
     public partial class BenchmarkApplication
     {
     {
+        private readonly static AsciiString _fortunesPreamble =
+            _http11OK +
+            _headerServer + _crlf +
+            _headerContentTypeHtml + _crlf +
+            _headerContentLength;
+
         private async Task Fortunes(PipeWriter pipeWriter)
         private async Task Fortunes(PipeWriter pipeWriter)
         {
         {
             OutputFortunes(pipeWriter, await Db.LoadFortunesRows());
             OutputFortunes(pipeWriter, await Db.LoadFortunesRows());
@@ -20,26 +25,13 @@ namespace PlatformBenchmarks
         {
         {
             var writer = GetWriter(pipeWriter);
             var writer = GetWriter(pipeWriter);
 
 
-            // HTTP 1.1 OK
-            writer.Write(_http11OK);
-
-            // Server headers
-            writer.Write(_headerServer);
-
-            // Date header
-            writer.Write(DateHeader.HeaderBytes);
-
-            // Content-Type header
-            writer.Write(_headerContentTypeHtml);
-
-            // Content-Length header
-            writer.Write(_headerContentLength);
+            writer.Write(_fortunesPreamble);
 
 
             var lengthWriter = writer;
             var lengthWriter = writer;
             writer.Write(_contentLengthGap);
             writer.Write(_contentLengthGap);
 
 
-            // End of headers
-            writer.Write(_eoh);
+            // Date header
+            writer.Write(DateHeader.HeaderBytes);
 
 
             var bodyStart = writer.Buffered;
             var bodyStart = writer.Buffered;
             // Body
             // Body

+ 87 - 17
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.HttpConnection.cs

@@ -48,23 +48,67 @@ namespace PlatformBenchmarks
             return HtmlEncoder.Create(settings);
             return HtmlEncoder.Create(settings);
         }
         }
 
 
+#if !DATABASE
         private async Task ProcessRequestsAsync()
         private async Task ProcessRequestsAsync()
         {
         {
             while (true)
             while (true)
             {
             {
-                var task = Reader.ReadAsync();
+                var readResult = await Reader.ReadAsync();
 
 
-                if (!task.IsCompleted)
+                if (!HandleRequest(readResult))
                 {
                 {
-                    // No more data in the input
-                    await OnReadCompletedAsync();
+                    return;
                 }
                 }
 
 
-                var result = await task;
-                var buffer = result.Buffer;
+                await Writer.FlushAsync();
+            }
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private bool HandleRequest(in ReadResult result)
+        {
+            var buffer = result.Buffer;
+            var writer = GetWriter(Writer);
+
+            while (true)
+            {
+                if (!ParseHttpRequest(ref buffer, result.IsCompleted, out var examined))
+                {
+                    return false;
+                }
+
+                if (_state == State.Body)
+                {
+                    ProcessRequest(ref writer);
+
+                    _state = State.StartLine;
+
+                    if (!buffer.IsEmpty)
+                    {
+                        // More input data to parse
+                        continue;
+                    }
+                }
+
+                // No more input or incomplete data, Advance the Reader
+                Reader.AdvanceTo(buffer.Start, examined);
+                break;
+            }
+
+            writer.Commit();
+            return true;
+        }
+#else
+        private async Task ProcessRequestsAsync()
+        {
+            while (true)
+            {
+                var readResult = await Reader.ReadAsync();
+
+                var buffer = readResult.Buffer;
                 while (true)
                 while (true)
                 {
                 {
-                    if (!ParseHttpRequest(ref buffer, result.IsCompleted, out var examined))
+                    if (!ParseHttpRequest(ref buffer, readResult.IsCompleted, out var examined))
                     {
                     {
                         return;
                         return;
                     }
                     }
@@ -86,18 +130,19 @@ namespace PlatformBenchmarks
                     Reader.AdvanceTo(buffer.Start, examined);
                     Reader.AdvanceTo(buffer.Start, examined);
                     break;
                     break;
                 }
                 }
+
+                await Writer.FlushAsync();
             }
             }
         }
         }
-
+#endif
         private bool ParseHttpRequest(ref ReadOnlySequence<byte> buffer, bool isCompleted, out SequencePosition examined)
         private bool ParseHttpRequest(ref ReadOnlySequence<byte> buffer, bool isCompleted, out SequencePosition examined)
         {
         {
             examined = buffer.End;
             examined = buffer.End;
-
-            var consumed = buffer.Start;
             var state = _state;
             var state = _state;
 
 
             if (!buffer.IsEmpty)
             if (!buffer.IsEmpty)
             {
             {
+                SequencePosition consumed;
                 if (state == State.StartLine)
                 if (state == State.StartLine)
                 {
                 {
                     if (Parser.ParseRequestLine(new ParsingAdapter(this), buffer, out consumed, out examined))
                     if (Parser.ParseRequestLine(new ParsingAdapter(this), buffer, out consumed, out examined))
@@ -141,18 +186,30 @@ namespace PlatformBenchmarks
             return true;
             return true;
         }
         }
 
 
-        public void OnHeader(Span<byte> name, Span<byte> value)
+#if NETCOREAPP5_0
+
+        public void OnStaticIndexedHeader(int index)
         {
         {
         }
         }
 
 
-        public void OnHeadersComplete()
+        public void OnStaticIndexedHeader(int index, ReadOnlySpan<byte> value)
         {
         {
         }
         }
 
 
-        public async ValueTask OnReadCompletedAsync()
+        public void OnHeader(ReadOnlySpan<byte> name, ReadOnlySpan<byte> value)
+        {
+        }
+        public void OnHeadersComplete(bool endStream)
+        {
+        }
+#else
+        public void OnHeader(Span<byte> name, Span<byte> value)
         {
         {
-            await Writer.FlushAsync();
         }
         }
+        public void OnHeadersComplete()
+        {
+        }
+#endif
 
 
         private static void ThrowUnexpectedEndOfData()
         private static void ThrowUnexpectedEndOfData()
         {
         {
@@ -194,14 +251,27 @@ namespace PlatformBenchmarks
             public ParsingAdapter(BenchmarkApplication requestHandler)
             public ParsingAdapter(BenchmarkApplication requestHandler)
                 => RequestHandler = requestHandler;
                 => RequestHandler = requestHandler;
 
 
+#if NETCOREAPP5_0
+            public void OnStaticIndexedHeader(int index) 
+                => RequestHandler.OnStaticIndexedHeader(index);
+
+            public void OnStaticIndexedHeader(int index, ReadOnlySpan<byte> value)
+                => RequestHandler.OnStaticIndexedHeader(index, value);
+
+            public void OnHeader(ReadOnlySpan<byte> name, ReadOnlySpan<byte> value)
+                => RequestHandler.OnHeader(name, value);
+
+            public void OnHeadersComplete(bool endStream)
+                => RequestHandler.OnHeadersComplete(endStream);
+#else
             public void OnHeader(Span<byte> name, Span<byte> value)
             public void OnHeader(Span<byte> name, Span<byte> value)
                 => RequestHandler.OnHeader(name, value);
                 => RequestHandler.OnHeader(name, value);
+            public void OnHeadersComplete()
+                => RequestHandler.OnHeadersComplete();
+#endif
 
 
             public void OnStartLine(HttpMethod method, HttpVersion version, Span<byte> target, Span<byte> path, Span<byte> query, Span<byte> customMethod, bool pathEncoded)
             public void OnStartLine(HttpMethod method, HttpVersion version, Span<byte> target, Span<byte> path, Span<byte> query, Span<byte> customMethod, bool pathEncoded)
                 => RequestHandler.OnStartLine(method, version, target, path, query, customMethod, pathEncoded);
                 => RequestHandler.OnStartLine(method, version, target, path, query, customMethod, pathEncoded);
-
-            public void OnHeadersComplete()
-                => RequestHandler.OnHeadersComplete();
         }
         }
     }
     }
 }
 }

+ 15 - 23
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Json.cs

@@ -1,42 +1,34 @@
 // Copyright (c) .NET Foundation. All rights reserved.
 // 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.
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 
 
-using System.IO.Pipelines;
 using System.Text.Json;
 using System.Text.Json;
-using System.Text.Json.Serialization;
-using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
 
 
 namespace PlatformBenchmarks
 namespace PlatformBenchmarks
 {
 {
     public partial class BenchmarkApplication
     public partial class BenchmarkApplication
     {
     {
-        private static void Json(PipeWriter pipeWriter)
-        {
-            var writer = GetWriter(pipeWriter);
+        private static readonly uint _jsonPayloadSize = (uint)JsonSerializer.SerializeToUtf8Bytes(new JsonMessage { message = "Hello, World!" }, SerializerOptions).Length;
 
 
-            // HTTP 1.1 OK
-            writer.Write(_http11OK);
+        private readonly static AsciiString _jsonPreamble =
+            _http11OK +
+            _headerServer + _crlf +
+            _headerContentTypeJson + _crlf +
+            _headerContentLength + _jsonPayloadSize.ToString();
 
 
-            // Server headers
-            writer.Write(_headerServer);
+        private static void Json(ref BufferWriter<WriterAdapter> writer)
+        {
+            writer.Write(_jsonPreamble);
 
 
             // Date header
             // Date header
             writer.Write(DateHeader.HeaderBytes);
             writer.Write(DateHeader.HeaderBytes);
 
 
-            // Content-Type header
-            writer.Write(_headerContentTypeJson);
-
-            // Content-Length header
-            writer.Write(_headerContentLength);
-            var jsonPayload = JsonSerializer.SerializeToUtf8Bytes(new JsonMessage { message = "Hello, World!" }, SerializerOptions);
-            writer.WriteNumeric((uint)jsonPayload.Length);
-
-            // End of headers
-            writer.Write(_eoh);
-
-            // Body
-            writer.Write(jsonPayload);
             writer.Commit();
             writer.Commit();
+
+            using var utf8jsonWriter = new Utf8JsonWriter(writer.Output);
+            JsonSerializer.Serialize(
+                utf8jsonWriter,
+                new JsonMessage { message = "Hello, World!" },
+                SerializerOptions);
         }
         }
     }
     }
 }
 }

+ 4 - 17
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.MultipleQueries.cs

@@ -3,9 +3,7 @@
 
 
 using System.IO.Pipelines;
 using System.IO.Pipelines;
 using System.Text.Json;
 using System.Text.Json;
-using System.Text.Json.Serialization;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
 
 
 namespace PlatformBenchmarks
 namespace PlatformBenchmarks
 {
 {
@@ -20,25 +18,14 @@ namespace PlatformBenchmarks
         {
         {
             var writer = GetWriter(pipeWriter);
             var writer = GetWriter(pipeWriter);
 
 
-            // HTTP 1.1 OK
-            writer.Write(_http11OK);
+            writer.Write(_dbPreamble);
 
 
-            // Server headers
-            writer.Write(_headerServer);
-
-            // Date header
-            writer.Write(DateHeader.HeaderBytes);
-
-            // Content-Type header
-            writer.Write(_headerContentTypeJson);
-
-            // Content-Length header
-            writer.Write(_headerContentLength);
+            // Content-Length
             var jsonPayload = JsonSerializer.SerializeToUtf8Bytes(rows, SerializerOptions);
             var jsonPayload = JsonSerializer.SerializeToUtf8Bytes(rows, SerializerOptions);
             writer.WriteNumeric((uint)jsonPayload.Length);
             writer.WriteNumeric((uint)jsonPayload.Length);
 
 
-            // End of headers
-            writer.Write(_eoh);
+            // Date header
+            writer.Write(DateHeader.HeaderBytes);
 
 
             // Body
             // Body
             writer.Write(jsonPayload);
             writer.Write(jsonPayload);

+ 8 - 22
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Plaintext.cs

@@ -1,39 +1,25 @@
 // Copyright (c) .NET Foundation. All rights reserved.
 // 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.
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 
 
-using System.IO.Pipelines;
-using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
-
 namespace PlatformBenchmarks
 namespace PlatformBenchmarks
 {
 {
     public partial class BenchmarkApplication
     public partial class BenchmarkApplication
     {
     {
-        private static void PlainText(PipeWriter pipeWriter)
-        {
-            var writer = GetWriter(pipeWriter);
+        private readonly static AsciiString _plaintextPreamble =
+            _http11OK +
+            _headerServer + _crlf +
+            _headerContentTypeText + _crlf +
+            _headerContentLength + _plainTextBody.Length.ToString();
 
 
-            // HTTP 1.1 OK
-            writer.Write(_http11OK);
-
-            // Server headers
-            writer.Write(_headerServer);
+        private static void PlainText(ref BufferWriter<WriterAdapter> writer)
+        {
+            writer.Write(_plaintextPreamble);
 
 
             // Date header
             // Date header
             writer.Write(DateHeader.HeaderBytes);
             writer.Write(DateHeader.HeaderBytes);
 
 
-            // Content-Type header
-            writer.Write(_headerContentTypeText);
-
-            // Content-Length header
-            writer.Write(_headerContentLength);
-            writer.WriteNumeric((uint)_plainTextBody.Length);
-
-            // End of headers
-            writer.Write(_eoh);
-
             // Body
             // Body
             writer.Write(_plainTextBody);
             writer.Write(_plainTextBody);
-            writer.Commit();
         }
         }
     }
     }
 }
 }

+ 4 - 17
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.SingleQuery.cs

@@ -3,9 +3,7 @@
 
 
 using System.IO.Pipelines;
 using System.IO.Pipelines;
 using System.Text.Json;
 using System.Text.Json;
-using System.Text.Json.Serialization;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
 
 
 namespace PlatformBenchmarks
 namespace PlatformBenchmarks
 {
 {
@@ -20,25 +18,14 @@ namespace PlatformBenchmarks
         {
         {
             var writer = GetWriter(pipeWriter);
             var writer = GetWriter(pipeWriter);
 
 
-            // HTTP 1.1 OK
-            writer.Write(_http11OK);
+            writer.Write(_dbPreamble);
 
 
-            // Server headers
-            writer.Write(_headerServer);
-
-            // Date header
-            writer.Write(DateHeader.HeaderBytes);
-
-            // Content-Type header
-            writer.Write(_headerContentTypeJson);
-
-            // Content-Length header
-            writer.Write(_headerContentLength);
+            // Content-Length
             var jsonPayload = JsonSerializer.SerializeToUtf8Bytes(row, SerializerOptions);
             var jsonPayload = JsonSerializer.SerializeToUtf8Bytes(row, SerializerOptions);
             writer.WriteNumeric((uint)jsonPayload.Length);
             writer.WriteNumeric((uint)jsonPayload.Length);
 
 
-            // End of headers
-            writer.Write(_eoh);
+            // Date header
+            writer.Write(DateHeader.HeaderBytes);
 
 
             // Body
             // Body
             writer.Write(jsonPayload);
             writer.Write(jsonPayload);

+ 4 - 17
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Updates.cs

@@ -3,9 +3,7 @@
 
 
 using System.IO.Pipelines;
 using System.IO.Pipelines;
 using System.Text.Json;
 using System.Text.Json;
-using System.Text.Json.Serialization;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
-using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
 
 
 namespace PlatformBenchmarks
 namespace PlatformBenchmarks
 {
 {
@@ -20,25 +18,14 @@ namespace PlatformBenchmarks
         {
         {
             var writer = GetWriter(pipeWriter);
             var writer = GetWriter(pipeWriter);
 
 
-            // HTTP 1.1 OK
-            writer.Write(_http11OK);
+            writer.Write(_dbPreamble);
 
 
-            // Server headers
-            writer.Write(_headerServer);
-
-            // Date header
-            writer.Write(DateHeader.HeaderBytes);
-
-            // Content-Type header
-            writer.Write(_headerContentTypeJson);
-
-            // Content-Length header
-            writer.Write(_headerContentLength);
+            // Content-Length
             var jsonPayload = JsonSerializer.SerializeToUtf8Bytes(rows, SerializerOptions);
             var jsonPayload = JsonSerializer.SerializeToUtf8Bytes(rows, SerializerOptions);
             writer.WriteNumeric((uint)jsonPayload.Length);
             writer.WriteNumeric((uint)jsonPayload.Length);
 
 
-            // End of headers
-            writer.Write(_eoh);
+            // Date header
+            writer.Write(DateHeader.HeaderBytes);
 
 
             // Body
             // Body
             writer.Write(jsonPayload);
             writer.Write(jsonPayload);

+ 65 - 42
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.cs

@@ -5,7 +5,6 @@ using System;
 using System.Buffers.Text;
 using System.Buffers.Text;
 using System.IO.Pipelines;
 using System.IO.Pipelines;
 using System.Text.Json;
 using System.Text.Json;
-using System.Text.Json.Serialization;
 using System.Threading.Tasks;
 using System.Threading.Tasks;
 using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
 using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
 
 
@@ -19,17 +18,23 @@ namespace PlatformBenchmarks
         private readonly static AsciiString _crlf = "\r\n";
         private readonly static AsciiString _crlf = "\r\n";
         private readonly static AsciiString _eoh = "\r\n\r\n"; // End Of Headers
         private readonly static AsciiString _eoh = "\r\n\r\n"; // End Of Headers
         private readonly static AsciiString _http11OK = "HTTP/1.1 200 OK\r\n";
         private readonly static AsciiString _http11OK = "HTTP/1.1 200 OK\r\n";
-        private readonly static AsciiString _headerServer = "Server: Custom";
+        private readonly static AsciiString _headerServer = "Server: K";
         private readonly static AsciiString _headerContentLength = "Content-Length: ";
         private readonly static AsciiString _headerContentLength = "Content-Length: ";
-        private readonly static AsciiString _headerContentLengthZero = "Content-Length: 0\r\n";
-        private readonly static AsciiString _headerContentTypeText = "Content-Type: text/plain\r\n";
-        private readonly static AsciiString _headerContentTypeJson = "Content-Type: application/json\r\n";
-        private readonly static AsciiString _headerContentTypeHtml = "Content-Type: text/html; charset=UTF-8\r\n";
+        private readonly static AsciiString _headerContentLengthZero = "Content-Length: 0";
+        private readonly static AsciiString _headerContentTypeText = "Content-Type: text/plain";
+        private readonly static AsciiString _headerContentTypeJson = "Content-Type: application/json";
+        private readonly static AsciiString _headerContentTypeHtml = "Content-Type: text/html; charset=UTF-8";
+
+        private readonly static AsciiString _dbPreamble =
+            _http11OK +
+            _headerServer + _crlf +
+            _headerContentTypeJson + _crlf +
+            _headerContentLength;
 
 
         private readonly static AsciiString _plainTextBody = "Hello, World!";
         private readonly static AsciiString _plainTextBody = "Hello, World!";
 
 
         private static readonly JsonSerializerOptions SerializerOptions = new JsonSerializerOptions();
         private static readonly JsonSerializerOptions SerializerOptions = new JsonSerializerOptions();
-        
+
         private readonly static AsciiString _fortunesTableStart = "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>";
         private readonly static AsciiString _fortunesTableStart = "<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>";
         private readonly static AsciiString _fortunesRowStart = "<tr><td>";
         private readonly static AsciiString _fortunesRowStart = "<tr><td>";
         private readonly static AsciiString _fortunesColumn = "</td><td>";
         private readonly static AsciiString _fortunesColumn = "</td><td>";
@@ -42,38 +47,44 @@ namespace PlatformBenchmarks
         public static class Paths
         public static class Paths
         {
         {
             public readonly static AsciiString SingleQuery = "/db";
             public readonly static AsciiString SingleQuery = "/db";
-            public readonly static AsciiString Json = "/json";
+            public readonly static AsciiString Json = "/j";
             public readonly static AsciiString Fortunes = "/fortunes";
             public readonly static AsciiString Fortunes = "/fortunes";
-            public readonly static AsciiString Plaintext = "/plaintext";
+            public readonly static AsciiString Plaintext = "/p";
             public readonly static AsciiString Updates = "/updates/queries=";
             public readonly static AsciiString Updates = "/updates/queries=";
             public readonly static AsciiString MultipleQueries = "/queries/queries=";
             public readonly static AsciiString MultipleQueries = "/queries/queries=";
         }
         }
 
 
         private RequestType _requestType;
         private RequestType _requestType;
+#if DATABASE
         private int _queries;
         private int _queries;
-
+#endif
         public void OnStartLine(HttpMethod method, HttpVersion version, Span<byte> target, Span<byte> path, Span<byte> query, Span<byte> customMethod, bool pathEncoded)
         public void OnStartLine(HttpMethod method, HttpVersion version, Span<byte> target, Span<byte> path, Span<byte> query, Span<byte> customMethod, bool pathEncoded)
         {
         {
             var requestType = RequestType.NotRecognized;
             var requestType = RequestType.NotRecognized;
             if (method == HttpMethod.Get)
             if (method == HttpMethod.Get)
             {
             {
+#if !DATABASE
+                if (path.Length >= 2 && path[0] == '/')
+                {
+                    if (path[1] == 'j')
+                    {
+                        requestType = RequestType.Json;
+                    }
+                    else if (path[1] == 'p')
+                    {
+                        requestType = RequestType.PlainText;
+                    }
+                }
+#else
                 var pathLength = path.Length;
                 var pathLength = path.Length;
                 if (Paths.SingleQuery.Length <= pathLength && path.StartsWith(Paths.SingleQuery))
                 if (Paths.SingleQuery.Length <= pathLength && path.StartsWith(Paths.SingleQuery))
                 {
                 {
                     requestType = RequestType.SingleQuery;
                     requestType = RequestType.SingleQuery;
                 }
                 }
-                else if (Paths.Json.Length <= pathLength && path.StartsWith(Paths.Json))
-                {
-                    requestType = RequestType.Json;
-                }
                 else if (Paths.Fortunes.Length <= pathLength && path.StartsWith(Paths.Fortunes))
                 else if (Paths.Fortunes.Length <= pathLength && path.StartsWith(Paths.Fortunes))
                 {
                 {
                     requestType = RequestType.Fortunes;
                     requestType = RequestType.Fortunes;
                 }
                 }
-                else if (Paths.Plaintext.Length <= pathLength && path.StartsWith(Paths.Plaintext))
-                {
-                    requestType = RequestType.PlainText;
-                }
                 else if (Paths.Updates.Length <= pathLength && path.StartsWith(Paths.Updates))
                 else if (Paths.Updates.Length <= pathLength && path.StartsWith(Paths.Updates))
                 {
                 {
                     _queries = ParseQueries(path, Paths.Updates.Length);
                     _queries = ParseQueries(path, Paths.Updates.Length);
@@ -84,11 +95,30 @@ namespace PlatformBenchmarks
                     _queries = ParseQueries(path, Paths.MultipleQueries.Length);
                     _queries = ParseQueries(path, Paths.MultipleQueries.Length);
                     requestType = RequestType.MultipleQueries;
                     requestType = RequestType.MultipleQueries;
                 }
                 }
+#endif
             }
             }
 
 
             _requestType = requestType;
             _requestType = requestType;
         }
         }
 
 
+
+#if !DATABASE
+        private void ProcessRequest(ref BufferWriter<WriterAdapter> writer)
+        {
+            if (_requestType == RequestType.PlainText)
+            {
+                PlainText(ref writer);
+            }
+            else if (_requestType == RequestType.Json)
+            {
+                Json(ref writer);
+            }
+            else
+            {
+                Default(ref writer);
+            }
+        }
+#else
         private static int ParseQueries(Span<byte> path, int pathLength)
         private static int ParseQueries(Span<byte> path, int pathLength)
         {
         {
             if (!Utf8Parser.TryParse(path.Slice(pathLength), out int queries, out _) || queries < 1)
             if (!Utf8Parser.TryParse(path.Slice(pathLength), out int queries, out _) || queries < 1)
@@ -103,19 +133,11 @@ namespace PlatformBenchmarks
             return queries;
             return queries;
         }
         }
 
 
-        public Task ProcessRequestAsync()
+        private Task ProcessRequestAsync()
         {
         {
+            Task task;
             var requestType = _requestType;
             var requestType = _requestType;
-            var task = Task.CompletedTask;
-            if (requestType == RequestType.PlainText)
-            {
-                PlainText(Writer);
-            }
-            else if (requestType == RequestType.Json)
-            {
-                Json(Writer);
-            }
-            else if (requestType == RequestType.Fortunes)
+            if (requestType == RequestType.Fortunes)
             {
             {
                 task = Fortunes(Writer);
                 task = Fortunes(Writer);
             }
             }
@@ -134,6 +156,7 @@ namespace PlatformBenchmarks
             else
             else
             {
             {
                 Default(Writer);
                 Default(Writer);
+                task = Task.CompletedTask;
             }
             }
 
 
             return task;
             return task;
@@ -142,22 +165,22 @@ namespace PlatformBenchmarks
         private static void Default(PipeWriter pipeWriter)
         private static void Default(PipeWriter pipeWriter)
         {
         {
             var writer = GetWriter(pipeWriter);
             var writer = GetWriter(pipeWriter);
-
-            // HTTP 1.1 OK
-            writer.Write(_http11OK);
-
-            // Server headers
-            writer.Write(_headerServer);
+            Default(ref writer);
+            writer.Commit();
+        }
+#endif
+        private readonly static AsciiString _defaultPreamble =
+            _http11OK +
+            _headerServer + _crlf +
+            _headerContentTypeText + _crlf +
+            _headerContentLengthZero;
+
+        private static void Default(ref BufferWriter<WriterAdapter> writer)
+        {
+            writer.Write(_defaultPreamble);
 
 
             // Date header
             // Date header
             writer.Write(DateHeader.HeaderBytes);
             writer.Write(DateHeader.HeaderBytes);
-
-            // Content-Length 0
-            writer.Write(_headerContentLengthZero);
-
-            // End of headers
-            writer.Write(_crlf);
-            writer.Commit();
         }
         }
 
 
         private enum RequestType
         private enum RequestType

+ 3 - 3
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkConfigurationHelpers.cs

@@ -23,8 +23,8 @@ namespace PlatformBenchmarks
             var threadCountRaw = builder.GetSetting("threadCount");
             var threadCountRaw = builder.GetSetting("threadCount");
             int? theadCount = null;
             int? theadCount = null;
 
 
-            if (!string.IsNullOrEmpty(threadCountRaw) && 
-                Int32.TryParse(threadCountRaw, out var value))
+            if (!string.IsNullOrEmpty(threadCountRaw) &&
+                int.TryParse(threadCountRaw, out var value))
             {
             {
                 theadCount = value;
                 theadCount = value;
             }
             }
@@ -49,7 +49,7 @@ namespace PlatformBenchmarks
 
 
             return builder;
             return builder;
         }
         }
-        
+
         public static IPEndPoint CreateIPEndPoint(this IConfiguration config)
         public static IPEndPoint CreateIPEndPoint(this IConfiguration config)
         {
         {
             var url = config["server.urls"] ?? config["urls"];
             var url = config["server.urls"] ?? config["urls"];

+ 0 - 2
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BufferExtensions.cs

@@ -3,9 +3,7 @@
 
 
 using System;
 using System;
 using System.Buffers;
 using System.Buffers;
-using System.Buffers.Text;
 using System.Runtime.CompilerServices;
 using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
 using System.Text;
 using System.Text;
 
 
 namespace PlatformBenchmarks
 namespace PlatformBenchmarks

+ 3 - 1
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BufferWriter.cs

@@ -17,13 +17,15 @@ namespace PlatformBenchmarks
         {
         {
             _buffered = 0;
             _buffered = 0;
             _output = output;
             _output = output;
-            _span = output.GetSpan();
+            _span = output.GetSpan(sizeHint: 16 * 160);
         }
         }
 
 
         public Span<byte> Span => _span;
         public Span<byte> Span => _span;
 
 
         public int Buffered => _buffered;
         public int Buffered => _buffered;
 
 
+        public T Output => _output;
+
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public void Commit()
         public void Commit()
         {
         {

+ 9 - 3
frameworks/CSharp/aspnetcore/PlatformBenchmarks/DateHeader.cs

@@ -23,18 +23,24 @@ namespace PlatformBenchmarks
             SetDateValues(DateTimeOffset.UtcNow);
             SetDateValues(DateTimeOffset.UtcNow);
         }, null, 1000, 1000);
         }, null, 1000, 1000);
 
 
-        private static byte[] s_headerBytesMaster = new byte[prefixLength + dateTimeRLength + suffixLength];
-        private static byte[] s_headerBytesScratch = new byte[prefixLength + dateTimeRLength + suffixLength];
+        private static byte[] s_headerBytesMaster = new byte[prefixLength + dateTimeRLength + 2 * suffixLength];
+        private static byte[] s_headerBytesScratch = new byte[prefixLength + dateTimeRLength + 2 * suffixLength];
 
 
         static DateHeader()
         static DateHeader()
         {
         {
             var utf8 = Encoding.ASCII.GetBytes("\r\nDate: ").AsSpan();
             var utf8 = Encoding.ASCII.GetBytes("\r\nDate: ").AsSpan();
+
             utf8.CopyTo(s_headerBytesMaster);
             utf8.CopyTo(s_headerBytesMaster);
             utf8.CopyTo(s_headerBytesScratch);
             utf8.CopyTo(s_headerBytesScratch);
             s_headerBytesMaster[suffixIndex] = (byte)'\r';
             s_headerBytesMaster[suffixIndex] = (byte)'\r';
             s_headerBytesMaster[suffixIndex + 1] = (byte)'\n';
             s_headerBytesMaster[suffixIndex + 1] = (byte)'\n';
+            s_headerBytesMaster[suffixIndex + 2] = (byte)'\r';
+            s_headerBytesMaster[suffixIndex + 3] = (byte)'\n';
             s_headerBytesScratch[suffixIndex] = (byte)'\r';
             s_headerBytesScratch[suffixIndex] = (byte)'\r';
             s_headerBytesScratch[suffixIndex + 1] = (byte)'\n';
             s_headerBytesScratch[suffixIndex + 1] = (byte)'\n';
+            s_headerBytesScratch[suffixIndex + 2] = (byte)'\r';
+            s_headerBytesScratch[suffixIndex + 3] = (byte)'\n';
+
             SetDateValues(DateTimeOffset.UtcNow);
             SetDateValues(DateTimeOffset.UtcNow);
             SyncDateTimer();
             SyncDateTimer();
         }
         }
@@ -47,7 +53,7 @@ namespace PlatformBenchmarks
         {
         {
             lock (s_headerBytesScratch)
             lock (s_headerBytesScratch)
             {
             {
-                if (!Utf8Formatter.TryFormat(value, s_headerBytesScratch.AsSpan(prefixLength), out int written, 'R'))
+                if (!Utf8Formatter.TryFormat(value, s_headerBytesScratch.AsSpan(prefixLength), out var written, 'R'))
                 {
                 {
                     throw new Exception("date time format failed");
                     throw new Exception("date time format failed");
                 }
                 }

+ 0 - 1
frameworks/CSharp/aspnetcore/PlatformBenchmarks/IHttpConnection.cs

@@ -12,6 +12,5 @@ namespace PlatformBenchmarks
         PipeReader Reader { get; set; }
         PipeReader Reader { get; set; }
         PipeWriter Writer { get; set; }
         PipeWriter Writer { get; set; }
         Task ExecuteAsync();
         Task ExecuteAsync();
-        ValueTask OnReadCompletedAsync();
     }
     }
 }
 }

+ 4 - 5
frameworks/CSharp/aspnetcore/PlatformBenchmarks/PlatformBenchmarks.csproj

@@ -6,6 +6,10 @@
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
   </PropertyGroup>
   </PropertyGroup>
   
   
+  <PropertyGroup>
+    <DefineConstants Condition=" '$(IsDatabase)' == 'true' ">$(DefineConstants);DATABASE</DefineConstants>
+  </PropertyGroup>
+  
   <ItemGroup>
   <ItemGroup>
       <None Include="appsettings.json" CopyToOutputDirectory="PreserveNewest" />
       <None Include="appsettings.json" CopyToOutputDirectory="PreserveNewest" />
   </ItemGroup>
   </ItemGroup>
@@ -14,10 +18,5 @@
     <PackageReference Include="Npgsql" Version="4.1.2" />
     <PackageReference Include="Npgsql" Version="4.1.2" />
     <PackageReference Include="MySqlConnector" Version="0.62.0-beta5" />
     <PackageReference Include="MySqlConnector" Version="0.62.0-beta5" />
     <PackageReference Include="RedHat.AspNetCore.Server.Kestrel.Transport.Linux" Version="3.0.0-*" />
     <PackageReference Include="RedHat.AspNetCore.Server.Kestrel.Transport.Linux" Version="3.0.0-*" />
-
-    <PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.0" />
-    <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.0" />
-    <PackageReference Include="Microsoft.Extensions.Options" Version="3.1.0" />
-    
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 8 - 2
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Program.cs

@@ -4,10 +4,11 @@
 using System;
 using System;
 using System.Net;
 using System.Net;
 using Microsoft.AspNetCore.Hosting;
 using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.Configuration;
+#if DATABASE
 using Npgsql;
 using Npgsql;
 using MySql.Data.MySqlClient;
 using MySql.Data.MySqlClient;
+#endif
 
 
 namespace PlatformBenchmarks
 namespace PlatformBenchmarks
 {
 {
@@ -20,12 +21,15 @@ namespace PlatformBenchmarks
             Args = args;
             Args = args;
 
 
             Console.WriteLine(BenchmarkApplication.ApplicationName);
             Console.WriteLine(BenchmarkApplication.ApplicationName);
+#if !DATABASE
             Console.WriteLine(BenchmarkApplication.Paths.Plaintext);
             Console.WriteLine(BenchmarkApplication.Paths.Plaintext);
             Console.WriteLine(BenchmarkApplication.Paths.Json);
             Console.WriteLine(BenchmarkApplication.Paths.Json);
+#else
             Console.WriteLine(BenchmarkApplication.Paths.Fortunes);
             Console.WriteLine(BenchmarkApplication.Paths.Fortunes);
             Console.WriteLine(BenchmarkApplication.Paths.SingleQuery);
             Console.WriteLine(BenchmarkApplication.Paths.SingleQuery);
             Console.WriteLine(BenchmarkApplication.Paths.Updates);
             Console.WriteLine(BenchmarkApplication.Paths.Updates);
             Console.WriteLine(BenchmarkApplication.Paths.MultipleQueries);
             Console.WriteLine(BenchmarkApplication.Paths.MultipleQueries);
+#endif
             DateHeader.SyncDateTimer();
             DateHeader.SyncDateTimer();
 
 
             var host = BuildWebHost(args);
             var host = BuildWebHost(args);
@@ -43,6 +47,7 @@ namespace PlatformBenchmarks
                 .Build();
                 .Build();
 
 
             var appSettings = config.Get<AppSettings>();
             var appSettings = config.Get<AppSettings>();
+#if DATABASE
             Console.WriteLine($"Database: {appSettings.Database}");
             Console.WriteLine($"Database: {appSettings.Database}");
 
 
             if (appSettings.Database == DatabaseServer.PostgreSql)
             if (appSettings.Database == DatabaseServer.PostgreSql)
@@ -53,12 +58,13 @@ namespace PlatformBenchmarks
             {
             {
                 BenchmarkApplication.Db = new RawDb(new ConcurrentRandom(), MySqlClientFactory.Instance, appSettings);
                 BenchmarkApplication.Db = new RawDb(new ConcurrentRandom(), MySqlClientFactory.Instance, appSettings);
             }
             }
+#endif
 
 
             var host = new WebHostBuilder()
             var host = new WebHostBuilder()
                 .UseBenchmarksConfiguration(config)
                 .UseBenchmarksConfiguration(config)
                 .UseKestrel((context, options) =>
                 .UseKestrel((context, options) =>
                 {
                 {
-                    IPEndPoint endPoint = context.Configuration.CreateIPEndPoint();
+                    var endPoint = context.Configuration.CreateIPEndPoint();
 
 
                     options.Listen(endPoint, builder =>
                     options.Listen(endPoint, builder =>
                     {
                     {

+ 1 - 1
frameworks/CSharp/aspnetcore/aspcore-ado-my.dockerfile

@@ -1,7 +1,7 @@
 FROM mcr.microsoft.com/dotnet/core/sdk:3.1.101 AS build
 FROM mcr.microsoft.com/dotnet/core/sdk:3.1.101 AS build
 WORKDIR /app
 WORKDIR /app
 COPY PlatformBenchmarks .
 COPY PlatformBenchmarks .
-RUN dotnet publish -c Release -o out
+RUN dotnet publish -c Release -o out /p:IsDatabase=true
 
 
 FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.2 AS runtime
 FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.2 AS runtime
 ENV ASPNETCORE_URLS http://+:8080
 ENV ASPNETCORE_URLS http://+:8080

+ 1 - 1
frameworks/CSharp/aspnetcore/aspcore-ado-pg-up.dockerfile

@@ -1,7 +1,7 @@
 FROM mcr.microsoft.com/dotnet/core/sdk:3.1.101 AS build
 FROM mcr.microsoft.com/dotnet/core/sdk:3.1.101 AS build
 WORKDIR /app
 WORKDIR /app
 COPY PlatformBenchmarks .
 COPY PlatformBenchmarks .
-RUN dotnet publish -c Release -o out
+RUN dotnet publish -c Release -o out /p:IsDatabase=true
 
 
 FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.2 AS runtime
 FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.2 AS runtime
 ENV ASPNETCORE_URLS http://+:8080
 ENV ASPNETCORE_URLS http://+:8080

+ 1 - 1
frameworks/CSharp/aspnetcore/aspcore-ado-pg.dockerfile

@@ -1,7 +1,7 @@
 FROM mcr.microsoft.com/dotnet/core/sdk:3.1.101 AS build
 FROM mcr.microsoft.com/dotnet/core/sdk:3.1.101 AS build
 WORKDIR /app
 WORKDIR /app
 COPY PlatformBenchmarks .
 COPY PlatformBenchmarks .
-RUN dotnet publish -c Release -o out
+RUN dotnet publish -c Release -o out /p:IsDatabase=true
 
 
 FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.2 AS runtime
 FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.2 AS runtime
 ENV ASPNETCORE_URLS http://+:8080
 ENV ASPNETCORE_URLS http://+:8080

+ 1 - 1
frameworks/CSharp/aspnetcore/aspcore-rhtx-pg-up.dockerfile

@@ -1,7 +1,7 @@
 FROM mcr.microsoft.com/dotnet/core/sdk:3.1.101 AS build
 FROM mcr.microsoft.com/dotnet/core/sdk:3.1.101 AS build
 WORKDIR /app
 WORKDIR /app
 COPY PlatformBenchmarks .
 COPY PlatformBenchmarks .
-RUN dotnet publish -c Release -o out
+RUN dotnet publish -c Release -o out /p:IsDatabase=true
 
 
 FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.2 AS runtime
 FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.2 AS runtime
 ENV ASPNETCORE_URLS http://+:8080
 ENV ASPNETCORE_URLS http://+:8080

+ 1 - 1
frameworks/CSharp/aspnetcore/aspcore-rhtx-pg.dockerfile

@@ -1,7 +1,7 @@
 FROM mcr.microsoft.com/dotnet/core/sdk:3.1.101 AS build
 FROM mcr.microsoft.com/dotnet/core/sdk:3.1.101 AS build
 WORKDIR /app
 WORKDIR /app
 COPY PlatformBenchmarks .
 COPY PlatformBenchmarks .
-RUN dotnet publish -c Release -o out
+RUN dotnet publish -c Release -o out /p:IsDatabase=true
 
 
 FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.2 AS runtime
 FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.2 AS runtime
 ENV ASPNETCORE_URLS http://+:8080
 ENV ASPNETCORE_URLS http://+:8080

+ 4 - 4
frameworks/CSharp/aspnetcore/benchmark_config.json

@@ -2,8 +2,8 @@
   "framework": "aspcore",
   "framework": "aspcore",
   "tests": [{
   "tests": [{
     "default": {
     "default": {
-      "plaintext_url": "/plaintext",
-      "json_url": "/json",
+      "plaintext_url": "/p",
+      "json_url": "/j",
       "port": 8080,
       "port": 8080,
       "approach": "Realistic",
       "approach": "Realistic",
       "classification": "Platform",
       "classification": "Platform",
@@ -21,8 +21,8 @@
       "versus": "aspcore"
       "versus": "aspcore"
     },
     },
     "rhtx": {
     "rhtx": {
-      "plaintext_url": "/plaintext",
-      "json_url": "/json",
+      "plaintext_url": "/p",
+      "json_url": "/j",
       "port": 8080,
       "port": 8080,
       "approach": "Realistic",
       "approach": "Realistic",
       "classification": "Platform",
       "classification": "Platform",