From 186f6d0a05e2447e78dd1e51a0f7526dda0e2195 Mon Sep 17 00:00:00 2001 From: Ben Adams Date: Thu, 17 Dec 2015 10:18:20 +0000 Subject: [PATCH] Horizontal initialize repeat vectors once --- .../Http/Frame.cs | 21 ++- .../Infrastructure/MemoryPoolIterator2.cs | 146 +++++++++--------- .../MemoryPoolBlock2Tests.cs | 38 +++-- .../MemoryPoolIterator2Tests.cs | 9 +- 4 files changed, 114 insertions(+), 100 deletions(-) diff --git a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs index 74f3ef6889..a69c5fc0d2 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Http/Frame.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; +using System.Numerics; using System.Text; using System.Threading; using System.Threading.Tasks; @@ -39,6 +40,12 @@ namespace Microsoft.AspNet.Server.Kestrel.Http private static readonly byte[] _bytesDate = Encoding.ASCII.GetBytes("Date: "); private static readonly byte[] _bytesEndHeaders = Encoding.ASCII.GetBytes("\r\n\r\n"); + private static readonly Vector _vectorCRs = new Vector((byte)'\r'); + private static readonly Vector _vectorColons = new Vector((byte)':'); + private static readonly Vector _vectorSpaces = new Vector((byte)' '); + private static readonly Vector _vectorQuestionMarks = new Vector((byte)'?'); + private static readonly Vector _vectorPercentages = new Vector((byte)'%'); + private readonly object _onStartingSync = new Object(); private readonly object _onCompletedSync = new Object(); protected readonly FrameRequestHeaders _requestHeaders = new FrameRequestHeaders(); @@ -704,7 +711,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http try { var begin = scan; - if (scan.Seek(' ') == -1) + if (scan.Seek(_vectorSpaces) == -1) { return false; } @@ -719,11 +726,11 @@ namespace Microsoft.AspNet.Server.Kestrel.Http begin = scan; var needDecode = false; - var chFound = scan.Seek(' ', '?', '%'); + var chFound = scan.Seek(_vectorSpaces, _vectorQuestionMarks, _vectorPercentages); if (chFound == '%') { needDecode = true; - chFound = scan.Seek(' ', '?'); + chFound = scan.Seek(_vectorSpaces, _vectorQuestionMarks); } var pathBegin = begin; @@ -733,7 +740,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http if (chFound == '?') { begin = scan; - if (scan.Seek(' ') != ' ') + if (scan.Seek(_vectorSpaces) != ' ') { return false; } @@ -742,7 +749,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http scan.Take(); begin = scan; - if (scan.Seek('\r') == -1) + if (scan.Seek(_vectorCRs) == -1) { return false; } @@ -836,7 +843,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http while (!scan.IsEnd) { var beginName = scan; - scan.Seek(':', '\r'); + scan.Seek(_vectorColons, _vectorCRs); var endName = scan; chFirst = scan.Take(); @@ -887,7 +894,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Http var wrapping = false; while (!scan.IsEnd) { - if (scan.Seek('\r') == -1) + if (scan.Seek(_vectorCRs) == -1) { // no "\r" in sight, burn used bytes and go back to await more data return false; diff --git a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.cs b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.cs index cab6fbe9ef..a10a2e23e7 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.cs @@ -168,16 +168,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure } } - public int Seek(int char0) + public int Seek(Vector byte0Vector) { if (IsDefault) { return -1; } - var byte0 = (byte)char0; - var ch0Vector = new Vector(byte0); - var block = _block; var index = _index; var array = block.Array; @@ -201,25 +198,28 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure if (following >= Vector.Count) { var data = new Vector(array, index); - var ch0Equals = Vector.Equals(data, ch0Vector); + var byte0Equals = Vector.Equals(data, byte0Vector); - if (ch0Equals.Equals(Vector.Zero)) + if (byte0Equals.Equals(Vector.Zero)) { index += Vector.Count; continue; } _block = block; - _index = index + FindFirstEqualByte(ch0Equals); - return char0; + _index = index + FindFirstEqualByte(byte0Equals); + return byte0Vector[0]; } + + var byte0 = byte0Vector[0]; + while (following > 0) { if (block.Array[index] == byte0) { _block = block; _index = index; - return char0; + return byte0; } following--; index++; @@ -228,18 +228,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure } } - public int Seek(int char0, int char1) + public int Seek(Vector byte0Vector, Vector byte1Vector) { if (IsDefault) { return -1; } - var byte0 = (byte)char0; - var byte1 = (byte)char1; - var ch0Vector = new Vector(byte0); - var ch1Vector = new Vector(byte1); - var block = _block; var index = _index; var array = block.Array; @@ -263,21 +258,21 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure if (following >= Vector.Count) { var data = new Vector(array, index); - var ch0Equals = Vector.Equals(data, ch0Vector); - var ch1Equals = Vector.Equals(data, ch1Vector); - int ch0Index = int.MaxValue; - int ch1Index = int.MaxValue; + var byte0Equals = Vector.Equals(data, byte0Vector); + var byte1Equals = Vector.Equals(data, byte1Vector); + int byte0Index = int.MaxValue; + int byte1Index = int.MaxValue; - if (!ch0Equals.Equals(Vector.Zero)) + if (!byte0Equals.Equals(Vector.Zero)) { - ch0Index = FindFirstEqualByte(ch0Equals); + byte0Index = FindFirstEqualByte(byte0Equals); } - if (!ch1Equals.Equals(Vector.Zero)) + if (!byte1Equals.Equals(Vector.Zero)) { - ch1Index = FindFirstEqualByte(ch1Equals); + byte1Index = FindFirstEqualByte(byte1Equals); } - if (ch0Index == int.MaxValue && ch1Index == int.MaxValue) + if (byte0Index == int.MaxValue && byte1Index == int.MaxValue) { index += Vector.Count; continue; @@ -285,15 +280,19 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure _block = block; - if (ch0Index < ch1Index) + if (byte0Index < byte1Index) { - _index = index + ch0Index; - return char0; + _index = index + byte0Index; + return byte0Vector[0]; } - _index = index + ch1Index; - return char1; + _index = index + byte1Index; + return byte1Vector[0]; } + + byte byte0 = byte0Vector[0]; + byte byte1 = byte1Vector[0]; + while (following > 0) { var byteIndex = block.Array[index]; @@ -301,13 +300,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure { _block = block; _index = index; - return char0; + return byte0; } else if (byteIndex == byte1) { _block = block; _index = index; - return char1; + return byte1; } following--; index++; @@ -316,20 +315,13 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure } } - public int Seek(int char0, int char1, int char2) + public int Seek(Vector byte0Vector, Vector byte1Vector, Vector byte2Vector) { if (IsDefault) { return -1; } - var byte0 = (byte)char0; - var byte1 = (byte)char1; - var byte2 = (byte)char2; - var ch0Vector = new Vector(byte0); - var ch1Vector = new Vector(byte1); - var ch2Vector = new Vector(byte2); - var block = _block; var index = _index; var array = block.Array; @@ -353,57 +345,57 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure if (following >= Vector.Count) { var data = new Vector(array, index); - var ch0Equals = Vector.Equals(data, ch0Vector); - var ch1Equals = Vector.Equals(data, ch1Vector); - var ch2Equals = Vector.Equals(data, ch2Vector); - int ch0Index = int.MaxValue; - int ch1Index = int.MaxValue; - int ch2Index = int.MaxValue; + var byte0Equals = Vector.Equals(data, byte0Vector); + var byte1Equals = Vector.Equals(data, byte1Vector); + var byte2Equals = Vector.Equals(data, byte2Vector); + int byte0Index = int.MaxValue; + int byte1Index = int.MaxValue; + int byte2Index = int.MaxValue; - if (!ch0Equals.Equals(Vector.Zero)) + if (!byte0Equals.Equals(Vector.Zero)) { - ch0Index = FindFirstEqualByte(ch0Equals); + byte0Index = FindFirstEqualByte(byte0Equals); } - if (!ch1Equals.Equals(Vector.Zero)) + if (!byte1Equals.Equals(Vector.Zero)) { - ch1Index = FindFirstEqualByte(ch1Equals); + byte1Index = FindFirstEqualByte(byte1Equals); } - if (!ch2Equals.Equals(Vector.Zero)) + if (!byte2Equals.Equals(Vector.Zero)) { - ch2Index = FindFirstEqualByte(ch2Equals); + byte2Index = FindFirstEqualByte(byte2Equals); } - if (ch0Index == int.MaxValue && ch1Index == int.MaxValue && ch2Index == int.MaxValue) + if (byte0Index == int.MaxValue && byte1Index == int.MaxValue && byte2Index == int.MaxValue) { index += Vector.Count; continue; } int toReturn, toMove; - if (ch0Index < ch1Index) + if (byte0Index < byte1Index) { - if (ch0Index < ch2Index) + if (byte0Index < byte2Index) { - toReturn = char0; - toMove = ch0Index; + toReturn = byte0Vector[0]; + toMove = byte0Index; } else { - toReturn = char2; - toMove = ch2Index; + toReturn = byte2Vector[0]; + toMove = byte2Index; } } else { - if (ch1Index < ch2Index) + if (byte1Index < byte2Index) { - toReturn = char1; - toMove = ch1Index; + toReturn = byte1Vector[0]; + toMove = byte1Index; } else { - toReturn = char2; - toMove = ch2Index; + toReturn = byte2Vector[0]; + toMove = byte2Index; } } @@ -412,6 +404,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure return toReturn; } + var byte0 = byte0Vector[0]; + var byte1 = byte1Vector[0]; + var byte2 = byte2Vector[0]; + while (following > 0) { var byteIndex = block.Array[index]; @@ -419,19 +415,19 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure { _block = block; _index = index; - return char0; + return byte0; } else if (byteIndex == byte1) { _block = block; _index = index; - return char1; + return byte1; } else if (byteIndex == byte2) { _block = block; _index = index; - return char2; + return byte2; } following--; index++; @@ -440,10 +436,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure } } - private static int FindFirstEqualByte(Vector chEquals) + private static int FindFirstEqualByte(Vector byteEquals) { // Quasi-tree search - var vector64 = Vector.AsVectorInt64(chEquals); + var vector64 = Vector.AsVectorInt64(byteEquals); for (var i = 0; i < Vector.Count; i++) { var longValue = vector64[i]; @@ -451,18 +447,18 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure var shift = i << 1; var offset = shift << 2; - var vector32 = Vector.AsVectorInt32(chEquals); + var vector32 = Vector.AsVectorInt32(byteEquals); if (vector32[shift] != 0) { - if (chEquals[offset] != 0) return offset; - if (chEquals[++offset] != 0) return offset; - if (chEquals[++offset] != 0) return offset; + if (byteEquals[offset] != 0) return offset; + if (byteEquals[++offset] != 0) return offset; + if (byteEquals[++offset] != 0) return offset; return ++offset; } offset += 4; - if (chEquals[offset] != 0) return offset; - if (chEquals[++offset] != 0) return offset; - if (chEquals[++offset] != 0) return offset; + if (byteEquals[offset] != 0) return offset; + if (byteEquals[++offset] != 0) return offset; + if (byteEquals[++offset] != 0) return offset; return ++offset; } throw new InvalidOperationException(); diff --git a/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolBlock2Tests.cs b/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolBlock2Tests.cs index 8618564004..c56f5311d5 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolBlock2Tests.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolBlock2Tests.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using Microsoft.AspNet.Server.Kestrel.Infrastructure; +using System.Numerics; using Xunit; namespace Microsoft.AspNet.Server.KestrelTests @@ -17,31 +18,36 @@ namespace Microsoft.AspNet.Server.KestrelTests { block.Array[block.End++] = ch; } + + var vectorMaxValues = new Vector(byte.MaxValue); + var iterator = block.GetIterator(); - foreach (var ch in Enumerable.Range(0, 256).Select(x => (char)x)) + foreach (var ch in Enumerable.Range(0, 256).Select(x => (byte)x)) { + var vectorCh = new Vector(ch); + var hit = iterator; - hit.Seek(ch); + hit.Seek(vectorCh); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(ch, byte.MaxValue); + hit.Seek(vectorCh, vectorMaxValues); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(byte.MaxValue, ch); + hit.Seek(vectorMaxValues, vectorCh); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(ch, byte.MaxValue, byte.MaxValue); + hit.Seek(vectorCh, vectorMaxValues, vectorMaxValues); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(byte.MaxValue, ch, byte.MaxValue); + hit.Seek(vectorMaxValues, vectorCh, vectorMaxValues); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(ch, byte.MaxValue, byte.MaxValue); + hit.Seek(vectorCh, vectorMaxValues, vectorMaxValues); Assert.Equal(ch, iterator.GetLength(hit)); } } @@ -69,31 +75,35 @@ namespace Microsoft.AspNet.Server.KestrelTests block3.Array[block3.End++] = ch; } + var vectorMaxValues = new Vector(byte.MaxValue); + var iterator = block1.GetIterator(); - foreach (var ch in Enumerable.Range(0, 256).Select(x => (char)x)) + foreach (var ch in Enumerable.Range(0, 256).Select(x => (byte)x)) { + var vectorCh = new Vector(ch); + var hit = iterator; - hit.Seek(ch); + hit.Seek(vectorCh); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(ch, byte.MaxValue); + hit.Seek(vectorCh, vectorMaxValues); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(byte.MaxValue, ch); + hit.Seek(vectorMaxValues, vectorCh); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(ch, byte.MaxValue, byte.MaxValue); + hit.Seek(vectorCh, vectorMaxValues, vectorMaxValues); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(byte.MaxValue, ch, byte.MaxValue); + hit.Seek(vectorMaxValues, vectorCh, vectorMaxValues); Assert.Equal(ch, iterator.GetLength(hit)); hit = iterator; - hit.Seek(ch, byte.MaxValue, byte.MaxValue); + hit.Seek(vectorMaxValues, vectorMaxValues, vectorCh); Assert.Equal(ch, iterator.GetLength(hit)); } } diff --git a/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolIterator2Tests.cs b/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolIterator2Tests.cs index 7368bf08d9..67c4a7e6ae 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolIterator2Tests.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolIterator2Tests.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using Microsoft.AspNet.Server.Kestrel.Infrastructure; +using System.Numerics; using Xunit; namespace Microsoft.AspNet.Server.KestrelTests @@ -52,15 +53,15 @@ namespace Microsoft.AspNet.Server.KestrelTests int found = -1; if (searchFor.Length == 1) { - found = begin.Seek(searchFor[0]); + found = begin.Seek(new Vector((byte)searchFor[0])); } else if (searchFor.Length == 2) { - found = begin.Seek(searchFor[0], searchFor[1]); + found = begin.Seek(new Vector((byte)searchFor[0]), new Vector((byte)searchFor[1])); } else if (searchFor.Length == 3) { - found = begin.Seek(searchFor[0], searchFor[1], searchFor[2]); + found = begin.Seek(new Vector((byte)searchFor[0]), new Vector((byte)searchFor[1]), new Vector((byte)searchFor[2])); } else { @@ -217,7 +218,7 @@ namespace Microsoft.AspNet.Server.KestrelTests block.End += chars.Length; var begin = block.GetIterator(); var end = begin; - end.Seek(endChar); + end.Seek(new Vector((byte)endChar)); string knownString; // Act