FrameFeatureCollection benchmark (#1643)
This commit is contained in:
parent
fb22629da6
commit
2863cca8ca
|
|
@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
_currentIHttpSendFileFeature = null;
|
_currentIHttpSendFileFeature = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private object FastFeatureGet(Type key)
|
internal object FastFeatureGet(Type key)
|
||||||
{
|
{
|
||||||
if (key == IHttpRequestFeatureType)
|
if (key == IHttpRequestFeatureType)
|
||||||
{
|
{
|
||||||
|
|
@ -132,7 +132,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return ExtraFeatureGet(key);
|
return ExtraFeatureGet(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FastFeatureSet(Type key, object feature)
|
internal void FastFeatureSet(Type key, object feature)
|
||||||
{
|
{
|
||||||
_featureRevision++;
|
_featureRevision++;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,107 @@
|
||||||
|
// 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 BenchmarkDotNet.Attributes;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
|
{
|
||||||
|
[Config(typeof(CoreConfig))]
|
||||||
|
public class FrameFeatureCollection
|
||||||
|
{
|
||||||
|
private readonly Frame<object> _frame;
|
||||||
|
private IFeatureCollection _collection;
|
||||||
|
|
||||||
|
[Benchmark(Baseline = true)]
|
||||||
|
public IHttpRequestFeature GetFirstViaFastFeature()
|
||||||
|
{
|
||||||
|
return (IHttpRequestFeature)GetFastFeature(typeof(IHttpRequestFeature));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public IHttpRequestFeature GetFirstViaType()
|
||||||
|
{
|
||||||
|
return (IHttpRequestFeature)Get(typeof(IHttpRequestFeature));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public IHttpRequestFeature GetFirstViaExtension()
|
||||||
|
{
|
||||||
|
return _collection.GetType<IHttpRequestFeature>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public IHttpRequestFeature GetFirstViaGeneric()
|
||||||
|
{
|
||||||
|
return _collection.Get<IHttpRequestFeature>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public IHttpSendFileFeature GetLastViaFastFeature()
|
||||||
|
{
|
||||||
|
return (IHttpSendFileFeature)GetFastFeature(typeof(IHttpSendFileFeature));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public IHttpSendFileFeature GetLastViaType()
|
||||||
|
{
|
||||||
|
return (IHttpSendFileFeature)Get(typeof(IHttpSendFileFeature));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public IHttpSendFileFeature GetLastViaExtension()
|
||||||
|
{
|
||||||
|
return _collection.GetType<IHttpSendFileFeature>();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Benchmark]
|
||||||
|
public IHttpSendFileFeature GetLastViaGeneric()
|
||||||
|
{
|
||||||
|
return _collection.Get<IHttpSendFileFeature> ();
|
||||||
|
}
|
||||||
|
|
||||||
|
private object Get(Type type)
|
||||||
|
{
|
||||||
|
return _collection[type];
|
||||||
|
}
|
||||||
|
|
||||||
|
private object GetFastFeature(Type type)
|
||||||
|
{
|
||||||
|
return _frame.FastFeatureGet(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrameFeatureCollection()
|
||||||
|
{
|
||||||
|
var serviceContext = new ServiceContext
|
||||||
|
{
|
||||||
|
HttpParserFactory = _ => NullParser.Instance,
|
||||||
|
ServerOptions = new KestrelServerOptions()
|
||||||
|
};
|
||||||
|
var frameContext = new FrameContext
|
||||||
|
{
|
||||||
|
ServiceContext = serviceContext,
|
||||||
|
ConnectionInformation = new MockConnectionInformation()
|
||||||
|
};
|
||||||
|
|
||||||
|
_frame = new Frame<object>(application: null, frameContext: frameContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Setup]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
_collection = _frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public static class IFeatureCollectionExtensions
|
||||||
|
{
|
||||||
|
public static T GetType<T>(this IFeatureCollection collection)
|
||||||
|
{
|
||||||
|
return (T)collection[typeof(T)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System.Text;
|
|
||||||
using BenchmarkDotNet.Attributes;
|
using BenchmarkDotNet.Attributes;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Internal.System;
|
|
||||||
using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
|
using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
|
|
@ -100,52 +98,5 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
ErrorUtilities.ThrowInvalidRequestHeaders();
|
ErrorUtilities.ThrowInvalidRequestHeaders();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NullParser : IHttpParser
|
|
||||||
{
|
|
||||||
private readonly byte[] _startLine = Encoding.ASCII.GetBytes("GET /plaintext HTTP/1.1\r\n");
|
|
||||||
private readonly byte[] _target = Encoding.ASCII.GetBytes("/plaintext");
|
|
||||||
private readonly byte[] _hostHeaderName = Encoding.ASCII.GetBytes("Host");
|
|
||||||
private readonly byte[] _hostHeaderValue = Encoding.ASCII.GetBytes("www.example.com");
|
|
||||||
private readonly byte[] _acceptHeaderName = Encoding.ASCII.GetBytes("Accept");
|
|
||||||
private readonly byte[] _acceptHeaderValue = Encoding.ASCII.GetBytes("text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7\r\n\r\n");
|
|
||||||
private readonly byte[] _connectionHeaderName = Encoding.ASCII.GetBytes("Connection");
|
|
||||||
private readonly byte[] _connectionHeaderValue = Encoding.ASCII.GetBytes("keep-alive");
|
|
||||||
|
|
||||||
public static readonly NullParser Instance = new NullParser();
|
|
||||||
|
|
||||||
public bool ParseHeaders(IHttpHeadersHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes)
|
|
||||||
{
|
|
||||||
handler.OnHeader(new Span<byte>(_hostHeaderName), new Span<byte>(_hostHeaderValue));
|
|
||||||
handler.OnHeader(new Span<byte>(_acceptHeaderName), new Span<byte>(_acceptHeaderValue));
|
|
||||||
handler.OnHeader(new Span<byte>(_connectionHeaderName), new Span<byte>(_connectionHeaderValue));
|
|
||||||
|
|
||||||
consumedBytes = 0;
|
|
||||||
consumed = buffer.Start;
|
|
||||||
examined = buffer.End;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ParseRequestLine(IHttpRequestLineHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined)
|
|
||||||
{
|
|
||||||
handler.OnStartLine(HttpMethod.Get,
|
|
||||||
HttpVersion.Http11,
|
|
||||||
new Span<byte>(_target),
|
|
||||||
new Span<byte>(_target),
|
|
||||||
Span<byte>.Empty,
|
|
||||||
Span<byte>.Empty,
|
|
||||||
false);
|
|
||||||
|
|
||||||
consumed = buffer.Start;
|
|
||||||
examined = buffer.End;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
// 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.Text;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Internal.System;
|
||||||
|
using Microsoft.AspNetCore.Server.Kestrel.Internal.System.IO.Pipelines;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
||||||
|
{
|
||||||
|
public class NullParser : IHttpParser
|
||||||
|
{
|
||||||
|
private readonly byte[] _startLine = Encoding.ASCII.GetBytes("GET /plaintext HTTP/1.1\r\n");
|
||||||
|
private readonly byte[] _target = Encoding.ASCII.GetBytes("/plaintext");
|
||||||
|
private readonly byte[] _hostHeaderName = Encoding.ASCII.GetBytes("Host");
|
||||||
|
private readonly byte[] _hostHeaderValue = Encoding.ASCII.GetBytes("www.example.com");
|
||||||
|
private readonly byte[] _acceptHeaderName = Encoding.ASCII.GetBytes("Accept");
|
||||||
|
private readonly byte[] _acceptHeaderValue = Encoding.ASCII.GetBytes("text/plain,text/html;q=0.9,application/xhtml+xml;q=0.9,application/xml;q=0.8,*/*;q=0.7\r\n\r\n");
|
||||||
|
private readonly byte[] _connectionHeaderName = Encoding.ASCII.GetBytes("Connection");
|
||||||
|
private readonly byte[] _connectionHeaderValue = Encoding.ASCII.GetBytes("keep-alive");
|
||||||
|
|
||||||
|
public static readonly NullParser Instance = new NullParser();
|
||||||
|
|
||||||
|
public bool ParseHeaders(IHttpHeadersHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined, out int consumedBytes)
|
||||||
|
{
|
||||||
|
handler.OnHeader(new Span<byte>(_hostHeaderName), new Span<byte>(_hostHeaderValue));
|
||||||
|
handler.OnHeader(new Span<byte>(_acceptHeaderName), new Span<byte>(_acceptHeaderValue));
|
||||||
|
handler.OnHeader(new Span<byte>(_connectionHeaderName), new Span<byte>(_connectionHeaderValue));
|
||||||
|
|
||||||
|
consumedBytes = 0;
|
||||||
|
consumed = buffer.Start;
|
||||||
|
examined = buffer.End;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ParseRequestLine(IHttpRequestLineHandler handler, ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined)
|
||||||
|
{
|
||||||
|
handler.OnStartLine(HttpMethod.Get,
|
||||||
|
HttpVersion.Http11,
|
||||||
|
new Span<byte>(_target),
|
||||||
|
new Span<byte>(_target),
|
||||||
|
Span<byte>.Empty,
|
||||||
|
Span<byte>.Empty,
|
||||||
|
false);
|
||||||
|
|
||||||
|
consumed = buffer.Start;
|
||||||
|
examined = buffer.End;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -87,7 +87,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
_current{feature.Name} = null;")}
|
_current{feature.Name} = null;")}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
private object FastFeatureGet(Type key)
|
internal object FastFeatureGet(Type key)
|
||||||
{{{Each(allFeatures, feature => $@"
|
{{{Each(allFeatures, feature => $@"
|
||||||
if (key == {feature.Name}Type)
|
if (key == {feature.Name}Type)
|
||||||
{{
|
{{
|
||||||
|
|
@ -96,7 +96,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http
|
||||||
return ExtraFeatureGet(key);
|
return ExtraFeatureGet(key);
|
||||||
}}
|
}}
|
||||||
|
|
||||||
private void FastFeatureSet(Type key, object feature)
|
internal void FastFeatureSet(Type key, object feature)
|
||||||
{{
|
{{
|
||||||
_featureRevision++;
|
_featureRevision++;
|
||||||
{Each(allFeatures, feature => $@"
|
{Each(allFeatures, feature => $@"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue