Skip to content

Commit 82f03f4

Browse files
authored
Add support for .NET SDK that uses Mono instead CLR as a default VM (#2230)
* add a failing test * fix current runtime detection for Mono SDK unify the order of runtime checks with other helper methods * delay the creation to avoid exceptions at DisassemblyDiagnoser ctor * use different toolchain when current .NET SDK uses MonoVM
1 parent bf8b531 commit 82f03f4

File tree

6 files changed

+58
-23
lines changed

6 files changed

+58
-23
lines changed

src/BenchmarkDotNet/Disassemblers/SameArchitectureDisassembler.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,21 @@
11
using BenchmarkDotNet.Diagnosers;
22
using BenchmarkDotNet.Environments;
33
using BenchmarkDotNet.Portability;
4-
using BenchmarkDotNet.Toolchains;
54
using System;
65

76
namespace BenchmarkDotNet.Disassemblers
87
{
98
internal class SameArchitectureDisassembler
109
{
1110
private readonly DisassemblyDiagnoserConfig config;
12-
private readonly ClrMdV2Disassembler clrMdV2Disassembler;
11+
private ClrMdV2Disassembler? clrMdV2Disassembler;
1312

14-
internal SameArchitectureDisassembler(DisassemblyDiagnoserConfig config)
15-
{
16-
this.config = config;
17-
clrMdV2Disassembler = CreateDisassemblerForCurrentArchitecture();
18-
}
13+
internal SameArchitectureDisassembler(DisassemblyDiagnoserConfig config) => this.config = config;
1914

2015
internal DisassemblyResult Disassemble(DiagnoserActionParameters parameters)
21-
=> clrMdV2Disassembler.AttachAndDisassemble(BuildDisassemblerSettings(parameters));
16+
// delay the creation to avoid exceptions at DisassemblyDiagnoser ctor
17+
=> (clrMdV2Disassembler ??= CreateDisassemblerForCurrentArchitecture())
18+
.AttachAndDisassemble(BuildDisassemblerSettings(parameters));
2219

2320
private static ClrMdV2Disassembler CreateDisassemblerForCurrentArchitecture()
2421
=> RuntimeInformation.GetCurrentPlatform() switch

src/BenchmarkDotNet/Environments/Runtimes/CoreRuntime.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ private CoreRuntime(RuntimeMoniker runtimeMoniker, string msBuildMoniker, string
3131
public bool IsPlatformSpecific => MsBuildMoniker.IndexOf('-') > 0;
3232

3333
/// <summary>
34-
/// use this method if you want to target .NET Core version not supported by current version of BenchmarkDotNet. Example: .NET Core 10
34+
/// use this method if you want to target .NET version not supported by current version of BenchmarkDotNet. Example: .NET 10
3535
/// </summary>
36-
/// <param name="msBuildMoniker">msbuild moniker, example: netcoreapp10.0</param>
36+
/// <param name="msBuildMoniker">msbuild moniker, example: net10.0</param>
3737
/// <param name="displayName">display name used by BDN to print the results</param>
3838
/// <returns>new runtime information</returns>
3939
public static CoreRuntime CreateForNewVersion(string msBuildMoniker, string displayName)

src/BenchmarkDotNet/Environments/Runtimes/MonoRuntime.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ namespace BenchmarkDotNet.Environments
55
{
66
public class MonoRuntime : Runtime, IEquatable<MonoRuntime>
77
{
8-
public static readonly MonoRuntime Default = new MonoRuntime("Mono");
9-
public static readonly MonoRuntime Mono60 = new MonoRuntime("Mono with .NET 6.0", RuntimeMoniker.Mono60, "net6.0", isDotNetBuiltIn: true);
10-
public static readonly MonoRuntime Mono70 = new MonoRuntime("Mono with .NET 7.0", RuntimeMoniker.Mono70, "net7.0", isDotNetBuiltIn: true);
11-
public static readonly MonoRuntime Mono80 = new MonoRuntime("Mono with .NET 8.0", RuntimeMoniker.Mono80, "net8.0", isDotNetBuiltIn: true);
8+
public static readonly MonoRuntime Default = new ("Mono");
9+
public static readonly MonoRuntime Mono60 = new ("Mono with .NET 6.0", RuntimeMoniker.Mono60, "net6.0", isDotNetBuiltIn: true);
10+
public static readonly MonoRuntime Mono70 = new ("Mono with .NET 7.0", RuntimeMoniker.Mono70, "net7.0", isDotNetBuiltIn: true);
11+
public static readonly MonoRuntime Mono80 = new ("Mono with .NET 8.0", RuntimeMoniker.Mono80, "net8.0", isDotNetBuiltIn: true);
1212

1313
public string CustomPath { get; }
1414

@@ -43,5 +43,17 @@ public bool Equals(MonoRuntime other)
4343

4444
public override int GetHashCode()
4545
=> HashCode.Combine(base.GetHashCode(), Name, CustomPath, AotArgs, MonoBclPath);
46+
47+
internal static Runtime GetCurrentVersion()
48+
{
49+
Version version = Environment.Version;
50+
return version.Major switch
51+
{
52+
6 => Mono60,
53+
7 => Mono70,
54+
8 => Mono80,
55+
_ => new MonoRuntime($"Mono with .NET {version.Major}.{version.Minor}", RuntimeMoniker.NotRecognized, $"net{version.Major}.{version.Minor}", isDotNetBuiltIn: true)
56+
};
57+
}
4658
}
4759
}

src/BenchmarkDotNet/Portability/RuntimeInformation.cs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ internal static string GetRuntimeVersion()
234234

235235
return $".NET Core (Mono) {versionString}";
236236
}
237-
else if (IsMono)
237+
else if (IsOldMono)
238238
{
239239
var monoRuntimeType = Type.GetType("Mono.Runtime");
240240
var monoDisplayName = monoRuntimeType?.GetMethod("GetDisplayName", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
@@ -255,10 +255,10 @@ internal static string GetRuntimeVersion()
255255

256256
return "Mono " + version;
257257
}
258-
else if (IsNewMono)
259-
{
260-
return $"{GetNetCoreVersion()} using MonoVM";
261-
}
258+
}
259+
else if (IsNewMono)
260+
{
261+
return $"{GetNetCoreVersion()} using MonoVM";
262262
}
263263
else if (IsFullFramework)
264264
{
@@ -301,12 +301,14 @@ internal static Runtime GetCurrentRuntime()
301301
//do not change the order of conditions because it may cause incorrect determination of runtime
302302
if (IsAot && IsMono)
303303
return MonoAotLLVMRuntime.Default;
304-
if (IsMono)
304+
if (IsWasm)
305+
return WasmRuntime.Default;
306+
if (IsNewMono)
307+
return MonoRuntime.GetCurrentVersion();
308+
if (IsOldMono)
305309
return MonoRuntime.Default;
306310
if (IsFullFramework)
307311
return ClrRuntime.GetCurrentVersion();
308-
if (IsWasm)
309-
return WasmRuntime.Default;
310312
if (IsNetCore)
311313
return CoreRuntime.GetCurrentVersion();
312314
if (IsNativeAOT)

src/BenchmarkDotNet/Toolchains/ToolchainExtensions.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,25 @@ internal static IToolchain GetToolchain(this Runtime runtime, Descriptor descrip
4949
if (!string.IsNullOrEmpty(mono.AotArgs))
5050
return MonoAotToolchain.Instance;
5151
if (mono.IsDotNetBuiltIn)
52-
return MonoToolchain.From(new NetCoreAppSettings(targetFrameworkMoniker: mono.MsBuildMoniker, runtimeFrameworkVersion: null, name: mono.Name));
52+
if (RuntimeInformation.IsNewMono)
53+
{
54+
// It's a .NET SDK with Mono as default VM.
55+
// Publishing self-contained apps might not work like in https://github.com/dotnet/performance/issues/2787.
56+
// In such case, we are going to use default .NET toolchain that is just going to perform dotnet build,
57+
// which internally will result in creating Mono-based app.
58+
return mono.RuntimeMoniker switch
59+
{
60+
RuntimeMoniker.Mono60 => GetToolchain(RuntimeMoniker.Net60),
61+
RuntimeMoniker.Mono70 => GetToolchain(RuntimeMoniker.Net70),
62+
RuntimeMoniker.Mono80 => GetToolchain(RuntimeMoniker.Net80),
63+
_ => CsProjCoreToolchain.From(new NetCoreAppSettings(mono.MsBuildMoniker, null, mono.Name))
64+
};
65+
}
66+
else
67+
{
68+
return MonoToolchain.From(
69+
new NetCoreAppSettings(targetFrameworkMoniker: mono.MsBuildMoniker, runtimeFrameworkVersion: null, name: mono.Name));
70+
}
5371

5472
return RoslynToolchain.Instance;
5573

tests/BenchmarkDotNet.IntegrationTests/MonoTests.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using BenchmarkDotNet.Configs;
44
using BenchmarkDotNet.Environments;
55
using BenchmarkDotNet.Jobs;
6+
using BenchmarkDotNet.Portability;
67
using BenchmarkDotNet.Tests.XUnit;
78

89
namespace BenchmarkDotNet.IntegrationTests
@@ -28,6 +29,11 @@ public void Check()
2829
{
2930
throw new Exception("This is not Mono runtime");
3031
}
32+
33+
if (RuntimeInformation.GetCurrentRuntime() != MonoRuntime.Mono70)
34+
{
35+
throw new Exception("Incorrect runtime detection");
36+
}
3137
}
3238
}
3339
}

0 commit comments

Comments
 (0)