소스 검색

Update corert for round20 path requirements (#5829)

* Update corert for round20 path requirements

* Use socket transport by default
Ben Adams 5 년 전
부모
커밋
76853f1d5f

+ 60 - 45
frameworks/CSharp/aspnetcore-corert/PlatformBenchmarks/BenchmarkApplication.HttpConnection.cs

@@ -75,7 +75,7 @@ namespace PlatformBenchmarks
         private bool HandleRequests(in ReadOnlySequence<byte> buffer, bool isCompleted)
         {
             var reader = new SequenceReader<byte>(buffer);
-            var writer = GetWriter(Writer);
+            var writer = GetWriter(Writer, sizeHint: 160 * 16); // 160*16 is for Plaintext, for Json 160 would be enough
 
             while (true)
             {
@@ -112,11 +112,13 @@ namespace PlatformBenchmarks
 
             if (state == State.StartLine)
             {
-#if NETCOREAPP5_0
-                var unconsumedSequence = reader.UnreadSequence;
+#if NETCOREAPP5_0 || NET5_0
+                if (Parser.ParseRequestLine(new ParsingAdapter(this), ref reader))
+                {
+                    state = State.Headers;
+                }
 #else
                 var unconsumedSequence = reader.Sequence.Slice(reader.Position);
-#endif
                 if (Parser.ParseRequestLine(new ParsingAdapter(this), unconsumedSequence, out var consumed, out _))
                 {
                     state = State.Headers;
@@ -124,6 +126,7 @@ namespace PlatformBenchmarks
                     var parsedLength = unconsumedSequence.Slice(reader.Position, consumed).Length;
                     reader.Advance(parsedLength);
                 }
+#endif
             }
 
             if (state == State.Headers)
@@ -150,11 +153,17 @@ namespace PlatformBenchmarks
             while (true)
             {
                 var readResult = await Reader.ReadAsync();
-
                 var buffer = readResult.Buffer;
+                var isCompleted = readResult.IsCompleted;
+
+                if (buffer.IsEmpty && isCompleted)
+                {
+                    return;
+                }
+
                 while (true)
                 {
-                    if (!ParseHttpRequest(ref buffer, readResult.IsCompleted, out var examined))
+                    if (!ParseHttpRequest(ref buffer, isCompleted))
                     {
                         return;
                     }
@@ -173,7 +182,7 @@ namespace PlatformBenchmarks
                     }
 
                     // No more input or incomplete data, Advance the Reader
-                    Reader.AdvanceTo(buffer.Start, examined);
+                    Reader.AdvanceTo(buffer.Start, buffer.End);
                     break;
                 }
 
@@ -181,59 +190,63 @@ namespace PlatformBenchmarks
             }
         }
 
-        private bool ParseHttpRequest(ref ReadOnlySequence<byte> buffer, bool isCompleted, out SequencePosition examined)
+        private bool ParseHttpRequest(ref ReadOnlySequence<byte> buffer, bool isCompleted)
         {
-            examined = buffer.End;
+            var reader = new SequenceReader<byte>(buffer);
             var state = _state;
 
-            if (!buffer.IsEmpty)
+            if (state == State.StartLine)
             {
-                SequencePosition consumed;
-                if (state == State.StartLine)
+#if NETCOREAPP5_0 || NET5_0
+                if (Parser.ParseRequestLine(new ParsingAdapter(this), ref reader))
                 {
-                    if (Parser.ParseRequestLine(new ParsingAdapter(this), buffer, out consumed, out examined))
-                    {
-                        state = State.Headers;
-                    }
-
-                    buffer = buffer.Slice(consumed);
+                    state = State.Headers;
                 }
-
-                if (state == State.Headers)
+#else
+                var unconsumedSequence = reader.Sequence.Slice(reader.Position);
+                if (Parser.ParseRequestLine(new ParsingAdapter(this), unconsumedSequence, out var consumed, out _))
                 {
-                    var reader = new SequenceReader<byte>(buffer);
-                    var success = Parser.ParseHeaders(new ParsingAdapter(this), ref reader);
-
-                    consumed = reader.Position;
-                    if (success)
-                    {
-                        examined = consumed;
-                        state = State.Body;
-                    }
-                    else
-                    {
-                        examined = buffer.End;
-                    }
+                    state = State.Headers;
 
-                    buffer = buffer.Slice(consumed);
+                    var parsedLength = unconsumedSequence.Slice(reader.Position, consumed).Length;
+                    reader.Advance(parsedLength);
                 }
+#endif
+            }
 
-                if (state != State.Body && isCompleted)
+            if (state == State.Headers)
+            {
+                var success = Parser.ParseHeaders(new ParsingAdapter(this), ref reader);
+
+                if (success)
                 {
-                    ThrowUnexpectedEndOfData();
+                    state = State.Body;
                 }
             }
-            else if (isCompleted)
+
+            if (state != State.Body && isCompleted)
             {
-                return false;
+                ThrowUnexpectedEndOfData();
             }
 
             _state = state;
+
+            if (state == State.Body)
+            {
+                // Complete request read, consumed and examined are the same (length 0)
+                buffer = buffer.Slice(reader.Position, 0);
+            }
+            else
+            {
+                // In-complete request read, consumed is current position and examined is the remaining.
+                buffer = buffer.Slice(reader.Position);
+            }
+
             return true;
         }
 #endif
 
-#if NETCOREAPP5_0
+#if NETCOREAPP5_0 || NET5_0
 
         public void OnStaticIndexedHeader(int index)
         {
@@ -271,8 +284,8 @@ namespace PlatformBenchmarks
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        private static BufferWriter<WriterAdapter> GetWriter(PipeWriter pipeWriter)
-            => new BufferWriter<WriterAdapter>(new WriterAdapter(pipeWriter));
+        private static BufferWriter<WriterAdapter> GetWriter(PipeWriter pipeWriter, int sizeHint)
+            => new BufferWriter<WriterAdapter>(new WriterAdapter(pipeWriter), sizeHint);
 
         private struct WriterAdapter : IBufferWriter<byte>
         {
@@ -298,7 +311,7 @@ namespace PlatformBenchmarks
             public ParsingAdapter(BenchmarkApplication requestHandler)
                 => RequestHandler = requestHandler;
 
-#if NETCOREAPP5_0
+#if NETCOREAPP5_0 || NET5_0
             public void OnStaticIndexedHeader(int index) 
                 => RequestHandler.OnStaticIndexedHeader(index);
 
@@ -310,15 +323,17 @@ namespace PlatformBenchmarks
 
             public void OnHeadersComplete(bool endStream)
                 => RequestHandler.OnHeadersComplete(endStream);
+
+            public void OnStartLine(HttpVersionAndMethod versionAndMethod, TargetOffsetPathLength targetPath, Span<byte> startLine)
+                => RequestHandler.OnStartLine(versionAndMethod, targetPath, startLine);
 #else
             public void OnHeader(Span<byte> name, Span<byte> 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)
                 => RequestHandler.OnStartLine(method, version, target, path, query, customMethod, pathEncoded);
+#endif
         }
     }
-}
+}

