Browse Source

Aspnet platform updates (#5807)

* Sync, Update Urls for round 20

* Add cached query

* Reuse existing multiquery output
Ben Adams 5 years ago
parent
commit
77fd80534a
24 changed files with 472 additions and 328 deletions
  1. 16 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Caching.cs
  2. 1 1
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Fortunes.cs
  3. 60 45
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.HttpConnection.cs
  4. 7 5
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Json.cs
  5. 12 6
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.MultipleQueries.cs
  6. 12 6
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.SingleQuery.cs
  7. 12 6
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Updates.cs
  8. 91 58
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.cs
  9. 6 12
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkConfigurationHelpers.cs
  10. 2 52
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BufferExtensions.cs
  11. 50 4
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/BufferWriter.cs
  12. 5 4
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/BatchUpdateString.cs
  13. 17 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/CachedWorld.cs
  14. 12 12
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/Fortune.cs
  15. 135 76
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/RawDb.cs
  16. 1 2
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/PlatformBenchmarks.csproj
  17. 11 6
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/Program.cs
  18. 4 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/appsettings.postgresql.json
  19. 4 0
      frameworks/CSharp/aspnetcore/PlatformBenchmarks/appsettings.postgresql.updates.json
  20. 1 1
      frameworks/CSharp/aspnetcore/aspcore-ado-pg-up.dockerfile
  21. 1 1
      frameworks/CSharp/aspnetcore/aspcore-ado-pg.dockerfile
  22. 1 1
      frameworks/CSharp/aspnetcore/aspcore-rhtx-pg-up.dockerfile
  23. 1 1
      frameworks/CSharp/aspnetcore/aspcore-rhtx-pg.dockerfile
  24. 10 29
      frameworks/CSharp/aspnetcore/benchmark_config.json

+ 16 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Caching.cs

@@ -0,0 +1,16 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.IO.Pipelines;
+using System.Threading.Tasks;
+
+namespace PlatformBenchmarks
+{
+    public partial class BenchmarkApplication
+    {
+        private async Task Caching(PipeWriter pipeWriter, int count)
+        {
+            OutputMultipleQueries(pipeWriter, await Db.LoadCachedQueries(count));
+        }
+    }
+}

+ 1 - 1
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Fortunes.cs

@@ -23,7 +23,7 @@ namespace PlatformBenchmarks
 
         private void OutputFortunes(PipeWriter pipeWriter, List<Fortune> model)
         {
-            var writer = GetWriter(pipeWriter);
+            var writer = GetWriter(pipeWriter, sizeHint: 1600); // in reality it's 1361
 
             writer.Write(_fortunesPreamble);
 

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

@@ -1,4 +1,4 @@
-// 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.
 
 using System;
@@ -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
         }
     }
 }

+ 7 - 5
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Json.cs

@@ -1,6 +1,8 @@
 // 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.Text.Json;
 
 namespace PlatformBenchmarks
@@ -15,7 +17,7 @@ namespace PlatformBenchmarks
             _headerContentTypeJson + _crlf +
             _headerContentLength + _jsonPayloadSize.ToString();
 
-        private static void Json(ref BufferWriter<WriterAdapter> writer)
+        private static void Json(ref BufferWriter<WriterAdapter> writer, IBufferWriter<byte> bodyWriter)
         {
             writer.Write(_jsonPreamble);
 
@@ -24,11 +26,11 @@ namespace PlatformBenchmarks
 
             writer.Commit();
 
+            Utf8JsonWriter utf8JsonWriter = t_writer ??= new Utf8JsonWriter(bodyWriter, new JsonWriterOptions { SkipValidation = true });
+            utf8JsonWriter.Reset(bodyWriter);
+
             // Body
-            using (Utf8JsonWriter utf8JsonWriter = new Utf8JsonWriter(writer.Output))
-            {
-                JsonSerializer.Serialize<JsonMessage>(utf8JsonWriter, new JsonMessage { message = "Hello, World!" }, SerializerOptions);
-            }
+            JsonSerializer.Serialize<JsonMessage>(utf8JsonWriter, new JsonMessage { message = "Hello, World!" }, SerializerOptions);
         }
     }
 }

+ 12 - 6
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.MultipleQueries.cs

