diff --git a/tests/Benchmarks/Http/HttpParser.cs b/tests/Benchmarks/Http/HttpParser.cs new file mode 100644 index 00000000000..38b70e8c478 --- /dev/null +++ b/tests/Benchmarks/Http/HttpParser.cs @@ -0,0 +1,111 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using BenchmarkDotNet.Attributes; +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Text; +using System.Text.Http.Parser; + +public class HttpParser +{ + private const string _plaintextTechEmpowerRequest = + "GET /plaintext HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Accept: text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7\r\n" + + "Connection: keep-alive\r\n" + + "\r\n"; + + private const string _plaintextTechEmpowerHeaders = + "Host: localhost\r\n" + + "Accept: text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7\r\n" + + "Connection: keep-alive\r\n" + + "\r\n"; + + private static readonly byte[] s_plaintextTechEmpowerHeadersArray = Encoding.UTF8.GetBytes(_plaintextTechEmpowerHeaders); + private static readonly byte[] s_plaintextTechEmpowerRequestArray = Encoding.UTF8.GetBytes(_plaintextTechEmpowerRequest); + + private static readonly ReadOnlySequence s_plaintextTechEmpowerRequestRos = new ReadOnlySequence(s_plaintextTechEmpowerRequestArray); + private static readonly ReadOnlySequence s_plaintextTechEmpowerHeadersRos = new ReadOnlySequence(s_plaintextTechEmpowerHeadersArray); + + private static readonly System.Text.Http.Parser.HttpParser s_parser = new System.Text.Http.Parser.HttpParser(); + + [Benchmark] + public void RequestLine() + { + var request = new Request(); + s_parser.ParseRequestLine(request, s_plaintextTechEmpowerRequestRos, out _, out _); + } + + [Benchmark] + public void Headers() + { + var request = new Request(); + s_parser.ParseHeaders(request, s_plaintextTechEmpowerHeadersRos, out _, out _, out _); + } + + [Benchmark] + public void FullRequest() + { + var request = new Request(); + s_parser.ParseRequestLine(request, s_plaintextTechEmpowerRequestRos, out var consumed, out _); + s_parser.ParseHeaders(request, s_plaintextTechEmpowerRequestRos.Slice(consumed), out consumed, out _, out _); + } +} + +class Request : IHttpHeadersHandler, IHttpRequestLineHandler +{ + //public Http.Method Method; + //public Http.Version Version; + //public string Path; + //public string Query; + //public string Target; + + public Dictionary Headers = new Dictionary(); + + public void OnHeader(ReadOnlySpan name, ReadOnlySpan value) + { + //var nameString = PrimitiveEncoder.DecodeAscii(name); + //var valueString = PrimitiveEncoder.DecodeAscii(value); + //Headers.Add(nameString, valueString); + } + + public void OnStartLine(Http.Method method, Http.Version version, ReadOnlySpan target, ReadOnlySpan path, ReadOnlySpan query, ReadOnlySpan customMethod, bool pathEncoded) + { + //Method = method; + //Version = version; + //Path = PrimitiveEncoder.DecodeAscii(path); + //Query = PrimitiveEncoder.DecodeAscii(query); + //Target = PrimitiveEncoder.DecodeAscii(target); + } +} + +struct RequestStruct : IHttpHeadersHandler, IHttpRequestLineHandler +{ + //public Http.Method Method; + //public Http.Version Version; + //public string Path; + //public string Query; + //public string Target; + + //public Dictionary Headers = new Dictionary(); + + public void OnHeader(ReadOnlySpan name, ReadOnlySpan value) + { + //var nameString = PrimitiveEncoder.DecodeAscii(name); + //var valueString = PrimitiveEncoder.DecodeAscii(value); + //Headers.Add(nameString, valueString); + } + + public void OnStartLine(Http.Method method, Http.Version version, ReadOnlySpan target, ReadOnlySpan path, ReadOnlySpan query, ReadOnlySpan customMethod, bool pathEncoded) + { + //Method = method; + //Version = version; + //Path = PrimitiveEncoder.DecodeAscii(path); + //Query = PrimitiveEncoder.DecodeAscii(query); + //Target = PrimitiveEncoder.DecodeAscii(target); + } +} + diff --git a/tests/Benchmarks/HttpParserBench.cs b/tests/Benchmarks/HttpParserBench.cs deleted file mode 100644 index 92228a05f97..00000000000 --- a/tests/Benchmarks/HttpParserBench.cs +++ /dev/null @@ -1,193 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Xunit.Performance; -using System; -using System.Buffers; -using System.Collections.Generic; -using System.Text; -using System.Text.Http.Parser; - -public class HttpParserBench -{ - private static readonly byte[] s_plaintextTechEmpowerRequestBytes = Encoding.UTF8.GetBytes(_plaintextTechEmpowerRequest); - - private const string _plaintextTechEmpowerRequest = - "GET /plaintext HTTP/1.1\r\n" + - "Host: localhost\r\n" + - "Accept: text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7\r\n" + - "Connection: keep-alive\r\n" + - "\r\n"; - - private static readonly byte[] s_plaintextTechEmpowerHeadersBytes = Encoding.UTF8.GetBytes(_plaintextTechEmpowerHeaders); - - private const string _plaintextTechEmpowerHeaders = - "Host: localhost\r\n" + - "Accept: text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7\r\n" + - "Connection: keep-alive\r\n" + - "\r\n"; - - const int Itterations = 10000; - - [Benchmark(InnerIterationCount = Itterations)] - static bool RequestLine() - { - ReadOnlySequence buffer = new ReadOnlySequence(s_plaintextTechEmpowerRequestBytes, 0, s_plaintextTechEmpowerHeadersBytes.Length); - var parser = new HttpParser(); - var request = new Request(); - SequencePosition consumed = default; - SequencePosition read; - bool success = true; - - foreach (var iteration in Benchmark.Iterations) - { - using (iteration.StartMeasurement()) - { - for (int i = 0; i < Benchmark.InnerIterationCount; i++) - { - success = success && parser.ParseRequestLine(request, buffer, out consumed, out read); - success = success && parser.ParseRequestLine(request, buffer, out consumed, out read); - success = success && parser.ParseRequestLine(request, buffer, out consumed, out read); - success = success && parser.ParseRequestLine(request, buffer, out consumed, out read); - success = success && parser.ParseRequestLine(request, buffer, out consumed, out read); - success = success && parser.ParseRequestLine(request, buffer, out consumed, out read); - success = success && parser.ParseRequestLine(request, buffer, out consumed, out read); - success = success && parser.ParseRequestLine(request, buffer, out consumed, out read); - success = success && parser.ParseRequestLine(request, buffer, out consumed, out read); - success = success && parser.ParseRequestLine(request, buffer, out consumed, out read); - - } - } - } - - return success; - } - - [Benchmark(InnerIterationCount = Itterations)] - static bool Headers() - { - ReadOnlySequence buffer = new ReadOnlySequence(s_plaintextTechEmpowerHeadersBytes); - var parser = new HttpParser(); - var request = new Request(); - SequencePosition consumed; - SequencePosition examined; - int consumedBytes; - bool success = true; - - foreach (var iteration in Benchmark.Iterations) - { - using (iteration.StartMeasurement()) - { - for (int i = 0; i < Benchmark.InnerIterationCount; i++) - { - success = success && parser.ParseHeaders(request, buffer, out consumed, out examined, out consumedBytes); - success = success && parser.ParseHeaders(request, buffer, out consumed, out examined, out consumedBytes); - success = success && parser.ParseHeaders(request, buffer, out consumed, out examined, out consumedBytes); - success = success && parser.ParseHeaders(request, buffer, out consumed, out examined, out consumedBytes); - success = success && parser.ParseHeaders(request, buffer, out consumed, out examined, out consumedBytes); - success = success && parser.ParseHeaders(request, buffer, out consumed, out examined, out consumedBytes); - success = success && parser.ParseHeaders(request, buffer, out consumed, out examined, out consumedBytes); - success = success && parser.ParseHeaders(request, buffer, out consumed, out examined, out consumedBytes); - success = success && parser.ParseHeaders(request, buffer, out consumed, out examined, out consumedBytes); - success = success && parser.ParseHeaders(request, buffer, out consumed, out examined, out consumedBytes); - } - } - } - - return success; - } - - [Benchmark(InnerIterationCount = Itterations)] - static bool FullRequest() - { - ReadOnlySequence buffer = new ReadOnlySequence(s_plaintextTechEmpowerRequestBytes); - var parser = new HttpParser(); - var request = new Request(); - int consumedBytes = 0; - SequencePosition examined; - SequencePosition consumed = buffer.Start; - bool success = true; - - foreach (var iteration in Benchmark.Iterations) - { - using (iteration.StartMeasurement()) - { - for (int i = 0; i < Benchmark.InnerIterationCount; i++) - { - success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined); - success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes); - - success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined); - success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes); - - success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined); - success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes); - - success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined); - success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes); - - success = success && parser.ParseRequestLine(request, buffer, out consumed, out examined); - success = success && parser.ParseHeaders(request, buffer.Slice(consumed), out consumed, out examined, out consumedBytes); - } - } - } - - return success; - } -} - -class Request : IHttpHeadersHandler, IHttpRequestLineHandler -{ - //public Http.Method Method; - //public Http.Version Version; - //public string Path; - //public string Query; - //public string Target; - - public Dictionary Headers = new Dictionary(); - - public void OnHeader(ReadOnlySpan name, ReadOnlySpan value) - { - //var nameString = PrimitiveEncoder.DecodeAscii(name); - //var valueString = PrimitiveEncoder.DecodeAscii(value); - //Headers.Add(nameString, valueString); - } - - public void OnStartLine(Http.Method method, Http.Version version, ReadOnlySpan target, ReadOnlySpan path, ReadOnlySpan query, ReadOnlySpan customMethod, bool pathEncoded) - { - //Method = method; - //Version = version; - //Path = PrimitiveEncoder.DecodeAscii(path); - //Query = PrimitiveEncoder.DecodeAscii(query); - //Target = PrimitiveEncoder.DecodeAscii(target); - } -} - -struct RequestStruct : IHttpHeadersHandler, IHttpRequestLineHandler -{ - //public Http.Method Method; - //public Http.Version Version; - //public string Path; - //public string Query; - //public string Target; - - //public Dictionary Headers = new Dictionary(); - - public void OnHeader(ReadOnlySpan name, ReadOnlySpan value) - { - //var nameString = PrimitiveEncoder.DecodeAscii(name); - //var valueString = PrimitiveEncoder.DecodeAscii(value); - //Headers.Add(nameString, valueString); - } - - public void OnStartLine(Http.Method method, Http.Version version, ReadOnlySpan target, ReadOnlySpan path, ReadOnlySpan query, ReadOnlySpan customMethod, bool pathEncoded) - { - //Method = method; - //Version = version; - //Path = PrimitiveEncoder.DecodeAscii(path); - //Query = PrimitiveEncoder.DecodeAscii(query); - //Target = PrimitiveEncoder.DecodeAscii(target); - } -} -