+ 25 - 126
frameworks/CSharp/aspnetcore-corert/PlatformBenchmarks/BenchmarkApplication.cs

@@ -2,10 +2,6 @@
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
 
 using System;
-using System.Buffers.Binary;
-using System.Buffers.Text;
-using System.IO.Pipelines;
-using System.Threading.Tasks;
 using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
 
 namespace PlatformBenchmarks
@@ -16,105 +12,62 @@ namespace PlatformBenchmarks
         public static AsciiString ApplicationName => _applicationName;
 
         private readonly static AsciiString _crlf = "\r\n";
-        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 _headerServer = "Server: K";
         private readonly static AsciiString _headerContentLength = "Content-Length: ";
         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 _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 _fortunesColumn = "</td><td>";
-        private readonly static AsciiString _fortunesRowEnd = "</td></tr>";
-        private readonly static AsciiString _fortunesTableEnd = "</table></body></html>";
-        private readonly static AsciiString _contentLengthGap = new string(' ', 4);
-
-#if DATABASE
-        public static RawDb Db { get; set; }
-#endif
-
         public static class Paths
         {
-            public readonly static AsciiString SingleQuery = "/db";
-            public readonly static AsciiString Json = "/j";
-            public readonly static AsciiString Fortunes = "/fortunes";
-            public readonly static AsciiString Plaintext = "/p";
-            public readonly static AsciiString Updates = "/updates/queries=";
-            public readonly static AsciiString MultipleQueries = "/queries/queries=";
-            public const ushort JsonPath = 0x6a2f;
-            public const ushort PlaintextPath = 0x702f;
+            public readonly static AsciiString Json = "/json";
+            public readonly static AsciiString Plaintext = "/plaintext";
         }
 
         private RequestType _requestType;
