Skip to content

Commit 77fd805

Browse files
authored
Aspnet platform updates (TechEmpower#5807)
* Sync, Update Urls for round 20 * Add cached query * Reuse existing multiquery output
1 parent ddada64 commit 77fd805

24 files changed

+472
-328
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using System.IO.Pipelines;
5+
using System.Threading.Tasks;
6+
7+
namespace PlatformBenchmarks
8+
{
9+
public partial class BenchmarkApplication
10+
{
11+
private async Task Caching(PipeWriter pipeWriter, int count)
12+
{
13+
OutputMultipleQueries(pipeWriter, await Db.LoadCachedQueries(count));
14+
}
15+
}
16+
}

frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Fortunes.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ private async Task Fortunes(PipeWriter pipeWriter)
2323

2424
private void OutputFortunes(PipeWriter pipeWriter, List<Fortune> model)
2525
{
26-
var writer = GetWriter(pipeWriter);
26+
var writer = GetWriter(pipeWriter, sizeHint: 1600); // in reality it's 1361
2727

2828
writer.Write(_fortunesPreamble);
2929

frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.HttpConnection.cs

+60-45
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation. All rights reserved.
1+
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
@@ -75,7 +75,7 @@ private async Task ProcessRequestsAsync()
7575
private bool HandleRequests(in ReadOnlySequence<byte> buffer, bool isCompleted)
7676
{
7777
var reader = new SequenceReader<byte>(buffer);
78-
var writer = GetWriter(Writer);
78+
var writer = GetWriter(Writer, sizeHint: 160 * 16); // 160*16 is for Plaintext, for Json 160 would be enough
7979

8080
while (true)
8181
{
@@ -112,18 +112,21 @@ private bool ParseHttpRequest(ref SequenceReader<byte> reader, bool isCompleted)
112112

113113
if (state == State.StartLine)
114114
{
115-
#if NETCOREAPP5_0
116-
var unconsumedSequence = reader.UnreadSequence;
115+
#if NETCOREAPP5_0 || NET5_0
116+
if (Parser.ParseRequestLine(new ParsingAdapter(this), ref reader))
117+
{
118+
state = State.Headers;
119+
}
117120
#else
118121
var unconsumedSequence = reader.Sequence.Slice(reader.Position);
119-
#endif
120122
if (Parser.ParseRequestLine(new ParsingAdapter(this), unconsumedSequence, out var consumed, out _))
121123
{
122124
state = State.Headers;
123125

124126
var parsedLength = unconsumedSequence.Slice(reader.Position, consumed).Length;
125127
reader.Advance(parsedLength);
126128
}
129+
#endif
127130
}
128131

129132
if (state == State.Headers)
@@ -150,11 +153,17 @@ private async Task ProcessRequestsAsync()
150153
while (true)
151154
{
152155
var readResult = await Reader.ReadAsync();
153-
154156
var buffer = readResult.Buffer;
157+
var isCompleted = readResult.IsCompleted;
158+
159+
if (buffer.IsEmpty && isCompleted)
160+
{
161+
return;
162+
}
163+
155164
while (true)
156165
{
157-
if (!ParseHttpRequest(ref buffer, readResult.IsCompleted, out var examined))
166+
if (!ParseHttpRequest(ref buffer, isCompleted))
158167
{
159168
return;
160169
}
@@ -173,67 +182,71 @@ private async Task ProcessRequestsAsync()
173182
}
174183

175184
// No more input or incomplete data, Advance the Reader
176-
Reader.AdvanceTo(buffer.Start, examined);
185+
Reader.AdvanceTo(buffer.Start, buffer.End);
177186
break;
178187
}
179188

180189
await Writer.FlushAsync();
181190
}
182191
}
183192

184-
private bool ParseHttpRequest(ref ReadOnlySequence<byte> buffer, bool isCompleted, out SequencePosition examined)
193+
private bool ParseHttpRequest(ref ReadOnlySequence<byte> buffer, bool isCompleted)
185194
{
186-
examined = buffer.End;
195+
var reader = new SequenceReader<byte>(buffer);
187196
var state = _state;
188197

189-
if (!buffer.IsEmpty)
198+
if (state == State.StartLine)
190199
{
191-
SequencePosition consumed;
192-
if (state == State.StartLine)
200+
#if NETCOREAPP5_0 || NET5_0
201+
if (Parser.ParseRequestLine(new ParsingAdapter(this), ref reader))
193202
{
194-
if (Parser.ParseRequestLine(new ParsingAdapter(this), buffer, out consumed, out examined))
195-
{
196-
state = State.Headers;
197-
}
198-
199-
buffer = buffer.Slice(consumed);
203+
state = State.Headers;
200204
}
201-
202-
if (state == State.Headers)
205+
#else
206+
var unconsumedSequence = reader.Sequence.Slice(reader.Position);
207+
if (Parser.ParseRequestLine(new ParsingAdapter(this), unconsumedSequence, out var consumed, out _))
203208
{
204-
var reader = new SequenceReader<byte>(buffer);
205-
var success = Parser.ParseHeaders(new ParsingAdapter(this), ref reader);
206-
207-
consumed = reader.Position;
208-
if (success)
209-
{
210-
examined = consumed;
211-
state = State.Body;
212-
}
213-
else
214-
{
215-
examined = buffer.End;
216-
}
209+
state = State.Headers;
217210

218-
buffer = buffer.Slice(consumed);
211+
var parsedLength = unconsumedSequence.Slice(reader.Position, consumed).Length;
212+
reader.Advance(parsedLength);
219213
}
214+
#endif
215+
}
220216

221-
if (state != State.Body && isCompleted)
217+
if (state == State.Headers)
218+
{
219+
var success = Parser.ParseHeaders(new ParsingAdapter(this), ref reader);
220+
221+
if (success)
222222
{
223-
ThrowUnexpectedEndOfData();
223+
state = State.Body;
224224
}
225225
}
226-
else if (isCompleted)
226+
227+
if (state != State.Body && isCompleted)
227228
{
228-
return false;
229+
ThrowUnexpectedEndOfData();
229230
}
230231

231232
_state = state;
233+
234+
if (state == State.Body)
235+
{
236+
// Complete request read, consumed and examined are the same (length 0)
237+
buffer = buffer.Slice(reader.Position, 0);
238+
}
239+
else
240+
{
241+
// In-complete request read, consumed is current position and examined is the remaining.
242+
buffer = buffer.Slice(reader.Position);
243+
}
244+
232245
return true;
233246
}
234247
#endif
235248

236-
#if NETCOREAPP5_0
249+
#if NETCOREAPP5_0 || NET5_0
237250

238251
public void OnStaticIndexedHeader(int index)
239252
{
@@ -271,8 +284,8 @@ private enum State
271284
}
272285

273286
[MethodImpl(MethodImplOptions.AggressiveInlining)]
274-
private static BufferWriter<WriterAdapter> GetWriter(PipeWriter pipeWriter)
275-
=> new BufferWriter<WriterAdapter>(new WriterAdapter(pipeWriter));
287+
private static BufferWriter<WriterAdapter> GetWriter(PipeWriter pipeWriter, int sizeHint)
288+
=> new BufferWriter<WriterAdapter>(new WriterAdapter(pipeWriter), sizeHint);
276289

277290
private struct WriterAdapter : IBufferWriter<byte>
278291
{
@@ -298,7 +311,7 @@ private struct ParsingAdapter : IHttpRequestLineHandler, IHttpHeadersHandler
298311
public ParsingAdapter(BenchmarkApplication requestHandler)
299312
=> RequestHandler = requestHandler;
300313

301-
#if NETCOREAPP5_0
314+
#if NETCOREAPP5_0 || NET5_0
302315
public void OnStaticIndexedHeader(int index)
303316
=> RequestHandler.OnStaticIndexedHeader(index);
304317

@@ -310,15 +323,17 @@ public void OnHeader(ReadOnlySpan<byte> name, ReadOnlySpan<byte> value)
310323

311324
public void OnHeadersComplete(bool endStream)
312325
=> RequestHandler.OnHeadersComplete(endStream);
326+
327+
public void OnStartLine(HttpVersionAndMethod versionAndMethod, TargetOffsetPathLength targetPath, Span<byte> startLine)
328+
=> RequestHandler.OnStartLine(versionAndMethod, targetPath, startLine);
313329
#else
314330
public void OnHeader(Span<byte> name, Span<byte> value)
315331
=> RequestHandler.OnHeader(name, value);
316332
public void OnHeadersComplete()
317333
=> RequestHandler.OnHeadersComplete();
318-
#endif
319-
320334
public void OnStartLine(HttpMethod method, HttpVersion version, Span<byte> target, Span<byte> path, Span<byte> query, Span<byte> customMethod, bool pathEncoded)
321335
=> RequestHandler.OnStartLine(method, version, target, path, query, customMethod, pathEncoded);
336+
#endif
322337
}
323338
}
324339
}

frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Json.cs

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System;
5+
using System.Buffers;
46
using System.Text.Json;
57

68
namespace PlatformBenchmarks
@@ -15,7 +17,7 @@ public partial class BenchmarkApplication
1517
_headerContentTypeJson + _crlf +
1618
_headerContentLength + _jsonPayloadSize.ToString();
1719

18-
private static void Json(ref BufferWriter<WriterAdapter> writer)
20+
private static void Json(ref BufferWriter<WriterAdapter> writer, IBufferWriter<byte> bodyWriter)
1921
{
2022
writer.Write(_jsonPreamble);
2123

@@ -24,11 +26,11 @@ private static void Json(ref BufferWriter<WriterAdapter> writer)
2426

2527
writer.Commit();
2628

29+
Utf8JsonWriter utf8JsonWriter = t_writer ??= new Utf8JsonWriter(bodyWriter, new JsonWriterOptions { SkipValidation = true });
30+
utf8JsonWriter.Reset(bodyWriter);
31+
2732
// Body
28-
using (Utf8JsonWriter utf8JsonWriter = new Utf8JsonWriter(writer.Output))
29-
{
30-
JsonSerializer.Serialize<JsonMessage>(utf8JsonWriter, new JsonMessage { message = "Hello, World!" }, SerializerOptions);
31-
}
33+
JsonSerializer.Serialize<JsonMessage>(utf8JsonWriter, new JsonMessage { message = "Hello, World!" }, SerializerOptions);
3234
}
3335
}
3436
}

frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.MultipleQueries.cs

+12-6
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,26 @@ private async Task MultipleQueries(PipeWriter pipeWriter, int count)
1616

1717
private static void OutputMultipleQueries(PipeWriter pipeWriter, World[] rows)
1818
{
19-
var writer = GetWriter(pipeWriter);
19+
var writer = GetWriter(pipeWriter, sizeHint: 160 * rows.Length); // in reality it's 152 for one
2020

2121
writer.Write(_dbPreamble);
2222

23-
// Content-Length
24-
var jsonPayload = JsonSerializer.SerializeToUtf8Bytes(rows, SerializerOptions);
25-
writer.WriteNumeric((uint)jsonPayload.Length);
23+
var lengthWriter = writer;
24+
writer.Write(_contentLengthGap);
2625

2726
// Date header
2827
writer.Write(DateHeader.HeaderBytes);
2928

30-
// Body
31-
writer.Write(jsonPayload);
3229
writer.Commit();
30+
31+
Utf8JsonWriter utf8JsonWriter = t_writer ??= new Utf8JsonWriter(pipeWriter, new JsonWriterOptions { SkipValidation = true });
32+
utf8JsonWriter.Reset(pipeWriter);
33+
34+
// Body
35+
JsonSerializer.Serialize<World[]>(utf8JsonWriter, rows, SerializerOptions);
36+
37+
// Content-Length
38+
lengthWriter.WriteNumeric((uint)utf8JsonWriter.BytesCommitted);
3339
}
3440
}
3541
}

frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.SingleQuery.cs

+12-6
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,26 @@ private async Task SingleQuery(PipeWriter pipeWriter)
1616

1717
private static void OutputSingleQuery(PipeWriter pipeWriter, World row)
1818
{
19-
var writer = GetWriter(pipeWriter);
19+
var writer = GetWriter(pipeWriter, sizeHint: 180); // in reality it's 150
2020

2121
writer.Write(_dbPreamble);
2222

23-
// Content-Length
24-
var jsonPayload = JsonSerializer.SerializeToUtf8Bytes(row, SerializerOptions);
25-
writer.WriteNumeric((uint)jsonPayload.Length);
23+
var lengthWriter = writer;
24+
writer.Write(_contentLengthGap);
2625

2726
// Date header
2827
writer.Write(DateHeader.HeaderBytes);
2928

30-
// Body
31-
writer.Write(jsonPayload);
3229
writer.Commit();
30+
31+
Utf8JsonWriter utf8JsonWriter = t_writer ??= new Utf8JsonWriter(pipeWriter, new JsonWriterOptions { SkipValidation = true });
32+
utf8JsonWriter.Reset(pipeWriter);
33+
34+
// Body
35+
JsonSerializer.Serialize<World>(utf8JsonWriter, row, SerializerOptions);
36+
37+
// Content-Length
38+
lengthWriter.WriteNumeric((uint)utf8JsonWriter.BytesCommitted);
3339
}
3440
}
3541
}

frameworks/CSharp/aspnetcore/PlatformBenchmarks/BenchmarkApplication.Updates.cs

+12-6
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,26 @@ private async Task Updates(PipeWriter pipeWriter, int count)
1616

1717
private static void OutputUpdates(PipeWriter pipeWriter, World[] rows)
1818
{
19-
var writer = GetWriter(pipeWriter);
19+
var writer = GetWriter(pipeWriter, sizeHint: 120 * rows.Length); // in reality it's 112 for one
2020

2121
writer.Write(_dbPreamble);
2222

23-
// Content-Length
24-
var jsonPayload = JsonSerializer.SerializeToUtf8Bytes(rows, SerializerOptions);
25-
writer.WriteNumeric((uint)jsonPayload.Length);
23+
var lengthWriter = writer;
24+
writer.Write(_contentLengthGap);
2625

2726
// Date header
2827
writer.Write(DateHeader.HeaderBytes);
2928

30-
// Body
31-
writer.Write(jsonPayload);
3229
writer.Commit();
30+
31+
Utf8JsonWriter utf8JsonWriter = t_writer ??= new Utf8JsonWriter(pipeWriter, new JsonWriterOptions { SkipValidation = true });
32+
utf8JsonWriter.Reset(pipeWriter);
33+
34+
// Body
35+
JsonSerializer.Serialize<World[]>(utf8JsonWriter, rows, SerializerOptions);
36+
37+
// Content-Length
38+
lengthWriter.WriteNumeric((uint)utf8JsonWriter.BytesCommitted);
3339
}
3440
}
3541
}

0 commit comments

Comments
 (0)