Skip to content
This repository has been archived by the owner on Dec 18, 2018. It is now read-only.

Faster IFeatureCollection.Get<TFeature> #2290

Merged
merged 2 commits into from
Feb 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 42 additions & 38 deletions benchmarks/Kestrel.Performance/HttpProtocolFeatureCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
using System;
using System.Buffers;
using System.IO.Pipelines;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Server.Kestrel.Core;
Expand All @@ -14,65 +17,63 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
{
public class HttpProtocolFeatureCollection
{
private readonly Http1Connection _http1Connection;
private IFeatureCollection _collection;

[Benchmark(Baseline = true)]
public IHttpRequestFeature GetFirstViaFastFeature()
{
return (IHttpRequestFeature)GetFastFeature(typeof(IHttpRequestFeature));
}

[Benchmark]
public IHttpRequestFeature GetFirstViaType()
{
return (IHttpRequestFeature)Get(typeof(IHttpRequestFeature));
}
private readonly IFeatureCollection _collection;

[Benchmark]
public IHttpRequestFeature GetFirstViaExtension()
[MethodImpl(MethodImplOptions.NoInlining)]
public IHttpRequestFeature GetViaTypeOf_First()
{
return _collection.GetType<IHttpRequestFeature>();
return (IHttpRequestFeature)_collection[typeof(IHttpRequestFeature)];
}

[Benchmark]
public IHttpRequestFeature GetFirstViaGeneric()
[MethodImpl(MethodImplOptions.NoInlining)]
public IHttpRequestFeature GetViaGeneric_First()
{
return _collection.Get<IHttpRequestFeature>();
}

[Benchmark]
public IHttpSendFileFeature GetLastViaFastFeature()
[MethodImpl(MethodImplOptions.NoInlining)]
public IHttpSendFileFeature GetViaTypeOf_Last()
{
return (IHttpSendFileFeature)GetFastFeature(typeof(IHttpSendFileFeature));
return (IHttpSendFileFeature)_collection[typeof(IHttpSendFileFeature)];
}

[Benchmark]
public IHttpSendFileFeature GetLastViaType()
[MethodImpl(MethodImplOptions.NoInlining)]
public IHttpSendFileFeature GetViaGeneric_Last()
{
return (IHttpSendFileFeature)Get(typeof(IHttpSendFileFeature));
return _collection.Get<IHttpSendFileFeature>();
}

[Benchmark]
public IHttpSendFileFeature GetLastViaExtension()
[MethodImpl(MethodImplOptions.NoInlining)]
public object GetViaTypeOf_Custom()
{
return _collection.GetType<IHttpSendFileFeature>();
return (IHttpCustomFeature)_collection[typeof(IHttpCustomFeature)];
}

[Benchmark]
public IHttpSendFileFeature GetLastViaGeneric()
[MethodImpl(MethodImplOptions.NoInlining)]
public object GetViaGeneric_Custom()
{
return _collection.Get<IHttpSendFileFeature>();
return _collection.Get<IHttpCustomFeature>();
}

private object Get(Type type)

[Benchmark]
[MethodImpl(MethodImplOptions.NoInlining)]
public object GetViaTypeOf_NotFound()
{
return _collection[type];
return (IHttpNotFoundFeature)_collection[typeof(IHttpNotFoundFeature)];
}

private object GetFastFeature(Type type)
[Benchmark]
[MethodImpl(MethodImplOptions.NoInlining)]
public object GetViaGeneric_NotFound()
{
return _http1Connection.FastFeatureGet(type);
return _collection.Get<IHttpNotFoundFeature>();
}

public HttpProtocolFeatureCollection()
Expand All @@ -99,21 +100,24 @@ public HttpProtocolFeatureCollection()

http1Connection.Reset();

_http1Connection = http1Connection;
_collection = http1Connection;
}

[IterationSetup]
public void Setup()
private class SendFileFeature : IHttpSendFileFeature
{
_collection = _http1Connection;
public Task SendFileAsync(string path, long offset, long? count, CancellationToken cancellation)
{
throw new NotImplementedException();
}
}

}
public static class IFeatureCollectionExtensions
{
public static T GetType<T>(this IFeatureCollection collection)
private interface IHttpCustomFeature
{
}

private interface IHttpNotFoundFeature
{
return (T)collection[typeof(T)];
}
}

}
2 changes: 1 addition & 1 deletion src/Kestrel.Core/Internal/Http/Http1Connection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ private void EnsureHostHeaderExists()

protected override void OnReset()
{
FastFeatureSet(typeof(IHttpUpgradeFeature), this);
ResetIHttpUpgradeFeature();

_requestTimedOut = false;
_requestTargetForm = HttpRequestTarget.Unknown;
Expand Down
14 changes: 4 additions & 10 deletions src/Kestrel.Core/Internal/Http/HttpProtocol.FeatureCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -244,20 +244,14 @@ MinDataRate IHttpMinResponseDataRateFeature.MinDataRate
set => MinResponseDataRate = value;
}

object IFeatureCollection.this[Type key]
protected void ResetIHttpUpgradeFeature()
{
get => FastFeatureGet(key) ?? ConnectionFeatures[key];
set => FastFeatureSet(key, value);
_currentIHttpUpgradeFeature = this;
}

TFeature IFeatureCollection.Get<TFeature>()
protected void ResetIHttp2StreamIdFeature()
{
return (TFeature)(FastFeatureGet(typeof(TFeature)) ?? ConnectionFeatures[typeof(TFeature)]);
}

void IFeatureCollection.Set<TFeature>(TFeature instance)
{
FastFeatureSet(typeof(TFeature), instance);
_currentIHttp2StreamIdFeature = this;
}

void IHttpResponseFeature.OnStarting(Func<object, Task> callback, object state)
Expand Down
Loading