Skip to content

Commit a3b4236

Browse files
BrzVladtimcassell
andauthored
Add support for composite r2r runs (#2967)
* Add support for composite r2r runs This is achieved by using already existing properties in the sdk: PublishReadyToRun and PublishReadyToRunComposite. The compositer2r toolchain adds these properties to a standar project template. In order to test with custom built runtime, the toolchain reuses the already existing `customruntimepack` and `aotcompilerpath` bdn args. Example command used locally from microbenchmarks project: dotnet run -c Release -f net10.0 --runtimes compositer2r10_0 --filter "System.Tests.Perf_Int32.TryFormat" --customruntimepack /home/vbrezae/runtime3/artifacts/bin/microsoft.netcore.app.runtime.linux-arm64/Release/ --aotcompilerpath /home/vbrezae/runtime3/artifacts/packages/Release/Shipping/crossgen2pack/ * Fix build * Review * Apply review * Add integration test This only checks that using r2r runtime builds and runs. We are not checking at runtime that we are actually running r2r code. * new review * Increase build timeout. --------- Co-authored-by: Tim Cassell <cassell.timothy@gmail.com>
1 parent b956aed commit a3b4236

12 files changed

Lines changed: 372 additions & 1 deletion

File tree

src/BenchmarkDotNet.Annotations/Jobs/RuntimeMoniker.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,5 +248,25 @@ public enum RuntimeMoniker
248248
/// .NET 11 using MonoVM (not CLR which is the default)
249249
/// </summary>
250250
Mono11_0,
251+
252+
/// <summary>
253+
/// .NET 8 CLR with composite ReadyToRun compilation
254+
/// </summary>
255+
R2R80,
256+
257+
/// <summary>
258+
/// .NET 9 CLR with composite ReadyToRun compilation
259+
/// </summary>
260+
R2R90,
261+
262+
/// <summary>
263+
/// .NET 10 CLR with composite ReadyToRun compilation
264+
/// </summary>
265+
R2R10_0,
266+
267+
/// <summary>
268+
/// .NET 11 CLR with composite ReadyToRun compilation
269+
/// </summary>
270+
R2R11_0,
251271
}
252272
}

src/BenchmarkDotNet.Diagnostics.dotMemory/DotMemoryDiagnoser.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,10 @@ internal override bool IsSupported(RuntimeMoniker runtimeMoniker)
8787
case RuntimeMoniker.Net90:
8888
case RuntimeMoniker.Net10_0:
8989
case RuntimeMoniker.Net11_0:
90+
case RuntimeMoniker.R2R80:
91+
case RuntimeMoniker.R2R90:
92+
case RuntimeMoniker.R2R10_0:
93+
case RuntimeMoniker.R2R11_0:
9094
return true;
9195
case RuntimeMoniker.NotRecognized:
9296
case RuntimeMoniker.Mono:

src/BenchmarkDotNet.Diagnostics.dotTrace/DotTraceDiagnoser.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ internal override bool IsSupported(RuntimeMoniker runtimeMoniker)
9090
case RuntimeMoniker.Net90:
9191
case RuntimeMoniker.Net10_0:
9292
case RuntimeMoniker.Net11_0:
93+
case RuntimeMoniker.R2R80:
94+
case RuntimeMoniker.R2R90:
95+
case RuntimeMoniker.R2R10_0:
96+
case RuntimeMoniker.R2R11_0:
9397
return true;
9498
case RuntimeMoniker.NotRecognized:
9599
case RuntimeMoniker.Mono:

