diff --git a/src/benchmarks/micro/coreclr/Devirtualization/GuardedThreeClassInterface.cs b/src/benchmarks/micro/coreclr/Devirtualization/GuardedThreeClassInterface.cs new file mode 100644 index 00000000000..7a873fa867d --- /dev/null +++ b/src/benchmarks/micro/coreclr/Devirtualization/GuardedThreeClassInterface.cs @@ -0,0 +1,96 @@ +// 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.Collections.Generic; +using System.Linq; +using BenchmarkDotNet.Attributes; +using MicroBenchmarks; + +// Performance test for virtual call dispatch with three +// possible target classes mixed in varying proportions. + +namespace GuardedDevirtualization +{ + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] + public class ThreeClassInterface + { + interface I + { + int F(); + } + + public class B : I + { + int I.F() => 33; + } + + public class D : B, I + { + int I.F() => 44; + } + + public class E : B, I + { + int I.F() => 55; + } + + [Benchmark(OperationsPerInvoke=TestInput.N)] + [ArgumentsSource(nameof(GetInput))] + public long Call(TestInput testInput) + { + long sum = 0; + + // Note: for now we type the test input as B[] and not I[] + // so the simple guessing heuristic in the jit has a class + // to guess for. + B[] input = testInput.Array; + for (int i = 0; i < input.Length; i++) + { + sum += ((I)input[i]).F(); + } + return sum; + } + + public static IEnumerable GetInput() + { + const int S = 3; + const double delta = 1.0 / (double) S; + + for (int i = 0; i <= S; i++) + { + for (int j = 0; j <= S - i; j++) + { + yield return new TestInput(i * delta, j * delta); + } + } + } + + public class TestInput + { + public const int N = 1000; + + public B[] Array; + private double _pB; + private double _pD; + + public TestInput(double pB, double pD) + { + _pB = pB; + _pD = pD; + Array = ValuesGenerator.Array(N).Select(p => + { + if (p <= _pB) + return new B(); + if (p <= _pB + _pD) + return new D(); + return new E(); + }).ToArray(); + } + + public override string ToString() => $"pB={_pB:F2} pD={_pD:F2}"; + } + } +} + + diff --git a/src/benchmarks/micro/coreclr/Devirtualization/GuardedThreeClassVirtual.cs b/src/benchmarks/micro/coreclr/Devirtualization/GuardedThreeClassVirtual.cs new file mode 100644 index 00000000000..77a08ee331d --- /dev/null +++ b/src/benchmarks/micro/coreclr/Devirtualization/GuardedThreeClassVirtual.cs @@ -0,0 +1,87 @@ +// 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.Collections.Generic; +using System.Linq; +using BenchmarkDotNet.Attributes; +using MicroBenchmarks; + +// Performance test for virtual call dispatch with three +// possible target classes mixed in varying proportions. + +namespace GuardedDevirtualization +{ + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] + public class ThreeClassVirtual + { + public class B + { + public virtual int F() => 33; + } + + public class D : B + { + public override int F() => 44; + } + + public class E : B + { + public override int F() => 55; + } + + [Benchmark(OperationsPerInvoke=TestInput.N)] + [ArgumentsSource(nameof(GetInput))] + public long Call(TestInput testInput) + { + long sum = 0; + B[] input = testInput.Array; + for (int i = 0; i < input.Length; i++) + { + sum += input[i].F(); + } + return sum; + } + + public static IEnumerable GetInput() + { + const int S = 3; + const double delta = 1.0 / (double) S; + + for (int i = 0; i <= S; i++) + { + for (int j = 0; j <= S - i; j++) + { + yield return new TestInput(i * delta, j * delta); + } + } + } + + public class TestInput + { + public const int N = 1000; + + public B[] Array; + private double _pB; + private double _pD; + + public TestInput(double pB, double pD) + { + _pB = pB; + _pD = pD; + Array = ValuesGenerator.Array(N).Select(p => + { + if (p <= _pB) + return new B(); + if (p <= _pB + _pD) + return new D(); + return new E(); + }).ToArray(); + } + + public override string ToString() => $"pB={_pB:F2} pD={_pD:F2}"; + } + } +} + + diff --git a/src/benchmarks/micro/coreclr/Devirtualization/GuardedTwoClassInterface.cs b/src/benchmarks/micro/coreclr/Devirtualization/GuardedTwoClassInterface.cs new file mode 100644 index 00000000000..91299a9313d --- /dev/null +++ b/src/benchmarks/micro/coreclr/Devirtualization/GuardedTwoClassInterface.cs @@ -0,0 +1,77 @@ +// 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.Collections.Generic; +using System.Linq; +using BenchmarkDotNet.Attributes; +using MicroBenchmarks; + +// Performance test for interface call dispatch with two +// possible target classes mixed in varying proportions. + +namespace GuardedDevirtualization +{ + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] + public class TwoClassInterface + { + interface I + { + int F(); + } + + public class B : I + { + int I.F() => 33; + } + + public class D : B, I + { + int I.F() => 44; + } + + [Benchmark(OperationsPerInvoke = TestInput.N)] + [ArgumentsSource(nameof(GetInput))] + public long Call(TestInput testInput) + { + long sum = 0; + + // Note: for now we type the test input as B[] and not I[] + // so the simple guessing heuristic in the jit has a class + // to guess for. + B[] input = testInput.Array; + for (int i = 0; i < input.Length; i++) + { + sum += ((I)input[i]).F(); + } + + return sum; + } + + public static IEnumerable GetInput() + { + for (double pB = 0; pB <= 1.0; pB += 0.1) + { + yield return new TestInput(pB); + } + } + + public class TestInput + { + public const int N = 1000; + + public B[] Array; + private double _pB; + + public TestInput(double pB) + { + _pB = pB; + Array = ValuesGenerator.Array(N).Select(p => p > _pB ? new D() : new B()).ToArray(); + } + + public override string ToString() => $"pB = {_pB:F2}"; + } + } +} + + diff --git a/src/benchmarks/micro/coreclr/Devirtualization/GuardedTwoClassVirtual.cs b/src/benchmarks/micro/coreclr/Devirtualization/GuardedTwoClassVirtual.cs new file mode 100644 index 00000000000..976b2cd4602 --- /dev/null +++ b/src/benchmarks/micro/coreclr/Devirtualization/GuardedTwoClassVirtual.cs @@ -0,0 +1,66 @@ +// 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.Collections.Generic; +using System.Linq; +using BenchmarkDotNet.Attributes; +using MicroBenchmarks; + +// Performance test for virtual call dispatch with two +// possible target classes mixed in varying proportions. + +namespace GuardedDevirtualization +{ + [BenchmarkCategory(Categories.CoreCLR, Categories.Virtual)] + public class TwoClassVirtual + { + public class B + { + public virtual int F() => 33; + } + + public class D : B + { + public override int F() => 44; + } + + [Benchmark(OperationsPerInvoke = TestInput.N)] + [ArgumentsSource(nameof(GetInput))] + public long Call(TestInput testInput) + { + long sum = 0; + B[] input = testInput.Array; + for (int i = 0; i < input.Length; i++) + { + sum += input[i].F(); + } + + return sum; + } + + public static IEnumerable GetInput() + { + for (double pB = 0; pB <= 1.0; pB += 0.1) + { + yield return new TestInput(pB); + } + } + + public class TestInput + { + public const int N = 1000; + + public B[] Array; + private double _pB; + + public TestInput(double pB) + { + _pB = pB; + Array = ValuesGenerator.Array(N).Select(p => p > _pB ? new D() : new B()).ToArray(); + } + + public override string ToString() => $"pB = {_pB:F2}"; + } + } +} \ No newline at end of file