@@ -16,20 +16,26 @@ namespace PlatformBenchmarks
 
         private static void OutputMultipleQueries(PipeWriter pipeWriter, World[] rows)
         {
-            var writer = GetWriter(pipeWriter);
+            var writer = GetWriter(pipeWriter, sizeHint: 160 * rows.Length); // in reality it's 152 for one
 
             writer.Write(_dbPreamble);
 
-            // Content-Length
-            var jsonPayload = JsonSerializer.SerializeToUtf8Bytes(rows, SerializerOptions);
-            writer.WriteNumeric((uint)jsonPayload.Length);
+            var lengthWriter = writer;
+            writer.Write(_contentLengthGap);
 
             // Date header
             writer.Write(DateHeader.HeaderBytes);
 
-            // Body
-            writer.Write(jsonPayload);
             writer.Commit();
+
+            Utf8JsonWriter utf8JsonWriter = t_writer ??= new Utf8JsonWriter(pipeWriter, new JsonWriterOptions { SkipValidation = true });
+            utf8JsonWriter.Reset(pipeWriter);
+
+            // Body
+            JsonSerializer.Serialize<World[]>(utf8JsonWriter, rows, SerializerOptions);
+
+            // Content-Length
+            lengthWriter.WriteNumeric((uint)utf8JsonWriter.BytesCommitted);
         }
     }
 }

+ 12 - 6
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.SingleQuery.cs

@@ -16,20 +16,26 @@ namespace PlatformBenchmarks
 
         private static void OutputSingleQuery(PipeWriter pipeWriter, World row)
         {
-            var writer = GetWriter(pipeWriter);
+            var writer = GetWriter(pipeWriter, sizeHint: 180); // in reality it's 150
 
             writer.Write(_dbPreamble);
 
-            // Content-Length
-            var jsonPayload = JsonSerializer.SerializeToUtf8Bytes(row, SerializerOptions);
-            writer.WriteNumeric((uint)jsonPayload.Length);
+            var lengthWriter = writer;
+            writer.Write(_contentLengthGap);
 
             // Date header
             writer.Write(DateHeader.HeaderBytes);
 
-            // Body
-            writer.Write(jsonPayload);
             writer.Commit();
+
+            Utf8JsonWriter utf8JsonWriter = t_writer ??= new Utf8JsonWriter(pipeWriter, new JsonWriterOptions { SkipValidation = true });
+            utf8JsonWriter.Reset(pipeWriter);
+
+            // Body
+            JsonSerializer.Serialize<World>(utf8JsonWriter, row, SerializerOptions);
+
+            // Content-Length
+            lengthWriter.WriteNumeric((uint)utf8JsonWriter.BytesCommitted);
         }
     }
 }

+ 12 - 6
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Updates.cs

@@ -16,20 +16,26 @@ namespace PlatformBenchmarks
 
         private static void OutputUpdates(PipeWriter pipeWriter, World[] rows)
         {
-            var writer = GetWriter(pipeWriter);
+            var writer = GetWriter(pipeWriter, sizeHint: 120 * rows.Length); // in reality it's 112 for one
 
             writer.Write(_dbPreamble);
 
-            // Content-Length
-            var jsonPayload = JsonSerializer.SerializeToUtf8Bytes(rows, SerializerOptions);
-            writer.WriteNumeric((uint)jsonPayload.Length);
+            var lengthWriter = writer;
+            writer.Write(_contentLengthGap);
 
             // Date header
             writer.Write(DateHeader.HeaderBytes);
 
-            // Body
-            writer.Write(jsonPayload);
             writer.Commit();
+
+            Utf8JsonWriter utf8JsonWriter = t_writer ??= new Utf8JsonWriter(pipeWriter, new JsonWriterOptions { SkipValidation = true });
+            utf8JsonWriter.Reset(pipeWriter);
+
+            // Body
+            JsonSerializer.Serialize<World[]>(utf8JsonWriter, rows, SerializerOptions);
+
+            // Content-Length
+            lengthWriter.WriteNumeric((uint)utf8JsonWriter.BytesCommitted);
         }
     }
 }

+ 91 - 58
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.cs

@@ -44,67 +44,117 @@ namespace PlatformBenchmarks
 
         public static RawDb Db { get; set; }
 
+        [ThreadStatic]
+        private static Utf8JsonWriter t_writer;
+
         public static class Paths
         {
+            public readonly static AsciiString Json = "/json";
+            public readonly static AsciiString Plaintext = "/plaintext";
             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 readonly static AsciiString Updates = "/updates/";
+            public readonly static AsciiString MultipleQueries = "/queries/";
+            public readonly static AsciiString Caching = "/cached-worlds/";
         }
 
         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 NETCOREAPP5_0 || NET5_0