src/BenchmarkDotNet/ConsoleArguments/ConfigParser.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using BenchmarkDotNet.Loggers;
1919
using BenchmarkDotNet.Portability;
2020
using BenchmarkDotNet.Reports;
21+
using BenchmarkDotNet.Toolchains.R2R;
2122
using BenchmarkDotNet.Toolchains.CoreRun;
2223
using BenchmarkDotNet.Toolchains.CsProj;
2324
using BenchmarkDotNet.Toolchains.DotNetCli;
@@ -641,6 +642,12 @@ private static Job CreateJobForGivenRuntime(Job baseJob, string runtimeId, Comma
641642
case RuntimeMoniker.Mono11_0:
642643
return MakeMonoJob(baseJob, options, MonoRuntime.Mono11_0);
643644

645+
case RuntimeMoniker.R2R80:
646+
case RuntimeMoniker.R2R90:
647+
case RuntimeMoniker.R2R10_0:
648+
case RuntimeMoniker.R2R11_0:
649+
return CreateR2RJob(baseJob, options, runtimeMoniker.GetRuntime());
650+
644651
default:
645652
throw new NotSupportedException($"Runtime {runtimeId} is not supported");
646653
}
@@ -703,6 +710,21 @@ private static Job MakeMonoAOTLLVMJob(Job baseJob, CommandLineOptions options, s
703710
return baseJob.WithRuntime(monoAotLLVMRuntime).WithToolchain(toolChain).WithId(monoAotLLVMRuntime.Name);
704711
}
705712

713+
private static Job CreateR2RJob(Job baseJob, CommandLineOptions options, Runtime runtime)
714+
{
715+
var toolChain = R2RToolchain.From(
716+
new NetCoreAppSettings(
717+
targetFrameworkMoniker: runtime.MsBuildMoniker,
718+
runtimeFrameworkVersion: null,
719+
name: runtime.Name,
720+
customDotNetCliPath: options.CliPath?.FullName,
721+
packagesPath: options.RestorePath?.FullName,
722+
customRuntimePack: options.CustomRuntimePack,
723+
aotCompilerPath: options.AOTCompilerPath != null ? options.AOTCompilerPath.ToString() : null));
724+
725+
return baseJob.WithRuntime(runtime).WithToolchain(toolChain).WithId(runtime.Name);
726+
}
727+
706728
private static Job MakeWasmJob(Job baseJob, CommandLineOptions options, string msBuildMoniker, RuntimeMoniker moniker)
707729
{
708730
bool wasmAot = options.AOTCompilerMode == MonoAotCompilerMode.wasm;
@@ -827,4 +849,4 @@ internal static bool TryParse(string runtime, out RuntimeMoniker runtimeMoniker)
827849
return Enum.TryParse(runtime.Replace('.', '_'), ignoreCase: true, out runtimeMoniker);
828850
}
829851
}
830-
}
852+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using BenchmarkDotNet.Jobs;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Text;
5+
6+
namespace BenchmarkDotNet.Environments
7+
{
8+
public class R2RRuntime : Runtime
9+
{
10+
public static readonly R2RRuntime Net80 = new R2RRuntime(RuntimeMoniker.R2R80, "net8.0", "R2R 8.0");
11+
public static readonly R2RRuntime Net90 = new R2RRuntime(RuntimeMoniker.R2R90, "net9.0", "R2R 9.0");
12+
public static readonly R2RRuntime Net10_0 = new R2RRuntime(RuntimeMoniker.R2R10_0, "net10.0", "R2R 10.0");
13+
public static readonly R2RRuntime Net11_0 = new R2RRuntime(RuntimeMoniker.R2R11_0, "net11.0", "R2R 11.0");
14+
15+
private R2RRuntime(RuntimeMoniker runtimeMoniker, string msBuildMoniker, string displayName)
16+
: base(runtimeMoniker, msBuildMoniker, displayName)
17+
{
18+
}
19+
}
20+
}