-#if DATABASE
-        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)
-        {
 
-#if !DATABASE
-            if (method == HttpMethod.Get && BinaryPrimitives.TryReadUInt16LittleEndian(path, out var value))
+#if NETCOREAPP5_0 || NET5_0
+        public void OnStartLine(HttpVersionAndMethod versionAndMethod, TargetOffsetPathLength targetPath, Span<byte> startLine)
+        {
+            var requestType = RequestType.NotRecognized;
+            if (versionAndMethod.Method == HttpMethod.Get)
             {
-                if (value == Paths.PlaintextPath)
+                var pathLength = targetPath.Offset;
+                if (pathLength == 10 && startLine.SequenceEqual(Paths.Plaintext))
                 {
-                    _requestType = RequestType.PlainText;
-                    return;
+                    requestType = RequestType.PlainText;
                 }
-                else if (value == Paths.JsonPath)
+                else if (pathLength == 5 && startLine.SequenceEqual(Paths.Json))
                 {
-                    _requestType = RequestType.Json;
-                    return;
+                    requestType = RequestType.Json;
                 }
             }
 
-            _requestType = RequestType.NotRecognized;
+            _requestType = requestType;
+        }
 #else
+        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;
             if (method == HttpMethod.Get)
             {
-                var pathLength = path.Length;
-                if (Paths.SingleQuery.Length <= pathLength && path.StartsWith(Paths.SingleQuery))
+                if (path.Length == 10 && path.SequenceEqual(Paths.Plaintext))
                 {
-                    _requestType = RequestType.SingleQuery;
+                    requestType = RequestType.PlainText;
                 }
-                else if (Paths.Fortunes.Length <= pathLength && path.StartsWith(Paths.Fortunes))
+                else if (path.Length == 5 && path.SequenceEqual(Paths.Json))
                 {
-                    _requestType = RequestType.Fortunes;
-                }
-                else if (Paths.Updates.Length <= pathLength && path.StartsWith(Paths.Updates))
-                {
-                    _queries = ParseQueries(path, Paths.Updates.Length);
-                    _requestType = RequestType.Updates;
-                }
-                else if (Paths.MultipleQueries.Length <= pathLength && path.StartsWith(Paths.MultipleQueries))
-                {
-                    _queries = ParseQueries(path, Paths.MultipleQueries.Length);
-                    _requestType = RequestType.MultipleQueries;
-                }
-                else
-                {
-                    _requestType = RequestType.NotRecognized;
+                    requestType = RequestType.Json;
                 }
             }
-            else
-            {
-                _requestType = RequestType.NotRecognized;
-            }
-#endif 
-        }
 
+            _requestType = requestType;
+        }
+#endif
 
-#if !DATABASE
         private void ProcessRequest(ref BufferWriter<WriterAdapter> writer)
         {
             if (_requestType == RequestType.PlainText)
@@ -130,57 +83,7 @@ namespace PlatformBenchmarks
                 Default(ref writer);
             }
         }
-#else
-        private static int ParseQueries(Span<byte> path, int pathLength)
-        {
-            if (!Utf8Parser.TryParse(path.Slice(pathLength), out int queries, out _) || queries < 1)
-            {
-                queries = 1;
-            }
-            else if (queries > 500)
-            {
-                queries = 500;
-            }
-
-            return queries;
-        }
 