+        public void OnStartLine(HttpVersionAndMethod versionAndMethod, TargetOffsetPathLength targetPath, Span<byte> startLine)
         {
-#if !DATABASE
-            if (method == HttpMethod.Get)
+            var requestType = RequestType.NotRecognized;
+            if (versionAndMethod.Method == HttpMethod.Get)
             {
-                if (path.Length >= 2 && path[0] == '/')
+#if !DATABASE
+                var pathLength = targetPath.Offset;
+                if (pathLength == 10 && startLine.SequenceEqual(Paths.Plaintext))
+                {
+                    requestType = RequestType.PlainText;
+                }
+                else if (pathLength == 5 && startLine.SequenceEqual(Paths.Json))
+                {
+                    requestType = RequestType.Json;
+                }
+#else
+                var pathLength = targetPath.Offset;
+                if (Paths.SingleQuery.Length == pathLength && startLine.SequenceEqual(Paths.SingleQuery))
+                {
+                    requestType = RequestType.SingleQuery;
+                }
+                else if (Paths.Fortunes.Length == pathLength && startLine.SequenceEqual(Paths.Fortunes))
+                {
+                    requestType = RequestType.Fortunes;
+                }
+                else if (Paths.Caching.Length <= pathLength && startLine.StartsWith(Paths.Caching))
+                {
+                    _queries = ParseQueries(startLine, Paths.Caching.Length);
+                    requestType = RequestType.Caching;
+                }
+                else if (Paths.Updates.Length <= pathLength && startLine.StartsWith(Paths.Updates))
                 {
-                    if (path[1] == 'p')
-                    {
-                        _requestType = RequestType.PlainText;
-                        return;
-                    }
-                    if (path[1] == 'j')
-                    {
-                        _requestType = RequestType.Json;
-                        return;
-                    }
+                    _queries = ParseQueries(startLine, Paths.Updates.Length);
+                    requestType = RequestType.Updates;
+                }
+                else if (Paths.MultipleQueries.Length <= pathLength && startLine.StartsWith(Paths.MultipleQueries))
+                {
+                    _queries = ParseQueries(startLine, Paths.MultipleQueries.Length);
+                    requestType = RequestType.MultipleQueries;
                 }
+#endif
             }
-            _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 !DATABASE
+                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.Json;
+                }
+#else
+                var pathLength = path.Length; 
+                if (Paths.Fortunes.Length == pathLength && path.SequenceEqual(Paths.Fortunes))
                 {
                     requestType = RequestType.Fortunes;
                 }
-                else if (Paths.Updates.Length <= pathLength && path.StartsWith(Paths.Updates))
+                else if (Paths.SingleQuery.Length == pathLength && path.SequenceEqual(Paths.SingleQuery))
                 {
-                    _queries = ParseQueries(path, Paths.Updates.Length);
-                    requestType = RequestType.Updates;
+                    requestType = RequestType.SingleQuery;
+                }
+                else if (Paths.Caching.Length <= pathLength && path.StartsWith(Paths.Caching))
+                {
+                    _queries = ParseQueries(path, Paths.Caching.Length);
+                    requestType = RequestType.Caching;
                 }
                 else if (Paths.MultipleQueries.Length <= pathLength && path.StartsWith(Paths.MultipleQueries))
                 {
                     _queries = ParseQueries(path, Paths.MultipleQueries.Length);
                     requestType = RequestType.MultipleQueries;
                 }
+                else if (Paths.Updates.Length <= pathLength && path.StartsWith(Paths.Updates))
+                {
+                    _queries = ParseQueries(path, Paths.Updates.Length);
+                    requestType = RequestType.Updates;
+                }
+#endif
             }
+
             _requestType = requestType;
-#endif
         }
+#endif
 
 
 #if !DATABASE
@@ -116,7 +166,7 @@ namespace PlatformBenchmarks
             }
             else if (_requestType == RequestType.Json)
             {
-                Json(ref writer);
+                Json(ref writer, Writer);
             }
             else
             {
@@ -138,40 +188,22 @@ namespace PlatformBenchmarks
             return queries;
         }
 
-        private Task ProcessRequestAsync()
+        private Task ProcessRequestAsync() => _requestType switch
         {
-            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)
+            RequestType.Fortunes => Fortunes(Writer),
+            RequestType.SingleQuery => SingleQuery(Writer),
+            RequestType.Caching => Caching(Writer, _queries),
+            RequestType.Updates => Updates(Writer, _queries),
+            RequestType.MultipleQueries => MultipleQueries(Writer, _queries),
+            _ => Default(Writer)
+        };
+
+        private static Task Default(PipeWriter pipeWriter)
         {
-            var writer = GetWriter(pipeWriter);
+            var writer = GetWriter(pipeWriter, sizeHint: _defaultPreamble.Length + DateHeader.HeaderBytes.Length);
             Default(ref writer);
             writer.Commit();
+            return Task.CompletedTask;
         }
 #endif
         private readonly static AsciiString _defaultPreamble =
