Skip to content

Commit d66289a

Browse files
authored
Improve support for NativeAOT (#1960)
* remove Obsolete fields * add a possibility to disable specific benchmarks for AOT runtimes * remove support for old experimental builds of CoreRT that are targeting runtimes that are not longer supported (nobody should be using this combination) * introduce NativeAotRuntime * rename --coreRtVersion to --ilCompilerVersion (not dependent on CoreRT/NativeAOT naming) * update default ILCompilerVersion and NuGet feed url to point to latest 7.0 bits * IsCoreRT should return false on .NET 7 * annotate GenericTypeArgumentsAttribute with [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
1 parent 010ac21 commit d66289a

20 files changed

+265
-163
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace System.Diagnostics.CodeAnalysis
5+
{
6+
/// <summary>
7+
/// Specifies the types of members that are dynamically accessed.
8+
///
9+
/// This enumeration has a <see cref="FlagsAttribute"/> attribute that allows a
10+
/// bitwise combination of its member values.
11+
/// </summary>
12+
[Flags]
13+
internal enum DynamicallyAccessedMemberTypes
14+
{
15+
/// <summary>
16+
/// Specifies no members.
17+
/// </summary>
18+
None = 0,
19+
20+
/// <summary>
21+
/// Specifies the default, parameterless public constructor.
22+
/// </summary>
23+
PublicParameterlessConstructor = 0x0001,
24+
25+
/// <summary>
26+
/// Specifies all public constructors.
27+
/// </summary>
28+
PublicConstructors = 0x0002 | PublicParameterlessConstructor,
29+
30+
/// <summary>
31+
/// Specifies all non-public constructors.
32+
/// </summary>
33+
NonPublicConstructors = 0x0004,
34+
35+
/// <summary>
36+
/// Specifies all public methods.
37+
/// </summary>
38+
PublicMethods = 0x0008,
39+
40+
/// <summary>
41+
/// Specifies all non-public methods.
42+
/// </summary>
43+
NonPublicMethods = 0x0010,
44+
45+
/// <summary>
46+
/// Specifies all public fields.
47+
/// </summary>
48+
PublicFields = 0x0020,
49+
50+
/// <summary>
51+
/// Specifies all non-public fields.
52+
/// </summary>
53+
NonPublicFields = 0x0040,
54+
55+
/// <summary>
56+
/// Specifies all public nested types.
57+
/// </summary>
58+
PublicNestedTypes = 0x0080,
59+
60+
/// <summary>
61+
/// Specifies all non-public nested types.
62+
/// </summary>
63+
NonPublicNestedTypes = 0x0100,
64+
65+
/// <summary>
66+
/// Specifies all public properties.
67+
/// </summary>
68+
PublicProperties = 0x0200,
69+
70+
/// <summary>
71+
/// Specifies all non-public properties.
72+
/// </summary>
73+
NonPublicProperties = 0x0400,
74+
75+
/// <summary>
76+
/// Specifies all public events.
77+
/// </summary>
78+
PublicEvents = 0x0800,
79+
80+
/// <summary>
81+
/// Specifies all non-public events.
82+
/// </summary>
83+
NonPublicEvents = 0x1000,
84+
85+
/// <summary>
86+
/// Specifies all members.
87+
/// </summary>
88+
All = ~None
89+
}
90+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
namespace System.Diagnostics.CodeAnalysis
5+
{
6+
/// <summary>
7+
/// Indicates that certain members on a specified <see cref="Type"/> are accessed dynamically,
8+
/// for example through <see cref="System.Reflection"/>.
9+
/// </summary>
10+
/// <remarks>
11+
/// This allows tools to understand which members are being accessed during the execution
12+
/// of a program.
13+
///
14+
/// This attribute is valid on members whose type is <see cref="Type"/> or <see cref="string"/>.
15+
///
16+
/// When this attribute is applied to a location of type <see cref="string"/>, the assumption is
17+
/// that the string represents a fully qualified type name.
18+
///
19+
/// If the attribute is applied to a method it's treated as a special case and it implies
20+
/// the attribute should be applied to the "this" parameter of the method. As such the attribute
21+
/// should only be used on instance methods of types assignable to System.Type (or string, but no methods
22+
/// will use it there).
23+
/// </remarks>
24+
[AttributeUsage(
25+
AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter |
26+
AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method,
27+
Inherited = false)]
28+
internal sealed class DynamicallyAccessedMembersAttribute : Attribute
29+
{
30+
/// <summary>
31+
/// Initializes a new instance of the <see cref="DynamicallyAccessedMembersAttribute"/> class
32+
/// with the specified member types.
33+
/// </summary>
34+
/// <param name="memberTypes">The types of members dynamically accessed.</param>
35+
public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes)
36+
{
37+
MemberTypes = memberTypes;
38+
}
39+
40+
/// <summary>
41+
/// Gets the <see cref="DynamicallyAccessedMemberTypes"/> which specifies the type
42+
/// of members dynamically accessed.
43+
/// </summary>
44+
public DynamicallyAccessedMemberTypes MemberTypes { get; }
45+
}
46+
}

src/BenchmarkDotNet.Annotations/Attributes/GenericTypeArgumentsAttribute.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using JetBrains.Annotations;
22
using System;
3+
using System.Diagnostics.CodeAnalysis;
34

45
namespace BenchmarkDotNet.Attributes
56
{
@@ -11,6 +12,6 @@ public class GenericTypeArgumentsAttribute : Attribute
1112
// CLS-Compliant Code requires a constructor without an array in the argument list
1213
[PublicAPI] public GenericTypeArgumentsAttribute() => GenericTypeArguments = new Type[0];
1314

14-
public GenericTypeArgumentsAttribute(params Type[] genericTypeArguments) => GenericTypeArguments = genericTypeArguments;
15+
public GenericTypeArgumentsAttribute([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] params Type[] genericTypeArguments) => GenericTypeArguments = genericTypeArguments;
1516
}
1617
}

src/BenchmarkDotNet.Annotations/Jobs/RuntimeMoniker.cs

+2-27
Original file line numberDiff line numberDiff line change
@@ -95,31 +95,6 @@ public enum RuntimeMoniker
9595
/// </summary>
9696
Net70,
9797

98-
/// <summary>
99-
/// CoreRT compiled as netcoreapp2.0
100-
/// </summary>
101-
CoreRt20,
102-
103-
/// <summary>
104-
/// CoreRT compiled as netcoreapp2.1
105-
/// </summary>
106-
CoreRt21,
107-
108-
/// <summary>
109-
/// CoreRT compiled as netcoreapp2.2
110-
/// </summary>
111-
CoreRt22,
112-
113-
/// <summary>
114-
/// CoreRT compiled as netcoreapp3.0
115-
/// </summary>
116-
CoreRt30,
117-
118-
/// <summary>
119-
/// CoreRT compiled as netcoreapp3.1
120-
/// </summary>
121-
CoreRt31,
122-
12398
/// <summary>
12499
/// CoreRT compiled as net5.0
125100
/// </summary>
@@ -131,9 +106,9 @@ public enum RuntimeMoniker
131106
CoreRt60,
132107

133108
/// <summary>
134-
/// CoreRT compiled as net7.0
109+
/// NativeAOT compiled as net7.0
135110
/// </summary>
136-
CoreRt70,
111+
NativeAot70,
137112

138113
/// <summary>
139114
/// WebAssembly with default .Net version
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using BenchmarkDotNet.Filters;
2+
3+
namespace BenchmarkDotNet.Attributes.Filters
4+
{
5+
public class AotFilterAttribute : FilterConfigBaseAttribute
6+
{
7+
public AotFilterAttribute(string reason = null)
8+
: base(new SimpleFilter(benchmark => !benchmark.GetRuntime().IsAOT))
9+
{
10+
}
11+
}
12+
}

src/BenchmarkDotNet/ConsoleArguments/CommandLineOptions.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ public class CommandLineOptions
9494
[Option("clrVersion", Required = false, HelpText = "Optional version of private CLR build used as the value of COMPLUS_Version env var.")]
9595
public string ClrVersion { get; set; }
9696

97-
[Option("coreRtVersion", Required = false, HelpText = "Optional version of Microsoft.DotNet.ILCompiler which should be used to run with CoreRT. Example: \"1.0.0-alpha-26414-01\"")]
98-
public string CoreRtVersion { get; set; }
97+
[Option("ilCompilerVersion", Required = false, HelpText = "Optional version of Microsoft.DotNet.ILCompiler which should be used to run with CoreRT/NativeAOT. Example: \"7.0.0-preview.3.22123.2\"")]
98+
public string ILCompilerVersion { get; set; }
9999

100100
[Option("ilcPath", Required = false, HelpText = "Optional IlcPath which should be used to run with private CoreRT build.")]
101101
public DirectoryInfo CoreRtPath { get; set; }

src/BenchmarkDotNet/ConsoleArguments/ConfigParser.cs

+25-24
Original file line numberDiff line numberDiff line change
@@ -363,32 +363,11 @@ private static Job CreateJobForGivenRuntime(Job baseJob, string runtimeId, Comma
363363
.WithToolchain(CsProjCoreToolchain.From(new NetCoreAppSettings(runtimeId, null, runtimeId, options.CliPath?.FullName, options.RestorePath?.FullName)));
364364
case RuntimeMoniker.Mono:
365365
return baseJob.WithRuntime(new MonoRuntime("Mono", options.MonoPath?.FullName));
366-
case RuntimeMoniker.CoreRt20:
367-
case RuntimeMoniker.CoreRt21:
368-
case RuntimeMoniker.CoreRt22:
369-
case RuntimeMoniker.CoreRt30:
370-
case RuntimeMoniker.CoreRt31:
371366
case RuntimeMoniker.CoreRt50:
372367
case RuntimeMoniker.CoreRt60:
373-
case RuntimeMoniker.CoreRt70:
374-
var builder = CoreRtToolchain.CreateBuilder();
375-
376-
if (options.CliPath != null)
377-
builder.DotNetCli(options.CliPath.FullName);
378-
if (options.RestorePath != null)
379-
builder.PackagesRestorePath(options.RestorePath.FullName);
380-
381-
if (options.CoreRtPath != null)
382-
builder.UseCoreRtLocal(options.CoreRtPath.FullName);
383-
else if (!string.IsNullOrEmpty(options.CoreRtVersion))
384-
builder.UseCoreRtNuGet(options.CoreRtVersion);
385-
else
386-
builder.UseCoreRtNuGet();
387-
388-
var runtime = runtimeMoniker.GetRuntime();
389-
builder.TargetFrameworkMoniker(runtime.MsBuildMoniker);
390-
391-
return baseJob.WithRuntime(runtime).WithToolchain(builder.ToToolchain());
368+
return CreateAotJob(baseJob, options, runtimeMoniker, "6.0.0-*", "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-experimental/nuget/v3/index.json");
369+
case RuntimeMoniker.NativeAot70:
370+
return CreateAotJob(baseJob, options, runtimeMoniker, "7.0.0-*", "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json");
392371
case RuntimeMoniker.Wasm:
393372
return MakeWasmJob(baseJob, options, RuntimeInformation.IsNetCore ? CoreRuntime.GetCurrentVersion().MsBuildMoniker : "net5.0", runtimeMoniker);
394373
case RuntimeMoniker.WasmNet50:
@@ -408,6 +387,28 @@ private static Job CreateJobForGivenRuntime(Job baseJob, string runtimeId, Comma
408387
}
409388
}
410389

390+
private static Job CreateAotJob(Job baseJob, CommandLineOptions options, RuntimeMoniker runtimeMoniker, string ilCompilerVersion, string nuGetFeedUrl)
391+
{
392+
var builder = CoreRtToolchain.CreateBuilder();
393+
394+
if (options.CliPath != null)
395+
builder.DotNetCli(options.CliPath.FullName);
396+
if (options.RestorePath != null)
397+
builder.PackagesRestorePath(options.RestorePath.FullName);
398+
399+
if (options.CoreRtPath != null)
400+
builder.UseCoreRtLocal(options.CoreRtPath.FullName);
401+
else if (!string.IsNullOrEmpty(options.ILCompilerVersion))
402+
builder.UseCoreRtNuGet(options.ILCompilerVersion, nuGetFeedUrl);
403+
else
404+
builder.UseCoreRtNuGet(ilCompilerVersion, nuGetFeedUrl);
405+
406+
var runtime = runtimeMoniker.GetRuntime();
407+
builder.TargetFrameworkMoniker(runtime.MsBuildMoniker);
408+
409+
return baseJob.WithRuntime(runtime).WithToolchain(builder.ToToolchain());
410+
}
411+
411412
private static Job MakeMonoAOTLLVMJob(Job baseJob, CommandLineOptions options, string msBuildMoniker)
412413
{
413414
var monoAotLLVMRuntime = new MonoAotLLVMRuntime(aotCompilerPath: options.AOTCompilerPath, msBuildMoniker: msBuildMoniker);

src/BenchmarkDotNet/Environments/Runtimes/CoreRtRuntime.cs

+2-31
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,11 @@
11
using BenchmarkDotNet.Jobs;
22
using BenchmarkDotNet.Portability;
33
using System;
4-
using System.Linq;
54

65
namespace BenchmarkDotNet.Environments
76
{
87
public class CoreRtRuntime : Runtime
98
{
10-
/// <summary>
11-
/// CoreRT compiled as netcoreapp2.0
12-
/// </summary>
13-
public static readonly CoreRtRuntime CoreRt20 = new CoreRtRuntime(RuntimeMoniker.CoreRt20, "netcoreapp2.0", "CoreRT 2.0");
14-
/// <summary>
15-
/// CoreRT compiled as netcoreapp2.1
16-
/// </summary>
17-
public static readonly CoreRtRuntime CoreRt21 = new CoreRtRuntime(RuntimeMoniker.CoreRt21, "netcoreapp2.1", "CoreRT 2.1");
18-
/// <summary>
19-
/// CoreRT compiled as netcoreapp2.2
20-
/// </summary>
21-
public static readonly CoreRtRuntime CoreRt22 = new CoreRtRuntime(RuntimeMoniker.CoreRt22, "netcoreapp2.2", "CoreRT 2.2");
22-
/// <summary>
23-
/// CoreRT compiled as netcoreapp3.0
24-
/// </summary>
25-
public static readonly CoreRtRuntime CoreRt30 = new CoreRtRuntime(RuntimeMoniker.CoreRt30, "netcoreapp3.0", "CoreRT 3.0");
26-
/// <summary>
27-
/// CoreRT compiled as netcoreapp3.1
28-
/// </summary>
29-
public static readonly CoreRtRuntime CoreRt31 = new CoreRtRuntime(RuntimeMoniker.CoreRt31, "netcoreapp3.1", "CoreRT 3.1");
309
/// <summary>
3110
/// CoreRT compiled as net5.0
3211
/// </summary>
@@ -35,10 +14,8 @@ public class CoreRtRuntime : Runtime
3514
/// CoreRT compiled as net6.0
3615
/// </summary>
3716
public static readonly CoreRtRuntime CoreRt60 = new CoreRtRuntime(RuntimeMoniker.CoreRt60, "net6.0", "CoreRT 6.0");
38-
/// <summary>
39-
/// CoreRT compiled as net7.0
40-
/// </summary>
41-
public static readonly CoreRtRuntime CoreRt70 = new CoreRtRuntime(RuntimeMoniker.CoreRt70, "net7.0", "CoreRT 7.0");
17+
18+
public override bool IsAOT => true;
4219

4320
private CoreRtRuntime(RuntimeMoniker runtimeMoniker, string msBuildMoniker, string displayName)
4421
: base(runtimeMoniker, msBuildMoniker, displayName)
@@ -59,14 +36,8 @@ public static CoreRtRuntime GetCurrentVersion()
5936

6037
switch (version)
6138
{
62-
case Version v when v.Major == 2 && v.Minor == 0: return CoreRt20;
63-
case Version v when v.Major == 2 && v.Minor == 1: return CoreRt21;
64-
case Version v when v.Major == 2 && v.Minor == 2: return CoreRt22;
65-
case Version v when v.Major == 3 && v.Minor == 0: return CoreRt30;
66-
case Version v when v.Major == 3 && v.Minor == 1: return CoreRt31;
6739
case Version v when v.Major == 5 && v.Minor == 0: return CoreRt50;
6840
case Version v when v.Major == 6 && v.Minor == 0: return CoreRt60;
69-
case Version v when v.Major == 7 && v.Minor == 0: return CoreRt70;
7041
default:
7142
return new CoreRtRuntime(RuntimeMoniker.NotRecognized, $"net{version.Major}.{version.Minor}", $"CoreRT {version.Major}.{version.Minor}");
7243
}

src/BenchmarkDotNet/Environments/Runtimes/MonoAotLLVMRuntime.cs

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ public class MonoAotLLVMRuntime : Runtime, IEquatable<MonoAotLLVMRuntime>
1313

1414
public FileInfo AOTCompilerPath { get; }
1515

16+
public override bool IsAOT => true;
17+
1618
/// <summary>
1719
/// creates new instance of MonoAotLLVMRuntime
1820
/// </summary>

src/BenchmarkDotNet/Environments/Runtimes/MonoRuntime.cs

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ public class MonoRuntime : Runtime, IEquatable<MonoRuntime>
1111

1212
public string AotArgs { get; }
1313

14+
public override bool IsAOT => !string.IsNullOrEmpty(AotArgs);
15+
1416
public string MonoBclPath { get; }
1517

1618
private MonoRuntime(string name) : base(RuntimeMoniker.Mono, "mono", name) { }

0 commit comments

Comments
 (0)