src/BenchmarkDotNet/Extensions/RuntimeMonikerExtensions.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@ internal static Runtime GetRuntime(this RuntimeMoniker runtimeMoniker)
7474
return MonoRuntime.Mono10_0;
7575
case RuntimeMoniker.Mono11_0:
7676
return MonoRuntime.Mono11_0;
77+
case RuntimeMoniker.R2R80:
78+
return R2RRuntime.Net80;
79+
case RuntimeMoniker.R2R90:
80+
return R2RRuntime.Net90;
81+
case RuntimeMoniker.R2R10_0:
82+
return R2RRuntime.Net10_0;
83+
case RuntimeMoniker.R2R11_0:
84+
return R2RRuntime.Net11_0;
7785
default:
7886
throw new ArgumentOutOfRangeException(nameof(runtimeMoniker), runtimeMoniker, "Runtime Moniker not supported");
7987
}
@@ -127,6 +135,10 @@ internal static Runtime GetRuntime(this RuntimeMoniker runtimeMoniker)
127135
RuntimeMoniker.MonoAOTLLVMNet90 => new Version(9, 0),
128136
RuntimeMoniker.MonoAOTLLVMNet10_0 => new Version(10, 0),
129137
RuntimeMoniker.MonoAOTLLVMNet11_0 => new Version(11, 0),
138+
RuntimeMoniker.R2R80 => new Version(8, 0),
139+
RuntimeMoniker.R2R90 => new Version(9, 0),
140+
RuntimeMoniker.R2R10_0 => new Version(10, 0),
141+
RuntimeMoniker.R2R11_0 => new Version(11, 0),
130142
_ => throw new NotImplementedException($"{nameof(GetRuntimeVersion)} not implemented for {runtimeMoniker}")
131143
};
132144
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<Project Sdk="Microsoft.NET.Sdk" DefaultTarget="Publish">
2+
3+
<!-- Properties same as standard CsProj.txt template -->
4+
<PropertyGroup>
5+
<ImportDirectoryBuildProps>false</ImportDirectoryBuildProps>
6+
<ImportDirectoryBuildTargets>false</ImportDirectoryBuildTargets>
7+
<AssemblyTitle>$PROGRAMNAME$</AssemblyTitle>
8+
<TargetFrameworks>$TFM$</TargetFrameworks>
9+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
10+
<PlatformTarget>$PLATFORM$</PlatformTarget>
11+
<AssemblyName>$PROGRAMNAME$</AssemblyName>
12+
<OutputType>Exe</OutputType>
13+
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
14+
<!-- Usage of System.Random can cause compilation errors if Code Analysis warnings are treated as Errors -->
15+
<CodeAnalysisTreatWarningsAsErrors>false</CodeAnalysisTreatWarningsAsErrors>
16+
<!-- disabled due to https://github.com/dotnet/roslyn/issues/59421 -->
17+
<DebugSymbols>false</DebugSymbols>
18+
<UseSharedCompilation>false</UseSharedCompilation>
19+
<CodeAnalysisRuleSet></CodeAnalysisRuleSet>
20+
<RunAnalyzers>false</RunAnalyzers>
21+
<Deterministic>true</Deterministic>
22+
<!-- needed for custom build configurations (only "Release" builds are optimized by default) -->
23+
<Optimize Condition=" '$(Configuration)' != 'Debug' ">true</Optimize>
24+
<!-- we set LangVersion after any copied settings which might contain LangVersion copied from the benchmarks project -->
25+
<LangVersion Condition="'$(LangVersion)' == '' Or ($([System.Char]::IsDigit('$(LangVersion)', 0)) And '$(LangVersion)' &lt; '7.3')">latest</LangVersion>
26+
<!-- fix for NETSDK1150: https://docs.microsoft.com/en-us/dotnet/core/compatibility/sdk/5.0/referencing-executable-generates-error -->
27+
<ValidateExecutableReferencesMatchSelfContained>false</ValidateExecutableReferencesMatchSelfContained>
28+
<!-- Suppress warning for nuget package used in old (unsupported) tfm. -->
29+
<SuppressTfmSupportBuildWarnings>true</SuppressTfmSupportBuildWarnings>
30+
<StartupObject>BenchmarkDotNet.Autogenerated.UniqueProgramName</StartupObject>
31+
<!-- workaround for 'Found multiple publish output files with the same relative path.' error -->
32+
<ErrorOnDuplicatePublishOutputFiles>false</ErrorOnDuplicatePublishOutputFiles>
33+
</PropertyGroup>
34+
35+
<PropertyGroup>
36+
<SelfContained>true</SelfContained>
37+
<RuntimeIdentifier>$RUNTIMEIDENTIFIER$</RuntimeIdentifier>
38+
<PublishReadyToRun>true</PublishReadyToRun>
39+
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
40+
</PropertyGroup>
41+
<ItemGroup>
42+
<!-- Temporary fix until https://github.com/dotnet/sdk/pull/52296 is resolved -->
43+
<PublishReadyToRunCompositeExclusions Include="Dia2Lib.dll" />
44+
<PublishReadyToRunCompositeExclusions Include="TraceReloggerLib.dll" />
45+
</ItemGroup>
46+
47+
<ItemGroup>
48+
<Compile Include="$CODEFILENAME$" Exclude="bin\**;obj\**;**\*.xproj;packages\**" />
49+
</ItemGroup>
50+
51+
<ItemGroup>
52+
<ProjectReference Include="$CSPROJPATH$" />
53+
</ItemGroup>
54+
55+
<!-- Begin copied settings from benchmarks project -->
56+
$COPIEDSETTINGS$
57+
<!-- End copied settings -->
58+
59+
<!-- The purpose of this project is to publish the app with r2r composite using a custom runtime pack and a custom crossgen2, built locally -->
60+
61+
<Target Name="TrickRuntimePackLocation" AfterTargets="ProcessFrameworkReferences">
62+
<ItemGroup>
63+
<RuntimePack>
64+
<PackageDirectory>$RUNTIMEPACK$</PackageDirectory>
65+
</RuntimePack>
66+
<Crossgen2Pack>
67+
<PackageDirectory>$CROSSGEN2PACK$</PackageDirectory>
68+
</Crossgen2Pack>
69+
</ItemGroup>
70+
</Target>
71+
</Project>