@@ -195,6 +227,7 @@ namespace PlatformBenchmarks
             Json,
             Fortunes,
             SingleQuery,
+            Caching,
             Updates,
             MultipleQueries
         }

+ 6 - 12
frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkConfigurationHelpers.cs

@@ -19,24 +19,18 @@ namespace PlatformBenchmarks
             // 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) &&
-                int.TryParse(threadCountRaw, out var value))
-            {
-                theadCount = value;
-            }
-
             if (string.Equals(webHost, "Sockets", StringComparison.OrdinalIgnoreCase))
             {
                 builder.UseSockets(options =>
                 {
-                    if (theadCount.HasValue)
+                    if (int.TryParse(builder.GetSetting("threadCount"), out int threadCount))
                     {
-                        options.IOQueueCount = theadCount.Value;
+                       options.IOQueueCount = threadCount;
                     }
+
+#if NETCOREAPP5_0 || NET5_0
+                    options.WaitForDataBeforeAllocatingBuffer = false;
+#endif
                 });
             }
             else if (string.Equals(webHost, "LinuxTransport", StringComparison.OrdinalIgnoreCase))

+ 2 - 52
frameworks/CSharp/aspnetcore/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/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);
+            }
+        }
     }
 }

+ 5 - 4
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/BatchUpdateString.cs

@@ -1,9 +1,7 @@
 // Copyright (c) .NET Foundation. All rights reserved. 
 // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. 
 
-using System.Collections.Generic;
 using System.Linq;