-        private Task ProcessRequestAsync()
-        {
-            Task task;
-            var requestType = _requestType;
-            if (requestType == RequestType.Fortunes)
-            {
-                task = Fortunes(Writer);
-            }
-            else if (requestType == RequestType.SingleQuery)
-            {
-                task = SingleQuery(Writer);
-            }
-            else if (requestType == RequestType.Updates)
-            {
-                task = Updates(Writer, _queries);
-            }
-            else if (requestType == RequestType.MultipleQueries)
-            {
-                task = MultipleQueries(Writer, _queries);
-            }
-            else
-            {
-                Default(Writer);
-                task = Task.CompletedTask;
-            }
-
-            return task;
-        }
-
-        private static void Default(PipeWriter pipeWriter)
-        {
-            var writer = GetWriter(pipeWriter);
-            Default(ref writer);
-            writer.Commit();
-        }
-#endif
         private readonly static AsciiString _defaultPreamble =
             _http11OK +
             _headerServer + _crlf +
@@ -199,11 +102,7 @@ namespace PlatformBenchmarks
         {
             NotRecognized,
             PlainText,
-            Json,
-            Fortunes,
-            SingleQuery,
-            Updates,
-            MultipleQueries
+            Json
         }
     }
 }

+ 16 - 18
frameworks/CSharp/aspnetcore-corert/PlatformBenchmarks/BenchmarkConfigurationHelpers.cs

@@ -19,35 +19,33 @@ namespace PlatformBenchmarks
             // Handle the transport type
             var webHost = builder.GetSetting("KestrelTransport");
 
-            // Handle the thread count
-            var threadCountRaw = builder.GetSetting("threadCount");
-            int? theadCount = null;
+            Console.WriteLine($"Transport: {webHost}");
 
-            if (!string.IsNullOrEmpty(threadCountRaw) &&
-                int.TryParse(threadCountRaw, out var value))
+            if (string.Equals(webHost, "LinuxTransport", StringComparison.OrdinalIgnoreCase))
             {
-                theadCount = value;
+                builder.UseLinuxTransport(options =>
+                {
+                    options.ApplicationSchedulingMode = PipeScheduler.Inline;
+                });
             }
-
-            if (string.Equals(webHost, "Sockets", StringComparison.OrdinalIgnoreCase))
+            else
             {
                 builder.UseSockets(options =>
                 {
-                    if (theadCount.HasValue)
+                    if (int.TryParse(builder.GetSetting("threadCount"), out int threadCount))
                     {
-                        options.IOQueueCount = theadCount.Value;
+                        options.IOQueueCount = threadCount;
                     }
-                });
-            }
-            else if (string.Equals(webHost, "LinuxTransport", StringComparison.OrdinalIgnoreCase))
-            {
-                builder.UseLinuxTransport(options =>
-                {
-                    options.ApplicationSchedulingMode = PipeScheduler.Inline;
+
+#if NETCOREAPP5_0 || NET5_0
+                    options.WaitForDataBeforeAllocatingBuffer = false;
+
+                    Console.WriteLine($"Options: WaitForData={options.WaitForDataBeforeAllocatingBuffer}, IOQueue={options.IOQueueCount}");
+#endif
                 });
             }
 
-            return builder;
+                return builder;
         }
 
         public static IPEndPoint CreateIPEndPoint(this IConfiguration config)

+ 2 - 52
frameworks/CSharp/aspnetcore-corert/PlatformBenchmarks/BufferExtensions.cs

@@ -28,59 +28,9 @@ namespace PlatformBenchmarks
             byteCount = Encoding.UTF8.GetBytes(text.AsSpan(), buffer.Span);
             buffer.Advance(byteCount);
         }