src/BenchmarkDotNet/Toolchains/Executor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ private static ProcessStartInfo CreateStartInfo(BenchmarkCase benchmarkCase, Art
140140
case ClrRuntime _:
141141
case CoreRuntime _:
142142
case NativeAotRuntime _:
143+
case R2RRuntime _:
143144
start.FileName = exePath;
144145
start.Arguments = args;
145146
break;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System.IO;
2+
using System.Text;
3+
using System.Xml;
4+
using BenchmarkDotNet.Detectors;
5+
using BenchmarkDotNet.Extensions;
6+
using BenchmarkDotNet.Helpers;
7+
using BenchmarkDotNet.Loggers;
8+
using BenchmarkDotNet.Running;
9+
using BenchmarkDotNet.Toolchains.CsProj;
10+
using BenchmarkDotNet.Toolchains.DotNetCli;
11+
12+
namespace BenchmarkDotNet.Toolchains.R2R
13+
{
14+
public class R2RGenerator : CsProjGenerator
15+
{
16+
private readonly string CustomRuntimePack;
17+
private readonly string Crossgen2Pack;
18+
19+
public R2RGenerator(string targetFrameworkMoniker, string cliPath, string packagesPath, string customRuntimePack, string crossgen2Pack)
20+
: base(targetFrameworkMoniker, cliPath, packagesPath, runtimeFrameworkVersion: null)
21+
{
22+
CustomRuntimePack = customRuntimePack;
23+
Crossgen2Pack = crossgen2Pack;
24+
BenchmarkRunCallType = Code.CodeGenBenchmarkRunCallType.Direct;
25+
}
26+
27+
protected override void GenerateProject(BuildPartition buildPartition, ArtifactsPaths artifactsPaths, ILogger logger)
28+
{
29+
BenchmarkCase benchmark = buildPartition.RepresentativeBenchmarkCase;
30+
var projectFile = GetProjectFilePath(benchmark.Descriptor.Type, logger);
31+
32+
var xmlDoc = new XmlDocument();
33+
xmlDoc.Load(projectFile.FullName);
34+
var (customProperties, sdkName) = GetSettingsThatNeedToBeCopied(xmlDoc, projectFile);
35+
36+
string content = new StringBuilder(ResourceHelper.LoadTemplate("R2RCsProj.txt"))
37+
.Replace("$PLATFORM$", buildPartition.Platform.ToConfig())
38+
.Replace("$CODEFILENAME$", Path.GetFileName(artifactsPaths.ProgramCodePath))
39+
.Replace("$CSPROJPATH$", projectFile.FullName)
40+
.Replace("$TFM$", TargetFrameworkMoniker)
41+
.Replace("$PROGRAMNAME$", artifactsPaths.ProgramName)
42+
.Replace("$COPIEDSETTINGS$", customProperties)
43+
.Replace("$SDKNAME$", sdkName)
44+
.Replace("$RUNTIMEPACK$", CustomRuntimePack)
45+
.Replace("$CROSSGEN2PACK$", Crossgen2Pack)
46+
.Replace("$RUNTIMEIDENTIFIER$", CustomDotNetCliToolchainBuilder.GetPortableRuntimeIdentifier())
47+
.ToString();
48+
49+
File.WriteAllText(artifactsPaths.ProjectFilePath, content);
50+
51+
GatherReferences(buildPartition, artifactsPaths, logger);
52+
}
53+
54+
protected override string GetExecutableExtension() => OsDetector.ExecutableExtension;
55+
56+
protected override string GetBinariesDirectoryPath(string buildArtifactsDirectoryPath, string configuration)
57+
=> Path.Combine(buildArtifactsDirectoryPath, "bin", configuration, TargetFrameworkMoniker, CustomDotNetCliToolchainBuilder.GetPortableRuntimeIdentifier(), "publish");
58+
}
59+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using BenchmarkDotNet.Characteristics;
2+
using BenchmarkDotNet.Running;
3+
using BenchmarkDotNet.Toolchains.CsProj;
4+
using BenchmarkDotNet.Toolchains.DotNetCli;
5+
using BenchmarkDotNet.Validators;
6+
using JetBrains.Annotations;
7+
using System;
8+
using System.Collections.Generic;
9+
10+
namespace BenchmarkDotNet.Toolchains.R2R
11+
{
12+
[PublicAPI]
13+
public class R2RToolchain : CsProjCoreToolchain, IEquatable<R2RToolchain>
14+
{
15+
[PublicAPI] public static readonly IToolchain R2R80 = From(new NetCoreAppSettings("net8.0", null, "R2R 8.0"));
16+
[PublicAPI] public static readonly IToolchain R2R90 = From(new NetCoreAppSettings("net9.0", null, "R2R 9.0"));
17+
[PublicAPI] public static readonly IToolchain R2R10_0 = From(new NetCoreAppSettings("net10.0", null, "R2R 10.0"));
18+
[PublicAPI] public static readonly IToolchain R2R11_0 = From(new NetCoreAppSettings("net11.0", null, "R2R 11.0"));
19+
20+
private readonly string _customDotNetCliPath;
21+
private R2RToolchain(string name, IGenerator generator, IBuilder builder, IExecutor executor, string customDotNetCliPath)
22+
: base(name, generator, builder, executor, customDotNetCliPath)
23+
{
24+
_customDotNetCliPath = customDotNetCliPath;
25+
}
26+
27+
[PublicAPI]
28+
public static new IToolchain From(NetCoreAppSettings settings)
29+
=> new R2RToolchain(settings.Name,
30+
new R2RGenerator(settings.TargetFrameworkMoniker, settings.CustomDotNetCliPath, settings.PackagesPath, settings.CustomRuntimePack, settings.AOTCompilerPath),
31+
new DotNetCliPublisher(settings.TargetFrameworkMoniker, settings.CustomDotNetCliPath),
32+
new Executor(),
33+
settings.CustomDotNetCliPath);
34+
35+
public override IEnumerable<ValidationError> Validate(BenchmarkCase benchmarkCase, IResolver resolver)
36+
{
37+
foreach (var validationError in DotNetSdkValidator.ValidateCoreSdks(_customDotNetCliPath, benchmarkCase))
38+
{
39+
yield return validationError;
40+
}
41+
}
42+
43+
public override bool Equals(object obj) => obj is R2RToolchain typed && Equals(typed);
44+
45+
public bool Equals(R2RToolchain other) => Generator.Equals(other.Generator);
46+
47+
public override int GetHashCode() => Generator.GetHashCode();
48+
}
49+
}

0 commit comments

Comments
 (0)