-using System.Runtime.CompilerServices;
 
 namespace PlatformBenchmarks
 {
@@ -11,10 +9,13 @@ namespace PlatformBenchmarks
     {
         private const int MaxBatch = 500;
 
-        private static string[] _queries = new string[MaxBatch+1];
-
         public static DatabaseServer DatabaseServer;
 
+        internal static readonly string[] Ids = Enumerable.Range(0, MaxBatch).Select(i => $"@Id_{i}").ToArray();
+        internal static readonly string[] Randoms = Enumerable.Range(0, MaxBatch).Select(i => $"@Random_{i}").ToArray();
+
+        private static string[] _queries = new string[MaxBatch + 1];
+
         public static string Query(int batchSize)
         {
             if (_queries[batchSize] != null)

+ 17 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/CachedWorld.cs

@@ -0,0 +1,17 @@
+// 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.Runtime.InteropServices;
+
+namespace PlatformBenchmarks
+{
+    public class CachedWorld
+    {
+        public int Id { get; set; }
+
+        public int RandomNumber { get; set; }
+
+        public static implicit operator World(CachedWorld world) => new World { Id = world.Id, RandomNumber = world.RandomNumber };
+        public static implicit operator CachedWorld(World world) => new CachedWorld { Id = world.Id, RandomNumber = world.RandomNumber };
+    }
+}

+ 12 - 12
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/Fortune.cs

@@ -5,21 +5,21 @@ using System;
 
 namespace PlatformBenchmarks
 {
-    public class Fortune : IComparable<Fortune>, IComparable
+    public readonly struct Fortune : IComparable<Fortune>, IComparable
     {
-        public int Id { get; set; }
-
-        public string Message { get; set; }
-        
-        public int CompareTo(object obj)
+        public Fortune(int id, string message)
         {
-            return CompareTo((Fortune)obj);
+            Id = id;
+            Message = message;
         }
 
-        public int CompareTo(Fortune other)
-        {
-            // Performance critical, using culture insensitive comparison
-            return String.CompareOrdinal(Message, other.Message);
-        }
+        public int Id { get; }
+
+        public string Message { get; }
+
+        public int CompareTo(object obj) => throw new InvalidOperationException("The non-generic CompareTo should not be used");
+
+        // Performance critical, using culture insensitive comparison
+        public int CompareTo(Fortune other) => string.CompareOrdinal(Message, other.Message);
     }
 }

+ 135 - 76
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Data/RawDb.cs

@@ -3,166 +3,225 @@
 
 using System;
 using System.Collections.Generic;
-using System.Data;
-using System.Data.Common;
+using System.Runtime.CompilerServices;
 using System.Threading.Tasks;
+using Microsoft.Extensions.Caching.Memory;
+using Npgsql;
 
 namespace PlatformBenchmarks
 {
     public class RawDb
     {
-        private static readonly Comparison<World> WorldSortComparison = (a, b) => a.Id.CompareTo(b.Id);
-
         private readonly ConcurrentRandom _random;
-        private readonly DbProviderFactory _dbProviderFactory;
         private readonly string _connectionString;
+        private readonly MemoryCache _cache = new MemoryCache(
+            new MemoryCacheOptions()
+            {
+                ExpirationScanFrequency = TimeSpan.FromMinutes(15)
+            });
 
-        public RawDb(ConcurrentRandom random, DbProviderFactory dbProviderFactory, AppSettings appSettings)
+        public RawDb(ConcurrentRandom random, AppSettings appSettings)
         {
             _random = random;
-            _dbProviderFactory = dbProviderFactory;
             _connectionString = appSettings.ConnectionString;
         }
 
         public async Task<World> LoadSingleQueryRow()
         {
-            using (var db = _dbProviderFactory.CreateConnection())
+            using (var db = new NpgsqlConnection(_connectionString))
             {
-                db.ConnectionString = _connectionString;
                 await db.OpenAsync();
 
-                using (var cmd = CreateReadCommand(db))
+                var (cmd, _) = CreateReadCommand(db);
+                using (cmd)
                 {
-                    return await ReadSingleRow(db, cmd);
+                    return await ReadSingleRow(cmd);
                 }
             }
         }
 
-        async Task<World> ReadSingleRow(DbConnection connection, DbCommand cmd)
+        public async Task<World[]> LoadMultipleQueriesRows(int count)
         {
-            using (var rdr = await cmd.ExecuteReaderAsync(CommandBehavior.SingleRow))
+            var result = new World[count];
+
+            using (var db = new NpgsqlConnection(_connectionString))
             {
-                await rdr.ReadAsync();
+                await db.OpenAsync();
 
-                return new World
+                var (cmd, idParameter) = CreateReadCommand(db);
+                using (cmd)
                 {
-                    Id = rdr.GetInt32(0),
-                    RandomNumber = rdr.GetInt32(1)
-                };
+                    for (int i = 0; i < result.Length; i++)
+                    {
+                        result[i] = await ReadSingleRow(cmd);
+                        idParameter.TypedValue = _random.Next(1, 10001);
+                    }
+                }
             }
+
+            return result;
         }
 
-        DbCommand CreateReadCommand(DbConnection connection)
+        public Task<World[]> LoadCachedQueries(int count)
         {
-            var cmd = connection.CreateCommand();
-            cmd.CommandText = "SELECT id, randomnumber FROM world WHERE id = @Id";
-            var id = cmd.CreateParameter();
-            id.ParameterName = "@Id";
-            id.DbType = DbType.Int32;
-            id.Value = _random.Next(1, 10001);
-            cmd.Parameters.Add(id);
+            var result = new World[count];
+            for (var i = 0; i < result.Length; i++)
+            {
+                var id = _random.Next(1, 10001);
+                var data = _cache.Get<CachedWorld>(id);
 
-            (cmd as MySql.Data.MySqlClient.MySqlCommand)?.Prepare();
+                if (data != null)
+                {
+                    result[i] = data;
+                }
+                else
+                {
+                    return LoadUncachedQueries(id, i, count, this, result);
+                }
+            }
 
-            return cmd;
-        }
+            return Task.FromResult(result);
 
+            static async Task<World[]> LoadUncachedQueries(int id, int i, int count, RawDb rawdb, World[] result)
+            {
+                using (var db = new NpgsqlConnection(rawdb._connectionString))
+                {
+                    await db.OpenAsync();
 
-        public async Task<World[]> LoadMultipleQueriesRows(int count)
-        {
-            var result = new World[count];
+                    var (cmd, idParameter) = rawdb.CreateReadCommand(db);
+                    using (cmd)
+                    {
+                        Func<ICacheEntry, Task<CachedWorld>> create = async (entry) => 
+                        { 
+                            return await rawdb.ReadSingleRow(cmd);
+                        };
+
+                        idParameter.TypedValue = id;
 
-            using (var db = _dbProviderFactory.CreateConnection())
+                        for (; i < result.Length; i++)
+                        {
+                            var data = await rawdb._cache.GetOrCreateAsync<CachedWorld>(id, create);
+                            result[i] = data;
+
+                            id = rawdb._random.Next(1, 10001);
+                            idParameter.TypedValue = id;
+                        }
+                    }
+                }
+
+                return result;
+            }
+        }
+
+        public async Task PopulateCache()
+        {
+            using (var db = new NpgsqlConnection(_connectionString))
             {
-                db.ConnectionString = _connectionString;
                 await db.OpenAsync();
-                using (var cmd = CreateReadCommand(db))
+
+                var (cmd, idParameter) = CreateReadCommand(db);
+                using (cmd)
                 {
-                    for (int i = 0; i < count; i++)
+                    for (var i = 1; i < 10001; i++)
                     {
-                        result[i] = await ReadSingleRow(db, cmd);
-                        cmd.Parameters["@Id"].Value = _random.Next(1, 10001);
+                        idParameter.TypedValue = i;
+                        _cache.Set<CachedWorld>(i, await ReadSingleRow(cmd));
                     }
                 }
             }
-
-            return result;
         }
 
         public async Task<World[]> LoadMultipleUpdatesRows(int count)
         {
-            using (var db = _dbProviderFactory.CreateConnection())
+            var results = new World[count];
+
+            using (var db = new NpgsqlConnection(_connectionString))
             {
-                db.ConnectionString = _connectionString;
                 await db.OpenAsync();
 
-                using (var updateCmd = db.CreateCommand())
-                using (var queryCmd = CreateReadCommand(db))
+                var (queryCmd, queryParameter) = CreateReadCommand(db);
+                using (queryCmd)
                 {
-                    var results = new World[count];
-                    for (int i = 0; i < count; i++)
+                    for (int i = 0; i < results.Length; i++)
                     {
-                        results[i] = await ReadSingleRow(db, queryCmd);
-                        queryCmd.Parameters["@Id"].Value = _random.Next(1, 10001);
+                        results[i] = await ReadSingleRow(queryCmd);
+                        queryParameter.TypedValue = _random.Next(1, 10001);
                     }
+                }
 
-                    updateCmd.CommandText = BatchUpdateString.Query(count);
+                using (var updateCmd = new NpgsqlCommand(BatchUpdateString.Query(count), db))
+                {
+                    var ids = BatchUpdateString.Ids;
+                    var randoms = BatchUpdateString.Randoms;
 
-                    for (int i = 0; i < count; i++)
+                    for (int i = 0; i < results.Length; i++)
                     {
-                        var id = updateCmd.CreateParameter();
-                        id.ParameterName = $"@Id_{i}";
-                        id.DbType = DbType.Int32;
-                        updateCmd.Parameters.Add(id);
+                        var randomNumber = _random.Next(1, 10001);
 
-                        var random = updateCmd.CreateParameter();
-                        random.ParameterName = $"@Random_{i}";
-                        random.DbType = DbType.Int32;
-                        updateCmd.Parameters.Add(random);
+                        updateCmd.Parameters.Add(new NpgsqlParameter<int>(parameterName: ids[i], value: results[i].Id));
+                        updateCmd.Parameters.Add(new NpgsqlParameter<int>(parameterName: randoms[i], value: randomNumber));
 
-                        var randomNumber = _random.Next(1, 10001);
-                        id.Value = results[i].Id;
-                        random.Value = randomNumber;
                         results[i].RandomNumber = randomNumber;
                     }
 
                     await updateCmd.ExecuteNonQueryAsync();
-                    return results;
                 }
             }
+
+            return results;
         }
 
         public async Task<List<Fortune>> LoadFortunesRows()
         {
-            var result = new List<Fortune>();
+            var result = new List<Fortune>(20);
 
-            using (var db = _dbProviderFactory.CreateConnection())
-            using (var cmd = db.CreateCommand())
+            using (var db = new NpgsqlConnection(_connectionString))
             {
-                cmd.CommandText = "SELECT id, message FROM fortune";
-
-                db.ConnectionString = _connectionString;
                 await db.OpenAsync();
 
-                (cmd as MySql.Data.MySqlClient.MySqlCommand)?.Prepare();
-
-                using (var rdr = await cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection))
+                using (var cmd = new NpgsqlCommand("SELECT id, message FROM fortune", db))
+                using (var rdr = await cmd.ExecuteReaderAsync())
                 {
                     while (await rdr.ReadAsync())
                     {
                         result.Add(new Fortune
-                        {
-                            Id = rdr.GetInt32(0),
-                            Message = rdr.GetString(1)
-                        });
+                        (
+                            id:rdr.GetInt32(0),
+                            message: rdr.GetString(1)
+                        ));
                     }
                 }
             }
 
-            result.Add(new Fortune { Message = "Additional fortune added at request time." });
+            result.Add(new Fortune(id: 0, message: "Additional fortune added at request time." ));
             result.Sort();
 
             return result;
         }
+
+        private (NpgsqlCommand readCmd, NpgsqlParameter<int> idParameter) CreateReadCommand(NpgsqlConnection connection)
+        {
+            var cmd = new NpgsqlCommand("SELECT id, randomnumber FROM world WHERE id = @Id", connection);
+            var parameter = new NpgsqlParameter<int>(parameterName: "@Id", value: _random.Next(1, 10001));
+
+            cmd.Parameters.Add(parameter);
+
+            return (cmd, parameter);
+        }
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private async Task<World> ReadSingleRow(NpgsqlCommand cmd)
+        {
+            using (var rdr = await cmd.ExecuteReaderAsync(System.Data.CommandBehavior.SingleRow))
+            {
+                await rdr.ReadAsync();
+
+                return new World
+                {
+                    Id = rdr.GetInt32(0),
+                    RandomNumber = rdr.GetInt32(1)
+                };
+            }
+        }
     }
 }

