diff --git a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.cs b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.cs index c6326465f9..37e18389ff 100644 --- a/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.cs +++ b/src/Microsoft.AspNet.Server.Kestrel/Infrastructure/MemoryPoolIterator2.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure { public struct MemoryPoolIterator2 { - private readonly static int _vectorSpan = Vector.Count; + private static readonly int _vectorSpan = Vector.Count; private MemoryPoolBlock2 _block; private int _index; @@ -203,7 +203,7 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure long nextLong; fixed (byte* ptr = &_block.Next.Array[_block.Next.Start]) { - nextLong = *(long*)(ptr ); + nextLong = *(long*)(ptr); } return (blockLong >> (sizeof(long) - blockBytes) * 8) | (nextLong << (sizeof(long) - nextBytes) * 8); @@ -537,7 +537,37 @@ namespace Microsoft.AspNet.Server.Kestrel.Infrastructure } } - private static int FindFirstEqualByte(ref Vector byteEquals) + /// + /// Find first byte + /// + /// + /// The first index of the result vector + /// byteEquals = 0 + internal static int FindFirstEqualByte(ref Vector byteEquals) + { + if (!BitConverter.IsLittleEndian) return FindFirstEqualByteSlow(ref byteEquals); + + // Quasi-tree search + var vector64 = Vector.AsVectorInt64(byteEquals); + for (var i = 0; i < Vector.Count; i++) + { + var longValue = vector64[i]; + if (longValue == 0) continue; + + return (i << 3) + + ((longValue & 0x00000000ffffffff) > 0 + ? (longValue & 0x000000000000ffff) > 0 + ? (longValue & 0x00000000000000ff) > 0 ? 0 : 1 + : (longValue & 0x0000000000ff0000) > 0 ? 2 : 3 + : (longValue & 0x0000ffff00000000) > 0 + ? (longValue & 0x000000ff00000000) > 0 ? 4 : 5 + : (longValue & 0x00ff000000000000) > 0 ? 6 : 7); + } + throw new InvalidOperationException(); + } + + // Internal for testing + internal static int FindFirstEqualByteSlow(ref Vector byteEquals) { // Quasi-tree search var vector64 = Vector.AsVectorInt64(byteEquals); diff --git a/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolIterator2Tests.cs b/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolIterator2Tests.cs index 2faee6f55b..627cd0dfa2 100644 --- a/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolIterator2Tests.cs +++ b/test/Microsoft.AspNet.Server.KestrelTests/MemoryPoolIterator2Tests.cs @@ -20,6 +20,34 @@ namespace Microsoft.AspNet.Server.KestrelTests _pool.Dispose(); } + [Fact] + public void FindFirstByte() + { + var bytes = new byte[] { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + for (int i = 0; i < Vector.Count; i++) + { + Vector vector = new Vector(bytes); + Assert.Equal(i, MemoryPoolIterator2.FindFirstEqualByte(ref vector)); + bytes[i] = 0; + } + } + + [Fact] + public void _FindFirstByte() + { + var bytes = new byte[] { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + for (int i = 0; i < Vector.Count; i++) + { + Vector vector = new Vector(bytes); + Assert.Equal(i, MemoryPoolIterator2.FindFirstEqualByteSlow(ref vector)); + bytes[i] = 0; + } + } + [Theory] [InlineData("a", "a", 'a', 0)] [InlineData("ab", "a", 'a', 0)]