diff options
author | Alexander Radchenko <radchenkosasha@gmail.com> | 2018-04-10 00:48:09 +0300 |
---|---|---|
committer | Ahson Khan <ahkha@microsoft.com> | 2018-04-10 00:48:09 +0300 |
commit | 622564b3ca5fc622a2fef5c42d301a7173b6054f (patch) | |
tree | 48516f34ba179fa9fbe261ecc05b9e78f92abdd5 /src | |
parent | b606666632275398d56f4de574e46550e6e098d7 (diff) |
Created performance tests for ReadOnlySequence (#28927)
* Created performance tests for ReadOnlySequence
* Review issues
* Removed InnerCount * 10
Diffstat (limited to 'src')
6 files changed, 2116 insertions, 0 deletions
diff --git a/src/System.Memory/tests/Performance/Perf.ReadOnlySequence.Enumerator.cs b/src/System.Memory/tests/Performance/Perf.ReadOnlySequence.Enumerator.cs new file mode 100644 index 0000000000..4d6d45c188 --- /dev/null +++ b/src/System.Memory/tests/Performance/Perf.ReadOnlySequence.Enumerator.cs @@ -0,0 +1,301 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Memory.Tests; +using System.MemoryTests; +using Microsoft.Xunit.Performance; +using Xunit; + +namespace System.Buffers.Tests +{ + public class Perf_ReadOnlySequence_Enumerator + { + private const int InnerCount = 100_000; + volatile static int _volatileInt = 0; + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Array(int bufSize, int bufOffset) + { + var buffer = new ReadOnlySequence<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + foreach(ReadOnlyMemory<byte> memory in buffer) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Memory(int bufSize, int bufOffset) + { + var manager = new CustomMemoryForTest<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<byte>(manager.Memory); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + foreach(ReadOnlyMemory<byte> memory in buffer) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_SingleSegment(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment1, bufSize - bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + foreach(ReadOnlyMemory<byte> memory in buffer) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount / 10)] + [InlineData(10_000, 100)] + private static void Byte_MultiSegment(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize / 10]); + BufferSegment<byte> segment2 = segment1; + for (int j = 0; j < 10; j++) + segment2 = segment2.Append(new byte[bufSize / 10]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment2, bufSize / 10 - bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + foreach(ReadOnlyMemory<byte> memory in buffer) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + private static void Byte_Empty() + { + ReadOnlySequence<byte> buffer = ReadOnlySequence<byte>.Empty; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + foreach(ReadOnlyMemory<byte> memory in buffer) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + private static void Byte_Default() + { + ReadOnlySequence<byte> buffer = default; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + foreach(ReadOnlyMemory<byte> memory in buffer) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Char_Array(int bufSize, int bufOffset) + { + var buffer = new ReadOnlySequence<char>(new char[bufSize], bufOffset, bufSize - 2 * bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + foreach(ReadOnlyMemory<char> memory in buffer) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Char_Memory(int bufSize, int bufOffset) + { + var manager = new CustomMemoryForTest<char>(new char[bufSize], bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<char>(manager.Memory); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + foreach(ReadOnlyMemory<char> memory in buffer) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Char_SingleSegment(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<char>(new char[bufSize]); + var buffer = new ReadOnlySequence<char>(segment1, bufOffset, segment1, bufSize - bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + foreach(ReadOnlyMemory<char> memory in buffer) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount / 10)] + [InlineData(10_000, 100)] + private static void Char_MultiSegment(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<char>(new char[bufSize / 10]); + BufferSegment<char> segment2 = segment1; + for (int j = 0; j < 10; j++) + segment2 = segment2.Append(new char[bufSize / 10]); + var buffer = new ReadOnlySequence<char>(segment1, bufOffset, segment2, bufSize / 10 - bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + foreach(ReadOnlyMemory<char> memory in buffer) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void String(int bufSize, int bufOffset) + { + ReadOnlyMemory<char> strMemory = new string('a', bufSize).AsMemory(); + strMemory = strMemory.Slice(bufOffset, bufSize - bufOffset); + var buffer = new ReadOnlySequence<char>(strMemory); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + foreach(ReadOnlyMemory<char> memory in buffer) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + private static void Char_Empty() + { + ReadOnlySequence<char> buffer = ReadOnlySequence<char>.Empty; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + foreach(ReadOnlyMemory<char> memory in buffer) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + private static void Char_Default() + { + ReadOnlySequence<char> buffer = default; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + foreach(ReadOnlyMemory<char> memory in buffer) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + } +} diff --git a/src/System.Memory/tests/Performance/Perf.ReadOnlySequence.First.cs b/src/System.Memory/tests/Performance/Perf.ReadOnlySequence.First.cs new file mode 100644 index 0000000000..3d5b69e1bf --- /dev/null +++ b/src/System.Memory/tests/Performance/Perf.ReadOnlySequence.First.cs @@ -0,0 +1,302 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Memory.Tests; +using System.MemoryTests; +using Microsoft.Xunit.Performance; +using Xunit; + +namespace System.Buffers.Tests +{ + public class Perf_ReadOnlySequence_First + { + private const int InnerCount = 100_000; + volatile static int _volatileInt = 0; + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Array(int bufSize, int bufOffset) + { + var buffer = new ReadOnlySequence<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlyMemory<byte> first = buffer.First; + localInt ^= first.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Memory(int bufSize, int bufOffset) + { + var manager = new CustomMemoryForTest<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<byte>(manager.Memory); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlyMemory<byte> first = buffer.First; + localInt ^= first.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_SingleSegment(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment1, bufSize - bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlyMemory<byte> first = buffer.First; + localInt ^= first.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_MultiSegment(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize / 10]); + BufferSegment<byte> segment2 = segment1; + for (int j = 0; j < 10; j++) + segment2 = segment2.Append(new byte[bufSize / 10]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment2, bufSize / 10 - bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlyMemory<byte> first = buffer.First; + localInt ^= first.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + private static void Byte_Empty() + { + ReadOnlySequence<byte> buffer = ReadOnlySequence<byte>.Empty; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlyMemory<byte> first = buffer.First; + localInt ^= first.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + private static void Byte_Default() + { + ReadOnlySequence<byte> buffer = default; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlyMemory<byte> first = buffer.First; + localInt ^= first.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Char_Array(int bufSize, int bufOffset) + { + var buffer = new ReadOnlySequence<char>(new char[bufSize], bufOffset, bufSize - 2 * bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlyMemory<char> first = buffer.First; + localInt ^= first.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Char_Memory(int bufSize, int bufOffset) + { + var manager = new CustomMemoryForTest<char>(new char[bufSize], bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<char>(manager.Memory); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlyMemory<char> first = buffer.First; + localInt ^= first.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Char_SingleSegment(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<char>(new char[bufSize]); + var buffer = new ReadOnlySequence<char>(segment1, bufOffset, segment1, bufSize - bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlyMemory<char> first = buffer.First; + localInt ^= first.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Char_MultiSegment(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<char>(new char[bufSize / 10]); + BufferSegment<char> segment2 = segment1; + for (int j = 0; j < 10; j++) + segment2 = segment2.Append(new char[bufSize / 10]); + + var buffer = new ReadOnlySequence<char>(segment1, bufOffset, segment2, bufSize / 10 - bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlyMemory<char> first = buffer.First; + localInt ^= first.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void String(int bufSize, int bufOffset) + { + ReadOnlyMemory<char> memory = new string('a', bufSize).AsMemory(); + memory = memory.Slice(bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<char>(memory); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlyMemory<char> first = buffer.First; + localInt ^= first.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + private static void Char_Empty() + { + ReadOnlySequence<char> buffer = ReadOnlySequence<char>.Empty; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlyMemory<char> first = buffer.First; + localInt ^= first.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + private static void Char_Default() + { + ReadOnlySequence<char> buffer = default; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlyMemory<char> first = buffer.First; + localInt ^= first.Length; + } + } + _volatileInt = localInt; + } + } + + } +} diff --git a/src/System.Memory/tests/Performance/Perf.ReadOnlySequence.GetPosition.cs b/src/System.Memory/tests/Performance/Perf.ReadOnlySequence.GetPosition.cs new file mode 100644 index 0000000000..5a4c6721c2 --- /dev/null +++ b/src/System.Memory/tests/Performance/Perf.ReadOnlySequence.GetPosition.cs @@ -0,0 +1,215 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Memory.Tests; +using Microsoft.Xunit.Performance; +using Xunit; + +namespace System.Buffers.Tests +{ + public class Rerf_ReadOnlySequence_GetPosition + { + private const int InnerCount = 10_000; + volatile static int _volatileInt = 0; + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Array(int bufSize, int bufOffset) + { + var buffer = new ReadOnlySequence<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + int offset = (int)buffer.Length / 10; + SequencePosition end = buffer.GetPosition(0, buffer.End); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition pos = buffer.Start; + while (pos != end) + { + pos = buffer.GetPosition(offset, pos); + localInt ^= pos.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_MultiSegment(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize / 10]); + BufferSegment<byte> segment2 = segment1; + for (int j = 0; j < 10; j++) + segment2 = segment2.Append(new byte[bufSize / 10]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment2, bufSize / 10 - bufOffset); + int offset = (int)buffer.Length / 10; + SequencePosition end = buffer.GetPosition(0, buffer.End); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition pos = buffer.Start; + while (pos != end) + { + pos = buffer.GetPosition(offset, pos); + localInt ^= pos.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount * 10)] + private static void Byte_Empty() + { + ReadOnlySequence<byte> buffer = ReadOnlySequence<byte>.Empty; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition pos = buffer.GetPosition(0); + localInt ^= pos.GetInteger(); + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount * 10)] + private static void Byte_Default() + { + ReadOnlySequence<byte> buffer = default; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition pos = buffer.GetPosition(0); + localInt ^= pos.GetInteger(); + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Char_MultiSegment(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<char>(new char[bufSize / 10]); + BufferSegment<char> segment2 = segment1; + for (int j = 0; j < 10; j++) + segment2 = segment2.Append(new char[bufSize / 10]); + var buffer = new ReadOnlySequence<char>(segment1, bufOffset, segment2, bufSize / 10 - bufOffset); + int offset = (int)buffer.Length / 10; + SequencePosition end = buffer.GetPosition(0, buffer.End); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition pos = buffer.Start; + while (pos != end) + { + pos = buffer.GetPosition(offset, pos); + localInt ^= pos.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void String(int bufSize, int bufOffset) + { + ReadOnlyMemory<char> memory = new string('a', bufSize).AsMemory(); + memory = memory.Slice(bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<char>(memory); + int offset = (int)buffer.Length / 10; + SequencePosition end = buffer.GetPosition(0, buffer.End); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition pos = buffer.Start; + while (pos != end) + { + pos = buffer.GetPosition(offset, pos); + localInt ^= pos.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount * 10)] + private static void Char_Empty() + { + ReadOnlySequence<char> buffer = ReadOnlySequence<char>.Empty; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition p = buffer.GetPosition(0); + localInt ^= p.GetInteger(); + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount * 10)] + private static void Char_Default() + { + ReadOnlySequence<char> buffer = default; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition p = buffer.GetPosition(0); + localInt ^= p.GetInteger(); + } + } + _volatileInt = localInt; + } + } + + } +} diff --git a/src/System.Memory/tests/Performance/Perf.ReadOnlySequence.Slice.cs b/src/System.Memory/tests/Performance/Perf.ReadOnlySequence.Slice.cs new file mode 100644 index 0000000000..6148c8a7cb --- /dev/null +++ b/src/System.Memory/tests/Performance/Perf.ReadOnlySequence.Slice.cs @@ -0,0 +1,973 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Memory.Tests; +using System.MemoryTests; +using Microsoft.Xunit.Performance; +using Xunit; + +namespace System.Buffers.Tests +{ + public class Perf_ReadOnlySequence_Slice + { + private const int InnerCount = 10_000; + volatile static int _volatileInt = 0; + + #region Byte_Array + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Array_Long(int bufSize, int bufOffset) + { + var buffer = new ReadOnlySequence<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + long offset = buffer.Length / 10; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + while (sliceLen > 0) + { + sliceLen -= offset; + sliced = sliced.Slice(offset); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Array_LongLong(int bufSize, int bufOffset) + { + var buffer = new ReadOnlySequence<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + sliced = sliced.Slice(offset, sliceLen); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Array_LongPos(int bufSize, int bufOffset) + { + var buffer = new ReadOnlySequence<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + SequencePosition end = sliced.GetPosition(0, sliced.End); + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + end = new SequencePosition(end.GetObject(), end.GetInteger() - (int)offset); + sliced = sliced.Slice(offset, end); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Array_Pos(int bufSize, int bufOffset) + { + var buffer = new ReadOnlySequence<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + long offset = buffer.Length / 10; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + SequencePosition start = sliced.GetPosition(0); + while (sliceLen > 0) + { + sliceLen -= offset; + start = new SequencePosition(start.GetObject(), start.GetInteger() + (int)offset); + sliced = sliced.Slice(start); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Array_PosLong(int bufSize, int bufOffset) + { + var buffer = new ReadOnlySequence<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + SequencePosition start = sliced.GetPosition(0); + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + start = new SequencePosition(start.GetObject(), start.GetInteger() + (int)offset); + sliced = sliced.Slice(start, sliceLen); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Array_PosPos(int bufSize, int bufOffset) + { + var buffer = new ReadOnlySequence<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + SequencePosition start = sliced.GetPosition(0); + SequencePosition end = sliced.GetPosition(0, sliced.End); + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + start = new SequencePosition(start.GetObject(), start.GetInteger() + (int)offset); + end = new SequencePosition(end.GetObject(), end.GetInteger() - (int)offset); + sliced = sliced.Slice(start, end); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + #endregion + + #region Byte_Memory + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Memory_Long(int bufSize, int bufOffset) + { + var manager = new CustomMemoryForTest<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<byte>(manager.Memory); + long offset = buffer.Length / 10; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + while (sliceLen > 0) + { + sliceLen -= offset; + sliced = sliced.Slice(offset); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Memory_LongLong(int bufSize, int bufOffset) + { + var manager = new CustomMemoryForTest<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<byte>(manager.Memory); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + sliced = sliced.Slice(offset, sliceLen); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Memory_LongPos(int bufSize, int bufOffset) + { + var manager = new CustomMemoryForTest<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<byte>(manager.Memory); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + SequencePosition end = sliced.GetPosition(0, sliced.End); + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + end = new SequencePosition(end.GetObject(), end.GetInteger() - (int)offset); + sliced = sliced.Slice(offset, end); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Memory_Pos(int bufSize, int bufOffset) + { + var manager = new CustomMemoryForTest<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<byte>(manager.Memory); + long offset = buffer.Length / 10; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + SequencePosition start = sliced.GetPosition(0); + while (sliceLen > 0) + { + sliceLen -= offset; + start = new SequencePosition(start.GetObject(), start.GetInteger() + (int)offset); + sliced = sliced.Slice(start); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Memory_PosLong(int bufSize, int bufOffset) + { + var manager = new CustomMemoryForTest<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<byte>(manager.Memory); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + SequencePosition start = sliced.GetPosition(0); + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + start = new SequencePosition(start.GetObject(), start.GetInteger() + (int)offset); + sliced = sliced.Slice(start, sliceLen); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Memory_PosPos(int bufSize, int bufOffset) + { + var manager = new CustomMemoryForTest<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<byte>(manager.Memory); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + SequencePosition start = sliced.GetPosition(0); + SequencePosition end = sliced.GetPosition(0, sliced.End); + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + start = new SequencePosition(start.GetObject(), start.GetInteger() + (int)offset); + end = new SequencePosition(end.GetObject(), end.GetInteger() - (int)offset); + sliced = sliced.Slice(start, end); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + #endregion + + #region Byte_SingleSegment + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_SingleSegment_Long(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment1, bufSize - bufOffset); + long offset = buffer.Length / 10; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + while (sliceLen > 0) + { + sliceLen -= offset; + sliced = sliced.Slice(offset); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_SingleSegment_LongLong(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment1, bufSize - bufOffset); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + sliced = sliced.Slice(offset, sliceLen); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_SingleSegment_LongPos(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment1, bufSize - bufOffset); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + SequencePosition end = sliced.GetPosition(0, sliced.End); + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + end = new SequencePosition(end.GetObject(), end.GetInteger() - (int)offset); + sliced = sliced.Slice(offset, end); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_SingleSegment_Pos(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment1, bufSize - bufOffset); + long offset = buffer.Length / 10; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + SequencePosition start = sliced.GetPosition(0); + while (sliceLen > 0) + { + sliceLen -= offset; + start = new SequencePosition(start.GetObject(), start.GetInteger() + (int)offset); + sliced = sliced.Slice(start); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_SingleSegment_PosLong(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment1, bufSize - bufOffset); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + SequencePosition start = sliced.GetPosition(0); + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + start = new SequencePosition(start.GetObject(), start.GetInteger() + (int)offset); + sliced = sliced.Slice(start, sliceLen); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_SingleSegment_PosPos(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment1, bufSize - bufOffset); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + SequencePosition start = sliced.GetPosition(0); + SequencePosition end = sliced.GetPosition(0, sliced.End); + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + start = new SequencePosition(start.GetObject(), start.GetInteger() + (int)offset); + end = new SequencePosition(end.GetObject(), end.GetInteger() - (int)offset); + sliced = sliced.Slice(start, end); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + #endregion + + #region Byte_MultiSegment + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_MultiSegment_Long(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize / 10]); + BufferSegment<byte> segment2 = segment1; + for (int j = 0; j < 10; j++) + segment2 = segment2.Append(new byte[bufSize / 10]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment2, bufSize / 10 - bufOffset); + long offset = buffer.Length / 10; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + while (sliceLen > 0) + { + sliceLen -= offset; + sliced = sliced.Slice(offset); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_MultiSegment_LongLong(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize / 10]); + BufferSegment<byte> segment2 = segment1; + for (int j = 0; j < 10; j++) + segment2 = segment2.Append(new byte[bufSize / 10]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment2, bufSize / 10 - bufOffset); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + sliced = sliced.Slice(offset, sliceLen); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_MultiSegment_LongPos(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize / 10]); + BufferSegment<byte> segment2 = segment1; + for (int j = 0; j < 10; j++) + segment2 = segment2.Append(new byte[bufSize / 10]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment2, bufSize / 10 - bufOffset); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + while (sliceLen > 0) + { + sliceLen -= offset; + SequencePosition end = sliced.GetPosition(sliceLen); + sliceLen -= offset; + sliced = sliced.Slice(offset, end); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_MultiSegment_Pos(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize / 10]); + BufferSegment<byte> segment2 = segment1; + for (int j = 0; j < 10; j++) + segment2 = segment2.Append(new byte[bufSize / 10]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment2, bufSize / 10 - bufOffset); + long offset = buffer.Length / 10; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + while (sliceLen > 0) + { + sliceLen -= offset; + SequencePosition start = sliced.GetPosition(offset); + sliced = sliced.Slice(start); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_MultiSegment_PosLong(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize / 10]); + BufferSegment<byte> segment2 = segment1; + for (int j = 0; j < 10; j++) + segment2 = segment2.Append(new byte[bufSize / 10]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment2, bufSize / 10 - bufOffset); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + SequencePosition start = sliced.GetPosition(offset); + sliced = sliced.Slice(start, sliceLen); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_MultiSegment_PosPos(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize / 10]); + BufferSegment<byte> segment2 = segment1; + for (int j = 0; j < 10; j++) + segment2 = segment2.Append(new byte[bufSize / 10]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment2, bufSize / 10 - bufOffset); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<byte> sliced = buffer; + long sliceLen = sliced.Length; + while (sliceLen > 0) + { + sliceLen -= offset; + SequencePosition end = sliced.GetPosition(sliceLen); + SequencePosition start = sliced.GetPosition(offset); + sliceLen -= offset; + sliced = sliced.Slice(start, end); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + #endregion + + #region String + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void String_Long(int bufSize, int bufOffset) + { + ReadOnlyMemory<char> memory = new string('a', bufSize).AsMemory(); + memory = memory.Slice(bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<char>(memory); + long offset = buffer.Length / 10; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<char> sliced = buffer; + long sliceLen = sliced.Length; + while (sliceLen > 0) + { + sliceLen -= offset; + sliced = sliced.Slice(offset); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void String_LongLong(int bufSize, int bufOffset) + { + ReadOnlyMemory<char> memory = new string('a', bufSize).AsMemory(); + memory = memory.Slice(bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<char>(memory); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<char> sliced = buffer; + long sliceLen = sliced.Length; + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + sliced = sliced.Slice(offset, sliceLen); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void String_LongPos(int bufSize, int bufOffset) + { + ReadOnlyMemory<char> memory = new string('a', bufSize).AsMemory(); + memory = memory.Slice(bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<char>(memory); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<char> sliced = buffer; + long sliceLen = sliced.Length; + SequencePosition end = sliced.GetPosition(0, sliced.End); + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + end = new SequencePosition(end.GetObject(), end.GetInteger() - (int)offset); + sliced = sliced.Slice(offset, end); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void String_Pos(int bufSize, int bufOffset) + { + ReadOnlyMemory<char> memory = new string('a', bufSize).AsMemory(); + memory = memory.Slice(bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<char>(memory); + long offset = buffer.Length / 10; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<char> sliced = buffer; + long sliceLen = sliced.Length; + SequencePosition start = sliced.GetPosition(0); + while (sliceLen > 0) + { + sliceLen -= offset; + start = new SequencePosition(start.GetObject(), start.GetInteger() + (int)offset); + sliced = sliced.Slice(start); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void String_PosLong(int bufSize, int bufOffset) + { + ReadOnlyMemory<char> memory = new string('a', bufSize).AsMemory(); + memory = memory.Slice(bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<char>(memory); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<char> sliced = buffer; + long sliceLen = sliced.Length; + SequencePosition start = sliced.GetPosition(0); + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + start = new SequencePosition(start.GetObject(), start.GetInteger() + (int)offset); + sliced = sliced.Slice(start, sliceLen); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void String_PosPos(int bufSize, int bufOffset) + { + ReadOnlyMemory<char> memory = new string('a', bufSize).AsMemory(); + memory = memory.Slice(bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<char>(memory); + long offset = buffer.Length / 20; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySequence<char> sliced = buffer; + long sliceLen = sliced.Length; + SequencePosition start = sliced.GetPosition(0); + SequencePosition end = sliced.GetPosition(0, sliced.End); + while (sliceLen > 0) + { + sliceLen -= 2 * offset; + start = new SequencePosition(start.GetObject(), start.GetInteger() + (int)offset); + end = new SequencePosition(end.GetObject(), end.GetInteger() - (int)offset); + sliced = sliced.Slice(start, end); + localInt ^= sliced.Start.GetInteger(); + } + } + } + _volatileInt = localInt; + } + } + + #endregion + + } +} diff --git a/src/System.Memory/tests/Performance/Perf.ReadOnlySequence.TryGet.cs b/src/System.Memory/tests/Performance/Perf.ReadOnlySequence.TryGet.cs new file mode 100644 index 0000000000..2d761181f9 --- /dev/null +++ b/src/System.Memory/tests/Performance/Perf.ReadOnlySequence.TryGet.cs @@ -0,0 +1,314 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Memory.Tests; +using System.MemoryTests; +using Microsoft.Xunit.Performance; +using Xunit; + +namespace System.Buffers.Tests +{ + public class Perf_ReadOnlySequence_TryGet + { + private const int InnerCount = 100_000; + volatile static int _volatileInt = 0; + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Array(int bufSize, int bufOffset) + { + var buffer = new ReadOnlySequence<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition p = buffer.Start; + while (buffer.TryGet(ref p, out ReadOnlyMemory<byte> memory)) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_Memory(int bufSize, int bufOffset) + { + var manager = new CustomMemoryForTest<byte>(new byte[bufSize], bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<byte>(manager.Memory); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition p = buffer.Start; + while (buffer.TryGet(ref p, out ReadOnlyMemory<byte> memory)) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Byte_SingleSegment(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment1, bufSize - bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition p = buffer.Start; + while (buffer.TryGet(ref p, out ReadOnlyMemory<byte> memory)) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount / 10)] + [InlineData(10_000, 100)] + private static void Byte_MultiSegment(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<byte>(new byte[bufSize / 10]); + BufferSegment<byte> segment2 = segment1; + for (int j = 0; j < 10; j++) + segment2 = segment2.Append(new byte[bufSize / 10]); + var buffer = new ReadOnlySequence<byte>(segment1, bufOffset, segment2, bufSize / 10 - bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition p = buffer.Start; + while (buffer.TryGet(ref p, out ReadOnlyMemory<byte> memory)) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + private static void Byte_Empty() + { + ReadOnlySequence<byte> buffer = ReadOnlySequence<byte>.Empty; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition p = buffer.Start; + while (buffer.TryGet(ref p, out ReadOnlyMemory<byte> memory)) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + private static void Byte_Default() + { + ReadOnlySequence<byte> buffer = default; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition p = buffer.Start; + while (buffer.TryGet(ref p, out ReadOnlyMemory<byte> memory)) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Char_Array(int bufSize, int bufOffset) + { + var buffer = new ReadOnlySequence<char>(new char[bufSize], bufOffset, bufSize - 2 * bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition p = buffer.Start; + while (buffer.TryGet(ref p, out ReadOnlyMemory<char> memory)) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Char_Memory(int bufSize, int bufOffset) + { + var manager = new CustomMemoryForTest<char>(new char[bufSize], bufOffset, bufSize - 2 * bufOffset); + var buffer = new ReadOnlySequence<char>(manager.Memory); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition p = buffer.Start; + while (buffer.TryGet(ref p, out ReadOnlyMemory<char> memory)) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void Char_SingleSegment(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<char>(new char[bufSize]); + var buffer = new ReadOnlySequence<char>(segment1, bufOffset, segment1, bufSize - bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition p = buffer.Start; + while (buffer.TryGet(ref p, out ReadOnlyMemory<char> memory)) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount / 10)] + [InlineData(10_000, 100)] + private static void Char_MultiSegment(int bufSize, int bufOffset) + { + var segment1 = new BufferSegment<char>(new char[bufSize / 10]); + BufferSegment<char> segment2 = segment1; + for (int j = 0; j < 10; j++) + segment2 = segment2.Append(new char[bufSize / 10]); + var buffer = new ReadOnlySequence<char>(segment1, bufOffset, segment2, bufSize / 10 - bufOffset); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition p = buffer.Start; + while (buffer.TryGet(ref p, out ReadOnlyMemory<char> memory)) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + [InlineData(10_000, 100)] + private static void String(int bufSize, int bufOffset) + { + ReadOnlyMemory<char> strMemory = new string('a', bufSize).AsMemory(); + strMemory = strMemory.Slice(bufOffset, bufSize - bufOffset); + var buffer = new ReadOnlySequence<char>(strMemory); + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition p = buffer.Start; + while (buffer.TryGet(ref p, out ReadOnlyMemory<char> memory)) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + private static void Char_Empty() + { + ReadOnlySequence<char> buffer = ReadOnlySequence<char>.Empty; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition p = buffer.Start; + while (buffer.TryGet(ref p, out ReadOnlyMemory<char> memory)) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + [Benchmark(InnerIterationCount = InnerCount)] + private static void Char_Default() + { + ReadOnlySequence<char> buffer = default; + + foreach (BenchmarkIteration iteration in Benchmark.Iterations) + { + int localInt = 0; + using (iteration.StartMeasurement()) + { + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + SequencePosition p = buffer.Start; + while (buffer.TryGet(ref p, out ReadOnlyMemory<char> memory)) + localInt ^= memory.Length; + } + } + _volatileInt = localInt; + } + } + + } +} diff --git a/src/System.Memory/tests/Performance/System.Memory.Performance.Tests.csproj b/src/System.Memory/tests/Performance/System.Memory.Performance.Tests.csproj index 692fb4e62b..edb6ffe73c 100644 --- a/src/System.Memory/tests/Performance/System.Memory.Performance.Tests.csproj +++ b/src/System.Memory/tests/Performance/System.Memory.Performance.Tests.csproj @@ -10,6 +10,11 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netcoreapp-Release|AnyCPU'" /> <ItemGroup> <Compile Include="Perf.Base64EncodeDecode.cs" /> + <Compile Include="Perf.ReadOnlySequence.Enumerator.cs" /> + <Compile Include="Perf.ReadOnlySequence.First.cs" /> + <Compile Include="Perf.ReadOnlySequence.GetPosition.cs" /> + <Compile Include="Perf.ReadOnlySequence.Slice.cs" /> + <Compile Include="Perf.ReadOnlySequence.TryGet.cs" /> <Compile Include="Perf.Span.BinaryReadAndWrite.cs" /> <Compile Include="Perf.Span.BinarySearch.cs" /> <Compile Include="Perf.Span.Clear.cs" /> @@ -26,6 +31,12 @@ <Compile Include="$(CommonTestPath)\System\PerfUtils.cs"> <Link>Common\System\PerfUtils.cs</Link> </Compile> + <Compile Include="..\Memory\CustomMemoryForTest.cs"> + <Link>Common\System\MemoryTests\CustomMemoryForTest.cs</Link> + </Compile> + <Compile Include="..\ReadOnlyBuffer\BufferSegment.cs"> + <Link>Common\System\Memory\Tests\BufferSegment.cs</Link> + </Compile> </ItemGroup> <ItemGroup> <ProjectReference Include="$(CommonPath)\..\perf\PerfRunner\PerfRunner.csproj"> |