Skip to content

Commit

Permalink
ensure the default order of benchmarks is the same as declared in sou…
Browse files Browse the repository at this point in the history
…rce code (#1907)
  • Loading branch information
adamsitnik authored Feb 2, 2022
1 parent 6d27395 commit 3ea2129
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 8 deletions.
11 changes: 11 additions & 0 deletions src/BenchmarkDotNet.Annotations/Attributes/BenchmarkAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Runtime.CompilerServices;
using JetBrains.Annotations;

namespace BenchmarkDotNet.Attributes
Expand All @@ -7,10 +8,20 @@ namespace BenchmarkDotNet.Attributes
[MeansImplicitUse]
public class BenchmarkAttribute : Attribute
{
public BenchmarkAttribute([CallerLineNumber] int sourceCodeLineNumber = 0, [CallerFilePath] string sourceCodeFile = "")
{
SourceCodeLineNumber = sourceCodeLineNumber;
SourceCodeFile = sourceCodeFile;
}

public string Description { get; set; }

public bool Baseline { get; set; }

public int OperationsPerInvoke { get; set; } = 1;

public int SourceCodeLineNumber { get; }

public string SourceCodeFile { get; }
}
}
14 changes: 11 additions & 3 deletions src/BenchmarkDotNet/Running/BenchmarkConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,22 @@ public static BenchmarkRunInfo TypeToBenchmarks(Type type, IConfig config = null

// We should check all methods including private to notify users about private methods with the [Benchmark] attribute
var bindingFlags = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
var benchmarkMethods = type.GetMethods(bindingFlags).Where(method => method.HasAttribute<BenchmarkAttribute>()).ToArray();
var benchmarkMethods = GetOrderedBenchmarkMethods(type.GetMethods(bindingFlags));

return MethodsToBenchmarksWithFullConfig(type, benchmarkMethods, config);
}

public static BenchmarkRunInfo MethodsToBenchmarks(Type containingType, MethodInfo[] benchmarkMethods, IConfig config = null)
=> MethodsToBenchmarksWithFullConfig(containingType, benchmarkMethods, config);
=> MethodsToBenchmarksWithFullConfig(containingType, GetOrderedBenchmarkMethods(benchmarkMethods), config);

private static MethodInfo[] GetOrderedBenchmarkMethods(MethodInfo[] methods)
=> methods
.Select(method => (method, attribute: method.ResolveAttribute<BenchmarkAttribute>()))
.Where(pair => pair.attribute is not null)
.OrderBy(pair => pair.attribute.SourceCodeFile)
.ThenBy(pair => pair.attribute.SourceCodeLineNumber)
.Select(pair => pair.method)
.ToArray();

private static BenchmarkRunInfo MethodsToBenchmarksWithFullConfig(Type type, MethodInfo[] benchmarkMethods, IConfig config)
{
Expand Down Expand Up @@ -108,7 +117,6 @@ private static IEnumerable<Descriptor> GetTargets(
Tuple<MethodInfo, TargetedAttribute>[] iterationCleanupMethods)
{
return targetMethods
.Where(m => m.HasAttribute<BenchmarkAttribute>())
.Select(methodInfo => CreateDescriptor(type,
GetTargetedMatchingMethod(methodInfo, globalSetupMethods),
methodInfo,
Expand Down
6 changes: 3 additions & 3 deletions src/BenchmarkDotNet/Running/TypeFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@

namespace BenchmarkDotNet.Running
{
internal static class TypeFilter
public static class TypeFilter
{
internal static (bool allTypesValid, IReadOnlyList<Type> runnable) GetTypesWithRunnableBenchmarks(IEnumerable<Type> types, IEnumerable<Assembly> assemblies, ILogger logger)
public static (bool allTypesValid, IReadOnlyList<Type> runnable) GetTypesWithRunnableBenchmarks(IEnumerable<Type> types, IEnumerable<Assembly> assemblies, ILogger logger)
{
var validRunnableTypes = new List<Type>();

Expand All @@ -37,7 +37,7 @@ internal static (bool allTypesValid, IReadOnlyList<Type> runnable) GetTypesWithR
return (true, validRunnableTypes);
}

internal static BenchmarkRunInfo[] Filter(IConfig effectiveConfig, IEnumerable<Type> types)
public static BenchmarkRunInfo[] Filter(IConfig effectiveConfig, IEnumerable<Type> types)
=> types
.Select(type => BenchmarkConverter.TypeToBenchmarks(type, effectiveConfig))
.Where(info => info.BenchmarksCases.Any())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using BenchmarkDotNet.Attributes;

namespace BenchmarkDotNet.Tests.Running
{
public partial class BenchmarkConverterTests
{
public partial class BAC_Partial_DifferentFiles
{
[Benchmark] public void B() { }
}
}
}
43 changes: 41 additions & 2 deletions tests/BenchmarkDotNet.Tests/Running/BenchmarkConverterTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Linq;
using System;
using System.Linq;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Environments;
Expand All @@ -9,7 +10,7 @@

namespace BenchmarkDotNet.Tests.Running
{
public class BenchmarkConverterTests
public partial class BenchmarkConverterTests
{
/// <summary>
/// https://github.com/dotnet/BenchmarkDotNet/issues/495
Expand Down Expand Up @@ -198,5 +199,43 @@ public class WithFewMutators
{
[Benchmark] public void Method() { }
}

[Fact]
public void MethodDeclarationOrderIsPreserved()
{
foreach (Type type in new[] { typeof(BAC), typeof(BAC_Partial), typeof(BAC_Partial_DifferentFiles) })
{
var info = BenchmarkConverter.TypeToBenchmarks(type);

Assert.Equal(nameof(BAC.B), info.BenchmarksCases[0].Descriptor.WorkloadMethod.Name);
Assert.Equal(nameof(BAC.A), info.BenchmarksCases[1].Descriptor.WorkloadMethod.Name);
Assert.Equal(nameof(BAC.C), info.BenchmarksCases[2].Descriptor.WorkloadMethod.Name);
}
}

public class BAC
{
// BAC is not sorted in either desceding or ascending way
[Benchmark] public void B() { }
[Benchmark] public void A() { }
[Benchmark] public void C() { }
}

public partial class BAC_Partial
{
[Benchmark] public void B() { }
[Benchmark] public void A() { }
}

public partial class BAC_Partial
{
[Benchmark] public void C() { }
}

public partial class BAC_Partial_DifferentFiles
{
[Benchmark] public void A() { }
[Benchmark] public void C() { }
}
}
}

0 comments on commit 3ea2129

Please sign in to comment.