-
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        internal static unsafe void WriteNumeric<T>(ref this BufferWriter<T> buffer, uint number)
-             where T : struct, IBufferWriter<byte>
-        {
-            const byte AsciiDigitStart = (byte)'0';
-
-            var span = buffer.Span;
-            var bytesLeftInBlock = span.Length;
-
-            // Fast path, try copying to the available memory directly
-            var advanceBy = 0;
-            fixed (byte* output = span)
-            {
-                var start = output;
-                if (number < 10 && bytesLeftInBlock >= 1)
-                {
-                    start[0] = (byte)(number + AsciiDigitStart);
-                    advanceBy = 1;
-                }
-                else if (number < 100 && bytesLeftInBlock >= 2)
-                {
-                    var tens = (byte)((number * 205u) >> 11); // div10, valid to 1028
-
-                    start[0] = (byte)(tens + AsciiDigitStart);
-                    start[1] = (byte)(number - (tens * 10) + AsciiDigitStart);
-                    advanceBy = 2;
-                }
-                else if (number < 1000 && bytesLeftInBlock >= 3)
-                {
-                    var digit0 = (byte)((number * 41u) >> 12); // div100, valid to 1098
-                    var digits01 = (byte)((number * 205u) >> 11); // div10, valid to 1028
-
-                    start[0] = (byte)(digit0 + AsciiDigitStart);
-                    start[1] = (byte)(digits01 - (digit0 * 10) + AsciiDigitStart);
-                    start[2] = (byte)(number - (digits01 * 10) + AsciiDigitStart);
-                    advanceBy = 3;
-                }
-            }
-
-            if (advanceBy > 0)
-            {
-                buffer.Advance(advanceBy);
-            }
-            else
-            {
-                WriteNumericMultiWrite(ref buffer, number);
-            }
-        }
-
         [MethodImpl(MethodImplOptions.NoInlining)]
-        private static void WriteNumericMultiWrite<T>(ref this BufferWriter<T> buffer, uint number)
-             where T : struct, IBufferWriter<byte>
+        internal static void WriteNumericMultiWrite<T>(ref this BufferWriter<T> buffer, uint number)
+             where T : IBufferWriter<byte>
         {
             const byte AsciiDigitStart = (byte)'0';
 

+ 50 - 4
frameworks/CSharp/aspnetcore-corert/PlatformBenchmarks/BufferWriter.cs

@@ -13,19 +13,19 @@ namespace PlatformBenchmarks
         private Span<byte> _span;
         private int _buffered;
 
-        public BufferWriter(T output)
+        public BufferWriter(T output, int sizeHint)
         {
             _buffered = 0;
             _output = output;
-            _span = output.GetSpan(sizeHint: 16 * 160);
+            _span = output.GetSpan(sizeHint);
         }
 
         public Span<byte> Span => _span;
 
-        public int Buffered => _buffered;
-
         public T Output => _output;
 
+        public int Buffered => _buffered;
+
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public void Commit()
         {
@@ -93,5 +93,51 @@ namespace PlatformBenchmarks
                 Advance(writable);
             }
         }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        internal void WriteNumeric(uint number)
+        {
+            const byte AsciiDigitStart = (byte)'0';
+
+            var span = this.Span;
+
+            // Fast path, try copying to the available memory directly
+            var advanceBy = 0;
+            if (span.Length >= 3)
+            {
+                if (number < 10)
+                {
+                    span[0] = (byte)(number + AsciiDigitStart);
+                    advanceBy = 1;
+                }
+                else if (number < 100)
+                {
+                    var tens = (byte)((number * 205u) >> 11); // div10, valid to 1028
+
+                    span[0] = (byte)(tens + AsciiDigitStart);
+                    span[1] = (byte)(number - (tens * 10) + AsciiDigitStart);
+                    advanceBy = 2;
+                }
+                else if (number < 1000)
+                {
+                    var digit0 = (byte)((number * 41u) >> 12); // div100, valid to 1098
+                    var digits01 = (byte)((number * 205u) >> 11); // div10, valid to 1028
+
+                    span[0] = (byte)(digit0 + AsciiDigitStart);
+                    span[1] = (byte)(digits01 - (digit0 * 10) + AsciiDigitStart);
+                    span[2] = (byte)(number - (digits01 * 10) + AsciiDigitStart);
+                    advanceBy = 3;
+                }
+            }
+
+            if (advanceBy > 0)
+            {
+                Advance(advanceBy);
+            }
+            else
+            {
+                BufferExtensions.WriteNumericMultiWrite(ref this, number);
+            }
+        }
     }
 }

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

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