diff options
Diffstat (limited to 'tests/src/JIT/Performance/CodeQuality/Layout/SearchLoops.cs')
-rw-r--r-- | tests/src/JIT/Performance/CodeQuality/Layout/SearchLoops.cs | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/tests/src/JIT/Performance/CodeQuality/Layout/SearchLoops.cs b/tests/src/JIT/Performance/CodeQuality/Layout/SearchLoops.cs new file mode 100644 index 0000000000..60684f65df --- /dev/null +++ b/tests/src/JIT/Performance/CodeQuality/Layout/SearchLoops.cs @@ -0,0 +1,120 @@ +// 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 Microsoft.Xunit.Performance; +using Microsoft.Xunit.Performance.Api; +using System; +using System.Reflection; +using Xunit; + +[assembly: OptimizeForBenchmarks] + +// Test code taken directly from GitHub issue #9692 (https://github.com/dotnet/coreclr/issues/9692) +// Laying the loop's early return path in-line can cost 30% on this micro-benchmark. + +namespace Layout +{ + public unsafe class SearchLoops + { + public static int Main(string[] args) + { + // Make sure equal strings compare as such + if (!LoopReturn("hello", "hello") || !LoopGoto("goodbye", "goodbye")) + { + return -1; + } + + // Make sure not-equal strings compare as such + if (LoopReturn("hello", "goodbye") || LoopGoto("goodbye", "hello")) + { + return -1; + } + + // Success + return 100; + } + + public int length = 100; + + private string test1; + private string test2; + + public SearchLoops() + { + test1 = new string('A', length); + test2 = new string('A', length); + } + + [Benchmark(InnerIterationCount = 20000000)] + public void LoopReturn() + { + Benchmark.Iterate(() => LoopReturn(test1, test2)); + } + + [Benchmark(InnerIterationCount = 20000000)] + public void LoopGoto() + { + Benchmark.Iterate(() => LoopGoto(test1, test2)); + } + + // Variant with code written naturally -- need JIT to lay this out + // with return path out of loop for best performance. + public static bool LoopReturn(String strA, String strB) + { + int length = strA.Length; + + fixed (char* ap = strA) fixed (char* bp = strB) + { + char* a = ap; + char* b = bp; + + while (length != 0) + { + int charA = *a; + int charB = *b; + + if (charA != charB) + return false; // placement of prolog for this return is the issue + + a++; + b++; + length--; + } + + return true; + } + } + + // Variant with code written awkwardly but which acheives the desired + // performance if JIT simply lays out code in source order. + public static bool LoopGoto(String strA, String strB) + { + int length = strA.Length; + + fixed (char* ap = strA) fixed (char* bp = strB) + { + char* a = ap; + char* b = bp; + + while (length != 0) + { + int charA = *a; + int charB = *b; + + if (charA != charB) + goto ReturnFalse; // placement of prolog for this return is the issue + + a++; + b++; + length--; + } + + return true; + + ReturnFalse: + return false; + } + } + } +} |