+ 1 - 2
frameworks/CSharp/aspnetcore/PlatformBenchmarks/PlatformBenchmarks.csproj

@@ -15,8 +15,7 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="Npgsql" Version="4.1.2" />
-    <PackageReference Include="MySqlConnector" Version="0.62.0-beta5" />
+    <PackageReference Include="Npgsql" Version="5.0.0-alpha1" />
     <PackageReference Include="RedHat.AspNetCore.Server.Kestrel.Transport.Linux" Version="3.0.0-*" />
   </ItemGroup>
 </Project>

+ 11 - 6
frameworks/CSharp/aspnetcore/PlatformBenchmarks/Program.cs

@@ -3,11 +3,11 @@
 
 using System;
 using System.Net;
+using System.Threading.Tasks;
 using Microsoft.AspNetCore.Hosting;
 using Microsoft.Extensions.Configuration;
 #if DATABASE
 using Npgsql;
-using MySql.Data.MySqlClient;
 #endif
 
 namespace PlatformBenchmarks
@@ -16,7 +16,7 @@ namespace PlatformBenchmarks
     {
         public static string[] Args;
 
-        public static void Main(string[] args)
+        public static async Task Main(string[] args)
         {
             Args = args;
 
@@ -35,13 +35,17 @@ namespace PlatformBenchmarks
             var host = BuildWebHost(args);
             var config = (IConfiguration)host.Services.GetService(typeof(IConfiguration));
             BatchUpdateString.DatabaseServer = config.Get<AppSettings>().Database;
-            host.Run();
+#if DATABASE
+            await BenchmarkApplication.Db.PopulateCache();
+#endif
+            await host.RunAsync();
         }
 
         public static IWebHost BuildWebHost(string[] args)
         {
             var config = new ConfigurationBuilder()
                 .AddJsonFile("appsettings.json")
+                .AddEnvironmentVariables()
                 .AddEnvironmentVariables(prefix: "ASPNETCORE_")
                 .AddCommandLine(args)
                 .Build();
@@ -49,14 +53,15 @@ namespace PlatformBenchmarks
             var appSettings = config.Get<AppSettings>();
 #if DATABASE
             Console.WriteLine($"Database: {appSettings.Database}");
+            Console.WriteLine($"ConnectionString: {appSettings.ConnectionString}");
 
             if (appSettings.Database == DatabaseServer.PostgreSql)
             {
-                BenchmarkApplication.Db = new RawDb(new ConcurrentRandom(), NpgsqlFactory.Instance, appSettings);
+                BenchmarkApplication.Db = new RawDb(new ConcurrentRandom(), appSettings);
             }
-            else if (appSettings.Database == DatabaseServer.MySql)
+            else
             {
-                BenchmarkApplication.Db = new RawDb(new ConcurrentRandom(), MySqlClientFactory.Instance, appSettings);
+                throw new NotSupportedException($"{appSettings.Database} is not supported");
             }
 #endif
 

+ 4 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/appsettings.postgresql.json

@@ -0,0 +1,4 @@
+{
+  "ConnectionString": "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=256;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Delay Us=500;Write Coalescing Buffer Threshold Bytes=1000",
+  "Database": "postgresql"
+}

+ 4 - 0
frameworks/CSharp/aspnetcore/PlatformBenchmarks/appsettings.postgresql.updates.json

@@ -0,0 +1,4 @@
+{
+  "ConnectionString": "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;Maximum Pool Size=64;NoResetOnClose=true;Enlist=false;Max Auto Prepare=3",
+  "Database": "postgresql"
+}

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

@@ -7,6 +7,6 @@ FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.2 AS runtime
 ENV ASPNETCORE_URLS http://+:8080
 WORKDIR /app
 COPY --from=build /app/out ./
-COPY Benchmarks/appsettings.postgresql.updates.json ./appsettings.json
+COPY PlatformBenchmarks/appsettings.postgresql.updates.json ./appsettings.json
 
 ENTRYPOINT ["dotnet", "PlatformBenchmarks.dll"]

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

@@ -7,6 +7,6 @@ FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.2 AS runtime
 ENV ASPNETCORE_URLS http://+:8080
 WORKDIR /app
 COPY --from=build /app/out ./
-COPY Benchmarks/appsettings.postgresql.json ./appsettings.json
+COPY PlatformBenchmarks/appsettings.postgresql.json ./appsettings.json
 
 ENTRYPOINT ["dotnet", "PlatformBenchmarks.dll"]

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

@@ -7,6 +7,6 @@ FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.2 AS runtime
 ENV ASPNETCORE_URLS http://+:8080
 WORKDIR /app
 COPY --from=build /app/out ./
-COPY Benchmarks/appsettings.postgresql.updates.json ./appsettings.json
+COPY PlatformBenchmarks/appsettings.postgresql.updates.json ./appsettings.json
 
 ENTRYPOINT ["dotnet", "PlatformBenchmarks.dll", "KestrelTransport=LinuxTransport"]

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

@@ -7,6 +7,6 @@ FROM mcr.microsoft.com/dotnet/core/aspnet:3.1.2 AS runtime
 ENV ASPNETCORE_URLS http://+:8080
 WORKDIR /app
 COPY --from=build /app/out ./
-COPY Benchmarks/appsettings.postgresql.json ./appsettings.json
+COPY PlatformBenchmarks/appsettings.postgresql.json ./appsettings.json
 
 ENTRYPOINT ["dotnet", "PlatformBenchmarks.dll", "KestrelTransport=LinuxTransport"]

+ 10 - 29
frameworks/CSharp/aspnetcore/benchmark_config.json

@@ -2,8 +2,8 @@
   "framework": "aspcore",
   "tests": [{
     "default": {
-      "plaintext_url": "/p",
-      "json_url": "/j",
+      "plaintext_url": "/plaintext",
+      "json_url": "/json",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Platform",
@@ -21,8 +21,8 @@
       "versus": "aspcore"
     },
     "rhtx": {
-      "plaintext_url": "/p",
-      "json_url": "/j",
+      "plaintext_url": "/plaintext",
+      "json_url": "/json",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Platform",
@@ -42,7 +42,8 @@
     "ado-pg": {
       "fortune_url": "/fortunes",
       "db_url": "/db",
-      "query_url": "/queries/queries=",
+      "query_url": "/queries/",
+      "cached_query_url": "/cached-worlds/",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Platform",
@@ -60,7 +61,7 @@
       "versus": "aspcore-ado-pg"
     },
     "ado-pg-up": {
-      "update_url": "/updates/queries=",
+      "update_url": "/updates/",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Platform",
@@ -80,7 +81,8 @@
     "rhtx-pg": {
       "fortune_url": "/fortunes",
       "db_url": "/db",
-      "query_url": "/queries/queries=",
+      "query_url": "/queries/",
+      "cached_query_url": "/cached-worlds/",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Platform",
@@ -98,7 +100,7 @@
       "versus": "aspcore-ado-pg"
     },
     "rhtx-pg-up": {
-      "update_url": "/updates/queries=",
+      "update_url": "/updates/",
       "port": 8080,
       "approach": "Realistic",
       "classification": "Platform",
@@ -115,27 +117,6 @@
       "notes": "",
       "versus": "aspcore-ado-pg-up"
     },
-    "ado-my": {
-      "fortune_url": "/fortunes",
-      "db_url": "/db",
-      "update_url": "/updates/queries=",
-      "query_url": "/queries/queries=",
-      "port": 8080,
-      "approach": "Realistic",
-      "classification": "Platform",
-      "database": "MySQL",
-      "framework": "ASP.NET Core",
-      "language": "C#",
-      "orm": "Raw",
-      "platform": ".NET",
-      "flavor": "CoreCLR",
-      "webserver": "Kestrel",
-      "os": "Linux",
-      "database_os": "Linux",
-      "display_name": "ASP.NET Core, ADO.NET",
-      "notes": "",
-      "versus": "aspcore-ado-my"
-    },
     "mw": {
       "plaintext_url": "/plaintext",
       "port": 8080,