From 1bf3bbb44397875e94ae95b8527fd1928b5373fe Mon Sep 17 00:00:00 2001 From: Ahson Ahmed Khan Date: Wed, 1 Mar 2017 20:16:40 -0800 Subject: Adding Span API perf tests for comparison with arrays and to monitor progress (#9790) * wip * Adding Span API perf tests for comparison with arrays and to monitor progress * Reducing iteration count so tests finish in < 2 minutes * Reducing the number of test cases * Commenting out ref DangerousGetPinnableReference test * Updated csproj to use latest compiler * Tuning test cases and runtime --- .../JIT/Performance/CodeQuality/Span/SpanBench.cs | 1157 ++++++++++++++------ .../Performance/CodeQuality/Span/SpanBench.csproj | 2 + 2 files changed, 843 insertions(+), 316 deletions(-) (limited to 'tests/src/JIT/Performance') diff --git a/tests/src/JIT/Performance/CodeQuality/Span/SpanBench.cs b/tests/src/JIT/Performance/CodeQuality/Span/SpanBench.cs index 7ec2a4a088..b0358d2268 100644 --- a/tests/src/JIT/Performance/CodeQuality/Span/SpanBench.cs +++ b/tests/src/JIT/Performance/CodeQuality/Span/SpanBench.cs @@ -2,467 +2,992 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Xunit.Performance; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; using Xunit; +using Microsoft.Xunit.Performance; [assembly: OptimizeForBenchmarks] [assembly: MeasureInstructionsRetired] -class Tests +namespace Span { + public class SpanBench + { #if DEBUG - const int Iterations = 1; + const int BubbleSortIterations = 1; + const int QuickSortIterations = 1; + const int FillAllIterations = 1; + const int BaseIterations = 1; #else - const int Iterations = 10000; + const int BubbleSortIterations = 100; + const int QuickSortIterations = 1000; + const int FillAllIterations = 100000; + const int BaseIterations = 10000000; #endif - const int Size = 1024; + const int Size = 1024; + // Helpers + #region Helpers + [StructLayout(LayoutKind.Sequential)] + private sealed class TestClass + { + private double _d; + public T[] C0; + } - [MethodImpl(MethodImplOptions.NoInlining)] - static void TestFillAllSpan(Span span) - { - for (int i = 0; i < span.Length; ++i) { - span[i] = unchecked((byte)i); + [MethodImpl(MethodImplOptions.NoInlining)] + static void TestFillAllSpan(Span span) + { + for (int i = 0; i < span.Length; ++i) { + span[i] = unchecked((byte)i); + } } - } - [MethodImpl(MethodImplOptions.NoInlining)] - static void TestFillAllArray(byte[] data) - { - for (int i = 0; i < data.Length; ++i) { - data[i] = unchecked((byte)i); + [MethodImpl(MethodImplOptions.NoInlining)] + static void TestFillAllArray(byte[] data) + { + for (int i = 0; i < data.Length; ++i) { + data[i] = unchecked((byte)i); + } } - } - [MethodImpl(MethodImplOptions.NoInlining)] - static void TestFillAllReverseSpan(Span span) - { - for (int i = span.Length; --i >= 0;) { - span[i] = unchecked((byte)i); + [MethodImpl(MethodImplOptions.NoInlining)] + static void TestFillAllReverseSpan(Span span) + { + for (int i = span.Length; --i >= 0;) { + span[i] = unchecked((byte)i); + } } - } - [MethodImpl(MethodImplOptions.NoInlining)] - static void TestFillAllReverseArray(byte[] data) - { - for (int i = data.Length; --i >= 0;) { - data[i] = unchecked((byte)i); + [MethodImpl(MethodImplOptions.NoInlining)] + static void TestFillAllReverseArray(byte[] data) + { + for (int i = data.Length; --i >= 0;) { + data[i] = unchecked((byte)i); + } } - } - static int[] GetUnsortedData() - { - int[] unsortedData = new int[Size]; - Random r = new Random(42); - for (int i = 0; i < unsortedData.Length; ++i) + static int[] GetUnsortedData() { - unsortedData[i] = r.Next(); + int[] unsortedData = new int[Size]; + Random r = new Random(42); + for (int i = 0; i < unsortedData.Length; ++i) + { + unsortedData[i] = r.Next(); + } + return unsortedData; } - return unsortedData; - } - [MethodImpl(MethodImplOptions.NoInlining)] - static void TestBubbleSortSpan(Span span) - { - bool swap; - int temp; - int n = span.Length - 1; - do { - swap = false; - for (int i = 0; i < n; i++) { - if (span[i] > span[i + 1]) { - temp = span[i]; - span[i] = span[i + 1]; - span[i + 1] = temp; - swap = true; + [MethodImpl(MethodImplOptions.NoInlining)] + static void TestBubbleSortSpan(Span span) + { + bool swap; + int temp; + int n = span.Length - 1; + do { + swap = false; + for (int i = 0; i < n; i++) { + if (span[i] > span[i + 1]) { + temp = span[i]; + span[i] = span[i + 1]; + span[i + 1] = temp; + swap = true; + } } + --n; } - --n; + while (swap); } - while (swap); - } - [MethodImpl(MethodImplOptions.NoInlining)] - static void TestBubbleSortArray(int[] data) - { - bool swap; - int temp; - int n = data.Length - 1; - do { - swap = false; - for (int i = 0; i < n; i++) { - if (data[i] > data[i + 1]) { - temp = data[i]; - data[i] = data[i + 1]; - data[i + 1] = temp; - swap = true; + [MethodImpl(MethodImplOptions.NoInlining)] + static void TestBubbleSortArray(int[] data) + { + bool swap; + int temp; + int n = data.Length - 1; + do { + swap = false; + for (int i = 0; i < n; i++) { + if (data[i] > data[i + 1]) { + temp = data[i]; + data[i] = data[i + 1]; + data[i + 1] = temp; + swap = true; + } } + --n; } - --n; + while (swap); } - while (swap); - } - static void TestQuickSortSpan(Span data) - { - QuickSortSpan(data); - } - - [MethodImpl(MethodImplOptions.NoInlining)] - static void QuickSortSpan(Span data) - { - if (data.Length <= 1) { - return; + static void TestQuickSortSpan(Span data) + { + QuickSortSpan(data); } - int lo = 0; - int hi = data.Length - 1; - int i, j; - int pivot, temp; - for (i = lo, j = hi, pivot = data[hi]; i < j;) { - while (i < j && data[i] <= pivot) { - ++i; + [MethodImpl(MethodImplOptions.NoInlining)] + static void QuickSortSpan(Span data) + { + if (data.Length <= 1) { + return; } - while (j > i && data[j] >= pivot) { - --j; + + int lo = 0; + int hi = data.Length - 1; + int i, j; + int pivot, temp; + for (i = lo, j = hi, pivot = data[hi]; i < j;) { + while (i < j && data[i] <= pivot) { + ++i; + } + while (j > i && data[j] >= pivot) { + --j; + } + if (i < j) { + temp = data[i]; + data[i] = data[j]; + data[j] = temp; + } } - if (i < j) { + if (i != hi) { temp = data[i]; - data[i] = data[j]; - data[j] = temp; + data[i] = pivot; + data[hi] = temp; } - } - if (i != hi) { - temp = data[i]; - data[i] = pivot; - data[hi] = temp; - } - - QuickSortSpan(data.Slice(0, i)); - QuickSortSpan(data.Slice(i + 1)); - } - static void TestQuickSortArray(int[] data) - { - QuickSortArray(data, 0, data.Length - 1); - } + QuickSortSpan(data.Slice(0, i)); + QuickSortSpan(data.Slice(i + 1)); + } - [MethodImpl(MethodImplOptions.NoInlining)] - static void QuickSortArray(int[] data, int lo, int hi) - { - if (lo >= hi) { - return; + static void TestQuickSortArray(int[] data) + { + QuickSortArray(data, 0, data.Length - 1); } - int i, j; - int pivot, temp; - for (i = lo, j = hi, pivot = data[hi]; i < j;) { - while (i < j && data[i] <= pivot) { - ++i; + [MethodImpl(MethodImplOptions.NoInlining)] + static void QuickSortArray(int[] data, int lo, int hi) + { + if (lo >= hi) { + return; } - while (j > i && data[j] >= pivot) { - --j; + + int i, j; + int pivot, temp; + for (i = lo, j = hi, pivot = data[hi]; i < j;) { + while (i < j && data[i] <= pivot) { + ++i; + } + while (j > i && data[j] >= pivot) { + --j; + } + if (i < j) { + temp = data[i]; + data[i] = data[j]; + data[j] = temp; + } } - if (i < j) { + if (i != hi) { temp = data[i]; - data[i] = data[j]; - data[j] = temp; + data[i] = pivot; + data[hi] = temp; } - } - if (i != hi) { - temp = data[i]; - data[i] = pivot; - data[hi] = temp; - } - QuickSortArray(data, lo, i - 1); - QuickSortArray(data, i + 1, hi); - } - - // XUNIT-PERF tests + QuickSortArray(data, lo, i - 1); + QuickSortArray(data, i + 1, hi); + } + #endregion - [Benchmark] - public static void FillAllSpan() - { - byte[] a = new byte[Size]; - Span s = new Span(a); - foreach (var iteration in Benchmark.Iterations) + // XUNIT-PERF tests + #region XUNIT-PERF tests + [Benchmark] + public static void FillAllSpan() { - using (iteration.StartMeasurement()) + byte[] a = new byte[Size]; + Span s = new Span(a); + foreach (var iteration in Benchmark.Iterations) { - for (int i = 0; i < Iterations; i++) + using (iteration.StartMeasurement()) { - TestFillAllSpan(s); + for (int i = 0; i < FillAllIterations; i++) + { + TestFillAllSpan(s); + } } } } - } - [Benchmark] - public static void FillAllArray() - { - byte[] a = new byte[Size]; - foreach (var iteration in Benchmark.Iterations) + [Benchmark] + public static void FillAllArray() { - using (iteration.StartMeasurement()) + byte[] a = new byte[Size]; + foreach (var iteration in Benchmark.Iterations) { - for (int i = 0; i < Iterations; i++) + using (iteration.StartMeasurement()) { - TestFillAllArray(a); + for (int i = 0; i < FillAllIterations; i++) + { + TestFillAllArray(a); + } } } } - } - [Benchmark] - public static void FillAllReverseSpan() - { - byte[] a = new byte[Size]; - Span s = new Span(a); - foreach (var iteration in Benchmark.Iterations) + [Benchmark] + public static void FillAllReverseSpan() { - using (iteration.StartMeasurement()) + byte[] a = new byte[Size]; + Span s = new Span(a); + foreach (var iteration in Benchmark.Iterations) { - for (int i = 0; i < Iterations; i++) + using (iteration.StartMeasurement()) { - TestFillAllReverseSpan(s); + for (int i = 0; i < FillAllIterations; i++) + { + TestFillAllReverseSpan(s); + } } } } - } - [Benchmark] - public static void FillAllReverseArray() - { - byte[] a = new byte[Size]; - foreach (var iteration in Benchmark.Iterations) + [Benchmark] + public static void FillAllReverseArray() { - using (iteration.StartMeasurement()) + byte[] a = new byte[Size]; + foreach (var iteration in Benchmark.Iterations) { - for (int i = 0; i < Iterations; i++) + using (iteration.StartMeasurement()) { - TestFillAllReverseArray(a); + for (int i = 0; i < FillAllIterations; i++) + { + TestFillAllReverseArray(a); + } } } } - } - - [Benchmark] - public static void QuickSortSpan() - { - int[] data = new int[Size]; - int[] unsortedData = GetUnsortedData(); - Span span = new Span(data); - foreach (var iteration in Benchmark.Iterations) + [Benchmark] + public static void QuickSortSpan() { - using (iteration.StartMeasurement()) + int[] data = new int[Size]; + int[] unsortedData = GetUnsortedData(); + Span span = new Span(data); + + foreach (var iteration in Benchmark.Iterations) { - for (int i = 0; i < Iterations; i++) + using (iteration.StartMeasurement()) { - Array.Copy(unsortedData, data, Size); - TestQuickSortSpan(span); + for (int i = 0; i < QuickSortIterations; i++) + { + Array.Copy(unsortedData, data, Size); + TestQuickSortSpan(span); + } } } } - } - - [Benchmark] - public static void BubbleSortSpan() - { - int[] data = new int[Size]; - int[] unsortedData = GetUnsortedData(); - Span span = new Span(data); - foreach (var iteration in Benchmark.Iterations) + [Benchmark] + public static void BubbleSortSpan() { - using (iteration.StartMeasurement()) + int[] data = new int[Size]; + int[] unsortedData = GetUnsortedData(); + Span span = new Span(data); + + foreach (var iteration in Benchmark.Iterations) { - for (int i = 0; i < Iterations; i++) + using (iteration.StartMeasurement()) { - Array.Copy(unsortedData, data, Size); - TestBubbleSortSpan(span); + for (int i = 0; i < BubbleSortIterations; i++) + { + Array.Copy(unsortedData, data, Size); + TestBubbleSortSpan(span); + } } } } - } - [Benchmark] - public static void QuickSortArray() - { - int[] data = new int[Size]; - int[] unsortedData = GetUnsortedData(); - - foreach (var iteration in Benchmark.Iterations) + [Benchmark] + public static void QuickSortArray() { - using (iteration.StartMeasurement()) + int[] data = new int[Size]; + int[] unsortedData = GetUnsortedData(); + + foreach (var iteration in Benchmark.Iterations) { - for (int i = 0; i < Iterations; i++) + using (iteration.StartMeasurement()) { - Array.Copy(unsortedData, data, Size); - TestQuickSortArray(data); + for (int i = 0; i < QuickSortIterations; i++) + { + Array.Copy(unsortedData, data, Size); + TestQuickSortArray(data); + } } } } - } - [Benchmark] - public static void BubbleSortArray() - { - int[] data = new int[Size]; - int[] unsortedData = GetUnsortedData(); - - foreach (var iteration in Benchmark.Iterations) + [Benchmark] + public static void BubbleSortArray() { - using (iteration.StartMeasurement()) + int[] data = new int[Size]; + int[] unsortedData = GetUnsortedData(); + + foreach (var iteration in Benchmark.Iterations) { - for (int i = 0; i < Iterations; i++) + using (iteration.StartMeasurement()) { - Array.Copy(unsortedData, data, Size); - TestBubbleSortArray(data); + for (int i = 0; i < BubbleSortIterations; i++) + { + Array.Copy(unsortedData, data, Size); + TestBubbleSortArray(data); + } } } } - } + #endregion + + // TestSpanAPIs (For comparison with Array and Slow Span) + #region TestSpanAPIs + + #region TestSpanConstructor + [Benchmark(InnerIterationCount = BaseIterations)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanConstructorByte(int length) + { + var array = new byte[length]; + Span span; + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + span = new Span(array); + } - // EXE-based testing + [Benchmark(InnerIterationCount = BaseIterations / 100)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanConstructorString(int length) + { + var array = new string[length]; + Span span; + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + span = new Span(array); + } + #endregion + + #region TestSpanDangerousCreate + [Benchmark(InnerIterationCount = BaseIterations)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanDangerousCreateByte(int length) + { + TestClass testClass = new TestClass(); + testClass.C0 = new byte[length]; + Span span; + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + span = Span.DangerousCreate(testClass, ref testClass.C0[0], testClass.C0.Length); + } - static void FillAllSpanBase() - { - byte[] a = new byte[Size]; - Span s = new Span(a); - for (int i = 0; i < Iterations; i++) + [Benchmark(InnerIterationCount = BaseIterations)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanDangerousCreateString(int length) { - TestFillAllSpan(s); + TestClass testClass = new TestClass(); + testClass.C0 = new string[length]; + Span span; + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + span = Span.DangerousCreate(testClass, ref testClass.C0[0], testClass.C0.Length); + } + #endregion + + #region TestSpanDangerousGetPinnableReference + [Benchmark(InnerIterationCount = BaseIterations)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanDangerousGetPinnableReferenceByte(int length) + { + var array = new byte[length]; + var span = new Span(array); + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ref byte temp = ref span.DangerousGetPinnableReference(); + } } - } - static void FillAllArrayBase() - { - byte[] a = new byte[Size]; - for (int i = 0; i < Iterations; i++) + [Benchmark(InnerIterationCount = BaseIterations)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanDangerousGetPinnableReferenceString(int length) { - TestFillAllArray(a); + var array = new string[length]; + var span = new Span(array); + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ref string temp = ref span.DangerousGetPinnableReference(); + } } - } + #endregion + + #region TestSpanIndex + [Benchmark(InnerIterationCount = BaseIterations)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanIndexByte(int length) + { + var array = new byte[length]; + var span = new Span(array); + byte temp; + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + temp = span[length/2]; - static void FillAllReverseSpanBase() - { - byte[] a = new byte[Size]; - Span s = new Span(a); - for (int i = 0; i < Iterations; i++) + } + + [Benchmark(InnerIterationCount = BaseIterations)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanIndexString(int length) { - TestFillAllReverseSpan(s); + var array = new string[length]; + var span = new Span(array); + string temp; + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + temp = span[length / 2]; } - } + #endregion + + #region TestArrayIndex + [Benchmark(InnerIterationCount = BaseIterations)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestArrayIndexByte(int length) + { + var array = new byte[length]; + byte temp; + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + temp = array[length / 2]; - static void FillAllReverseArrayBase() - { - byte[] a = new byte[Size]; - for (int i = 0; i < Iterations; i++) + } + + [Benchmark(InnerIterationCount = BaseIterations)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestArrayIndexString(int length) { - TestFillAllReverseArray(a); + var array = new string[length]; + string temp; + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + temp = array[length / 2]; + } + #endregion + + #region TestSpanSlice + [Benchmark(InnerIterationCount = BaseIterations)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanSliceByte(int length) + { + var array = new byte[length]; + var span = new Span(array); + Span temp; + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + temp = span.Slice(length / 2); } - } - static void QuickSortSpanBase() - { - int[] data = new int[Size]; - int[] unsortedData = GetUnsortedData(); - Span span = new Span(data); + [Benchmark(InnerIterationCount = BaseIterations)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanSliceString(int length) + { + var array = new string[length]; + var span = new Span(array); + Span temp; + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + temp = span.Slice(length / 2); + } + #endregion + + #region TestSpanToArray + [Benchmark(InnerIterationCount = BaseIterations / 100)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanToArrayByte(int length) + { + var array = new byte[length]; + var span = new Span(array); + byte[] temp; + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + temp = span.ToArray(); + } - for (int i = 0; i < Iterations; i++) + [Benchmark(InnerIterationCount = BaseIterations / 100)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanToArrayString(int length) { - Array.Copy(unsortedData, data, Size); - TestQuickSortSpan(span); + var array = new string[length]; + var span = new Span(array); + string[] temp; + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + temp = span.ToArray(); + } + #endregion + + #region TestSpanCopyTo + [Benchmark(InnerIterationCount = BaseIterations / 10)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanCopyToByte(int length) + { + var array = new byte[length]; + var span = new Span(array); + var destArray = new byte[array.Length]; + var destination = new Span(destArray); + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + span.CopyTo(destination); } - } - static void BubbleSortSpanBase() - { - int[] data = new int[Size]; - int[] unsortedData = GetUnsortedData(); - Span span = new Span(data); + [Benchmark(InnerIterationCount = BaseIterations / 100)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanCopyToString(int length) + { + var array = new string[length]; + var span = new Span(array); + var destArray = new string[array.Length]; + var destination = new Span(destArray); + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + span.CopyTo(destination); + } + #endregion + + #region TestArrayCopyTo + [Benchmark(InnerIterationCount = BaseIterations / 10)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestArrayCopyToByte(int length) + { + var array = new byte[length]; + var destination = new byte[array.Length]; + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + array.CopyTo(destination, 0); + } - for (int i = 0; i < Iterations; i++) + [Benchmark(InnerIterationCount = BaseIterations / 100)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestArrayCopyToString(int length) { - Array.Copy(unsortedData, data, Size); - TestBubbleSortSpan(span); + var array = new string[length]; + var destination = new string[array.Length]; + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + array.CopyTo(destination, 0); + } + #endregion + + #region TestSpanFill + [Benchmark(InnerIterationCount = BaseIterations * 10)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanFillByte(int length) + { + var array = new byte[length]; + var span = new Span(array); + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + span.Fill(default(byte)); } - } - static void QuickSortArrayBase() - { - int[] data = new int[Size]; - int[] unsortedData = GetUnsortedData(); + [Benchmark(InnerIterationCount = BaseIterations / 100)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanFillString(int length) + { + var array = new string[length]; + var span = new Span(array); + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + span.Fill(default(string)); + } + #endregion + + #region TestSpanClear + [Benchmark(InnerIterationCount = BaseIterations / 10)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanClearByte(int length) + { + var array = new byte[length]; + var span = new Span(array); + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + span.Clear(); + } - for (int i = 0; i < Iterations; i++) + [Benchmark(InnerIterationCount = BaseIterations / 10)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanClearString(int length) { - Array.Copy(unsortedData, data, Size); - TestQuickSortArray(data); + var array = new string[length]; + var span = new Span(array); + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + span.Clear(); + } + #endregion + + #region TestArrayClear + [Benchmark(InnerIterationCount = BaseIterations / 10)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestArrayClearByte(int length) + { + var array = new byte[length]; + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + Array.Clear(array, 0, length); } - } - static void BubbleSortArrayBase() - { - int[] data = new int[Size]; - int[] unsortedData = GetUnsortedData(); + [Benchmark(InnerIterationCount = BaseIterations / 10)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestArrayClearString(int length) + { + var array = new string[length]; + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + Array.Clear(array, 0, length); + } + #endregion + + #region TestSpanAsBytes + [Benchmark(InnerIterationCount = BaseIterations)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanAsBytesByte(int length) + { + var array = new byte[length]; + var span = new Span(array); + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + Span temp = span.AsBytes(); + } + } - for (int i = 0; i < Iterations; i++) + [Benchmark(InnerIterationCount = BaseIterations)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanAsBytesInt(int length) { - Array.Copy(unsortedData, data, Size); - TestBubbleSortArray(data); + var array = new int[length]; + var span = new Span(array); + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + Span temp = span.AsBytes(); + } + } + #endregion + + #region TestSpanNonPortableCast + [Benchmark(InnerIterationCount = BaseIterations)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanNonPortableCastFromByteToInt(int length) + { + var array = new byte[length]; + var span = new Span(array); + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + Span temp = span.NonPortableCast(); + } } - } - static double Bench(Action f) - { - Stopwatch sw = Stopwatch.StartNew(); - f(); - sw.Stop(); - return sw.Elapsed.TotalMilliseconds; - } + [Benchmark(InnerIterationCount = BaseIterations)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanNonPortableCastFromIntToByte(int length) + { + var array = new int[length]; + var span = new Span(array); + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + Span temp = span.NonPortableCast(); + } + } + #endregion + + #region TestSpanSliceStringChar + [Benchmark(InnerIterationCount = BaseIterations)] + [InlineData(1)] + [InlineData(10)] + [InlineData(100)] + [InlineData(1000)] + public static void TestSpanSliceStringChar(int length) + { + StringBuilder sb = new StringBuilder(); + Random rand = new Random(42); + char[] c = new char[1]; + for (int i = 0; i < length; i++) + { + c[0] = (char)rand.Next(32, 126); + sb.Append(new string(c)); + } + string s = sb.ToString(); + + foreach (var iteration in Benchmark.Iterations) + using (iteration.StartMeasurement()) + for (int i = 0; i < Benchmark.InnerIterationCount; i++) + { + ReadOnlySpan temp = s.Slice(); + } + } + #endregion - static IEnumerable MakeArgs(params string[] args) - { - return args.Select(arg => new object[] { arg }); - } + #endregion + + // EXE-based testing + #region EXE-base testing + static void FillAllSpanBase() + { + byte[] a = new byte[Size]; + Span s = new Span(a); + for (int i = 0; i < FillAllIterations; i++) + { + TestFillAllSpan(s); + } + } - static IEnumerable TestFuncs = MakeArgs( - "FillAllSpanBase", "FillAllArrayBase", - "FillAllReverseSpanBase", "FillAllReverseArrayBase", - "BubbleSortSpanBase", "BubbleSortArrayBase", - "QuickSortSpanBase", "QuickSortArrayBase" - ); + static void FillAllArrayBase() + { + byte[] a = new byte[Size]; + for (int i = 0; i < FillAllIterations; i++) + { + TestFillAllArray(a); + } + } - static Action LookupFunc(object o) - { - TypeInfo t = typeof(Tests).GetTypeInfo(); - MethodInfo m = t.GetDeclaredMethod((string) o); - return m.CreateDelegate(typeof(Action)) as Action; - } + static void FillAllReverseSpanBase() + { + byte[] a = new byte[Size]; + Span s = new Span(a); + for (int i = 0; i < FillAllIterations; i++) + { + TestFillAllReverseSpan(s); + } + } - public static int Main(string[] args) - { - bool result = true; + static void FillAllReverseArrayBase() + { + byte[] a = new byte[Size]; + for (int i = 0; i < FillAllIterations; i++) + { + TestFillAllReverseArray(a); + } + } - foreach(object[] o in TestFuncs) + static void QuickSortSpanBase() { - string funcName = (string) o[0]; - Action func = LookupFunc(funcName); - double timeInMs = Bench(func); - Console.WriteLine("{0}: {1}ms", funcName, timeInMs); + int[] data = new int[Size]; + int[] unsortedData = GetUnsortedData(); + Span span = new Span(data); + + for (int i = 0; i < QuickSortIterations; i++) + { + Array.Copy(unsortedData, data, Size); + TestQuickSortSpan(span); + } } - return (result ? 100 : -1); - } -} + static void BubbleSortSpanBase() + { + int[] data = new int[Size]; + int[] unsortedData = GetUnsortedData(); + Span span = new Span(data); + + for (int i = 0; i < BubbleSortIterations; i++) + { + Array.Copy(unsortedData, data, Size); + TestBubbleSortSpan(span); + } + } + + static void QuickSortArrayBase() + { + int[] data = new int[Size]; + int[] unsortedData = GetUnsortedData(); + for (int i = 0; i < QuickSortIterations; i++) + { + Array.Copy(unsortedData, data, Size); + TestQuickSortArray(data); + } + } + + static void BubbleSortArrayBase() + { + int[] data = new int[Size]; + int[] unsortedData = GetUnsortedData(); + + for (int i = 0; i < BubbleSortIterations; i++) + { + Array.Copy(unsortedData, data, Size); + TestBubbleSortArray(data); + } + } + #endregion + + static double Bench(Action f) + { + Stopwatch sw = Stopwatch.StartNew(); + f(); + sw.Stop(); + return sw.Elapsed.TotalMilliseconds; + } + + static IEnumerable MakeArgs(params string[] args) + { + return args.Select(arg => new object[] { arg }); + } + + static IEnumerable TestFuncs = MakeArgs( + "FillAllSpanBase", "FillAllArrayBase", + "FillAllReverseSpanBase", "FillAllReverseArrayBase", + "BubbleSortSpanBase", "BubbleSortArrayBase", + "QuickSortSpanBase", "QuickSortArrayBase" + ); + + static Action LookupFunc(object o) + { + TypeInfo t = typeof(SpanBench).GetTypeInfo(); + MethodInfo m = t.GetDeclaredMethod((string) o); + return m.CreateDelegate(typeof(Action)) as Action; + } + + public static int Main(string[] args) + { + bool result = true; + + foreach(object[] o in TestFuncs) + { + string funcName = (string) o[0]; + Action func = LookupFunc(funcName); + double timeInMs = Bench(func); + Console.WriteLine("{0}: {1}ms", funcName, timeInMs); + } + + return (result ? 100 : -1); + } + } +} \ No newline at end of file diff --git a/tests/src/JIT/Performance/CodeQuality/Span/SpanBench.csproj b/tests/src/JIT/Performance/CodeQuality/Span/SpanBench.csproj index e932acf2a2..ba240107ba 100644 --- a/tests/src/JIT/Performance/CodeQuality/Span/SpanBench.csproj +++ b/tests/src/JIT/Performance/CodeQuality/Span/SpanBench.csproj @@ -1,5 +1,7 @@  + + Debug -- cgit v1.2.3