knownmethods optimizations
This commit is contained in:
parent
cb6059c143
commit
b89415d9b2
|
|
@ -35,20 +35,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
|
|||
private readonly static ulong _mask5Chars = GetMaskAsLong(new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 });
|
||||
private readonly static ulong _mask4Chars = GetMaskAsLong(new byte[] { 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 });
|
||||
|
||||
private readonly static Tuple<ulong, ulong, HttpMethod, int>[] _knownMethods = new Tuple<ulong, ulong, HttpMethod, int>[8];
|
||||
private readonly static Tuple<ulong, ulong, HttpMethod, int, bool>[] _knownMethods = new Tuple<ulong, ulong, HttpMethod, int, bool>[17];
|
||||
|
||||
private readonly static string[] _methodNames = new string[9];
|
||||
|
||||
static HttpUtilities()
|
||||
{
|
||||
_knownMethods[0] = Tuple.Create(_mask4Chars, _httpPutMethodLong, HttpMethod.Put, 3);
|
||||
_knownMethods[1] = Tuple.Create(_mask5Chars, _httpPostMethodLong, HttpMethod.Post, 4);
|
||||
_knownMethods[2] = Tuple.Create(_mask5Chars, _httpHeadMethodLong, HttpMethod.Head, 4);
|
||||
_knownMethods[3] = Tuple.Create(_mask6Chars, _httpTraceMethodLong, HttpMethod.Trace, 5);
|
||||
_knownMethods[4] = Tuple.Create(_mask6Chars, _httpPatchMethodLong, HttpMethod.Patch, 5);
|
||||
_knownMethods[5] = Tuple.Create(_mask7Chars, _httpDeleteMethodLong, HttpMethod.Delete, 6);
|
||||
_knownMethods[6] = Tuple.Create(_mask8Chars, _httpConnectMethodLong, HttpMethod.Connect, 7);
|
||||
_knownMethods[7] = Tuple.Create(_mask8Chars, _httpOptionsMethodLong, HttpMethod.Options, 7);
|
||||
SetKnownMethod(_mask4Chars, _httpPutMethodLong, HttpMethod.Put, 3);
|
||||
SetKnownMethod(_mask5Chars, _httpPostMethodLong, HttpMethod.Post, 4);
|
||||
SetKnownMethod(_mask5Chars, _httpHeadMethodLong, HttpMethod.Head, 4);
|
||||
SetKnownMethod(_mask6Chars, _httpTraceMethodLong, HttpMethod.Trace, 5);
|
||||
SetKnownMethod(_mask6Chars, _httpPatchMethodLong, HttpMethod.Patch, 5);
|
||||
SetKnownMethod(_mask7Chars, _httpDeleteMethodLong, HttpMethod.Delete, 6);
|
||||
SetKnownMethod(_mask8Chars, _httpConnectMethodLong, HttpMethod.Connect, 7);
|
||||
SetKnownMethod(_mask8Chars, _httpOptionsMethodLong, HttpMethod.Options, 7);
|
||||
FillEmptyKnownMethods();
|
||||
_methodNames[(byte)HttpMethod.Get] = HttpMethods.Get;
|
||||
_methodNames[(byte)HttpMethod.Put] = HttpMethods.Put;
|
||||
_methodNames[(byte)HttpMethod.Delete] = HttpMethods.Delete;
|
||||
|
|
@ -60,6 +61,33 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
|
|||
_methodNames[(byte)HttpMethod.Options] = HttpMethods.Options;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static int GetKnownMethodIndex(ulong value)
|
||||
{
|
||||
var tmp = (int)value & 0x100604;
|
||||
|
||||
return ((tmp >> 2) | (tmp >> 8) | (tmp >> 17)) & 0x0F;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void SetKnownMethod(ulong mask, ulong knownMethodUlong, HttpMethod knownMethod, int length)
|
||||
{
|
||||
_knownMethods[GetKnownMethodIndex(knownMethodUlong)] = new Tuple<ulong, ulong, HttpMethod, int, bool>(mask, knownMethodUlong, knownMethod, length, true);
|
||||
}
|
||||
|
||||
private static void FillEmptyKnownMethods()
|
||||
{
|
||||
var knownMethods = _knownMethods;
|
||||
var length = knownMethods.Length;
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
if (knownMethods[i] == null)
|
||||
{
|
||||
knownMethods[i] = new Tuple<ulong, ulong, HttpMethod, int, bool>(_mask8Chars, 0ul, HttpMethod.Custom, 0, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe static ulong GetAsciiStringAsLong(string str)
|
||||
{
|
||||
Debug.Assert(str.Length == 8, "String must be exactly 8 (ASCII) characters long.");
|
||||
|
|
@ -139,14 +167,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Internal.Infrastructure
|
|||
|
||||
if (span.TryRead<ulong>(out var value))
|
||||
{
|
||||
foreach (var x in _knownMethods)
|
||||
var key = GetKnownMethodIndex(value);
|
||||
|
||||
var x = _knownMethods[key];
|
||||
|
||||
if (x != null && (value & x.Item1) == x.Item2)
|
||||
{
|
||||
if ((value & x.Item1) == x.Item2)
|
||||
{
|
||||
method = x.Item3;
|
||||
length = x.Item4;
|
||||
return true;
|
||||
}
|
||||
method = x.Item3;
|
||||
length = x.Item4;
|
||||
return x.Item5;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,17 +11,98 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
{
|
||||
public class KnownStrings
|
||||
{
|
||||
static byte[] _method = Encoding.UTF8.GetBytes("GET ");
|
||||
static byte[] _methodGet = Encoding.UTF8.GetBytes("GET ");
|
||||
static byte[] _methodConnect = Encoding.UTF8.GetBytes("CONNECT ");
|
||||
static byte[] _methodDelete = Encoding.UTF8.GetBytes("DELETE ");
|
||||
static byte[] _methodHead = Encoding.UTF8.GetBytes("HEAD ");
|
||||
static byte[] _methodPatch = Encoding.UTF8.GetBytes("PATCH ");
|
||||
static byte[] _methodPost = Encoding.UTF8.GetBytes("POST ");
|
||||
static byte[] _methodPut = Encoding.UTF8.GetBytes("PUT ");
|
||||
static byte[] _methodOptions = Encoding.UTF8.GetBytes("OPTIONS ");
|
||||
static byte[] _methodTrace = Encoding.UTF8.GetBytes("TRACE ");
|
||||
|
||||
|
||||
|
||||
static byte[] _version = Encoding.UTF8.GetBytes("HTTP/1.1\r\n");
|
||||
const int loops = 1000;
|
||||
|
||||
[Benchmark(OperationsPerInvoke = loops * 10)]
|
||||
public int GetKnownMethod_GET()
|
||||
{
|
||||
Span<byte> data = _methodGet;
|
||||
|
||||
return GetKnownMethod(data);
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = loops * 10)]
|
||||
public int GetKnownMethod_CONNECT()
|
||||
{
|
||||
Span<byte> data = _methodConnect;
|
||||
|
||||
return GetKnownMethod(data);
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = loops * 10)]
|
||||
public int GetKnownMethod_DELETE()
|
||||
{
|
||||
Span<byte> data = _methodDelete;
|
||||
|
||||
return GetKnownMethod(data);
|
||||
}
|
||||
[Benchmark(OperationsPerInvoke = loops * 10)]
|
||||
public int GetKnownMethod_HEAD()
|
||||
{
|
||||
Span<byte> data = _methodHead;
|
||||
|
||||
return GetKnownMethod(data);
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = loops * 10)]
|
||||
public int GetKnownMethod_PATCH()
|
||||
{
|
||||
Span<byte> data = _methodPatch;
|
||||
|
||||
return GetKnownMethod(data);
|
||||
}
|
||||
[Benchmark(OperationsPerInvoke = loops * 10)]
|
||||
public int GetKnownMethod_POST()
|
||||
{
|
||||
Span<byte> data = _methodPost;
|
||||
|
||||
return GetKnownMethod(data);
|
||||
}
|
||||
[Benchmark(OperationsPerInvoke = loops * 10)]
|
||||
public int GetKnownMethod_PUT()
|
||||
{
|
||||
Span<byte> data = _methodPut;
|
||||
|
||||
return GetKnownMethod(data);
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = loops * 10)]
|
||||
public int GetKnownMethod_OPTIONS()
|
||||
{
|
||||
Span<byte> data = _methodOptions;
|
||||
|
||||
return GetKnownMethod(data);
|
||||
}
|
||||
|
||||
[Benchmark(OperationsPerInvoke = loops * 10)]
|
||||
public int GetKnownMethod_TRACE()
|
||||
{
|
||||
Span<byte> data = _methodTrace;
|
||||
|
||||
return GetKnownMethod(data);
|
||||
}
|
||||
|
||||
|
||||
private int GetKnownMethod(Span<byte> data)
|
||||
{
|
||||
int len = 0;
|
||||
HttpMethod method;
|
||||
Span<byte> data = _method;
|
||||
for (int i = 0; i < loops; i++) {
|
||||
|
||||
for (int i = 0; i < loops; i++)
|
||||
{
|
||||
data.GetKnownMethod(out method, out var length);
|
||||
len += length;
|
||||
data.GetKnownMethod(out method, out length);
|
||||
|
|
@ -46,13 +127,15 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Performance
|
|||
return len;
|
||||
}
|
||||
|
||||
|
||||
[Benchmark(OperationsPerInvoke = loops * 10)]
|
||||
public int GetKnownVersion_HTTP1_1()
|
||||
{
|
||||
int len = 0;
|
||||
HttpVersion version;
|
||||
Span<byte> data = _version;
|
||||
for (int i = 0; i < loops; i++) {
|
||||
for (int i = 0; i < loops; i++)
|
||||
{
|
||||
data.GetKnownVersion(out version, out var length);
|
||||
len += length;
|
||||
data.GetKnownVersion(out version, out length);
|
||||
|
|
|
|||
Loading…
Reference in New Issue