diff --git a/src/BenchmarkDotNet/Environments/Runtimes/CoreRuntime.cs b/src/BenchmarkDotNet/Environments/Runtimes/CoreRuntime.cs index 954a8ac7dc..472b629405 100644 --- a/src/BenchmarkDotNet/Environments/Runtimes/CoreRuntime.cs +++ b/src/BenchmarkDotNet/Environments/Runtimes/CoreRuntime.cs @@ -99,11 +99,26 @@ internal static bool TryGetVersion(out Version? version) return true; } - var systemPrivateCoreLib = FileVersionInfo.GetVersionInfo(typeof(object).Assembly.Location); - // systemPrivateCoreLib.Product*Part properties return 0 so we have to implement some ugly parsing... - if (TryGetVersionFromProductInfo(systemPrivateCoreLib.ProductVersion, systemPrivateCoreLib.ProductName, out version)) + string coreclrLocation = typeof(object).Assembly.Location; + // Single-file publish has empty assembly location. + if (!string.IsNullOrEmpty(coreclrLocation)) { - return true; + var systemPrivateCoreLib = FileVersionInfo.GetVersionInfo(coreclrLocation); + // systemPrivateCoreLib.Product*Part properties return 0 so we have to implement some ugly parsing... + if (TryGetVersionFromProductInfo(systemPrivateCoreLib.ProductVersion, systemPrivateCoreLib.ProductName, out version)) + { + return true; + } + } + else + { + // .Net Core 3.X supports single-file publish, .Net Core 2.X does not. + // .Net Core 3.X fixed the version in FrameworkDescription, so we don't need to handle the case of 4.6.x in this branch. + var frameworkDescriptionVersion = GetParsableVersionPart(GetVersionFromFrameworkDescription()); + if (Version.TryParse(frameworkDescriptionVersion, out version)) + { + return true; + } } // it's OK to use this method only after checking the previous ones @@ -125,6 +140,14 @@ internal static bool TryGetVersion(out Version? version) return false; } + internal static string GetVersionFromFrameworkDescription() + { + // .NET 10.0.0-preview.5.25277.114 -> 10.0.0-preview.5.25277.114 + // .NET Core 3.1.32 -> 3.1.32 + string frameworkDescription = System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription; + return new string(frameworkDescription.SkipWhile(c => !char.IsDigit(c)).ToArray()); + } + // sample input: // for dotnet run: C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.1.12\ // for dotnet publish: C:\Users\adsitnik\source\repos\ConsoleApp25\ConsoleApp25\bin\Release\netcoreapp2.0\win-x64\publish\ diff --git a/src/BenchmarkDotNet/Portability/RuntimeInformation.cs b/src/BenchmarkDotNet/Portability/RuntimeInformation.cs index fb5150db2d..9b8348a125 100644 --- a/src/BenchmarkDotNet/Portability/RuntimeInformation.cs +++ b/src/BenchmarkDotNet/Portability/RuntimeInformation.cs @@ -2,22 +2,16 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.IO; using System.Linq; using System.Management; using System.Reflection; using System.Runtime.InteropServices; using System.Text.RegularExpressions; using BenchmarkDotNet.Detectors; -using BenchmarkDotNet.Detectors.Cpu; using BenchmarkDotNet.Environments; using BenchmarkDotNet.Extensions; using BenchmarkDotNet.Helpers; -using JetBrains.Annotations; -using Microsoft.Win32; -using Perfolizer.Helpers; using static System.Runtime.InteropServices.RuntimeInformation; -using RuntimeEnvironment = Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment; namespace BenchmarkDotNet.Portability { @@ -48,12 +42,6 @@ internal static class RuntimeInformation FrameworkDescription.StartsWith(".NET Framework", StringComparison.OrdinalIgnoreCase); #endif - public static readonly bool IsNetNative = FrameworkDescription.StartsWith(".NET Native", StringComparison.OrdinalIgnoreCase); - - public static readonly bool IsNetCore = - ((Environment.Version.Major >= 5) || FrameworkDescription.StartsWith(".NET Core", StringComparison.OrdinalIgnoreCase)) - && !string.IsNullOrEmpty(typeof(object).Assembly.Location); - #if NET6_0_OR_GREATER [System.Runtime.Versioning.SupportedOSPlatformGuard("browser")] public static readonly bool IsWasm = OperatingSystem.IsBrowser(); @@ -61,13 +49,8 @@ internal static class RuntimeInformation public static readonly bool IsWasm = IsOSPlatform(OSPlatform.Create("BROWSER")); #endif - public static readonly bool IsNativeAOT = - Environment.Version.Major >= 5 - && string.IsNullOrEmpty(typeof(object).Assembly.Location) // it's merged to a single .exe and .Location returns null - && !IsWasm; // Wasm also returns "" for assembly locations - #if NETSTANDARD2_0 - public static readonly bool IsAot = IsAotMethod(); + public static readonly bool IsAot = IsAotMethod() || FrameworkDescription.StartsWith(".NET Native", StringComparison.OrdinalIgnoreCase); private static bool IsAotMethod() { @@ -88,6 +71,16 @@ private static bool IsAotMethod() public static readonly bool IsAot = !System.Runtime.CompilerServices.RuntimeFeature.IsDynamicCodeCompiled; #endif + public static bool IsNetCore + => ((Environment.Version.Major >= 5) || FrameworkDescription.StartsWith(".NET Core", StringComparison.OrdinalIgnoreCase)) + && !IsAot; + + public static bool IsNativeAOT + => Environment.Version.Major >= 5 + && IsAot + && !IsWasm && !IsMono; // Wasm and MonoAOTLLVM are also AOT + + public static readonly bool IsTieredJitEnabled = IsNetCore && (Environment.Version.Major < 3 @@ -171,24 +164,21 @@ private static string GetNetCoreVersion() { return $".NET {Environment.Version}"; } - else - { - var coreclrAssemblyInfo = FileVersionInfo.GetVersionInfo(typeof(object).GetTypeInfo().Assembly.Location); - var corefxAssemblyInfo = FileVersionInfo.GetVersionInfo(typeof(Regex).GetTypeInfo().Assembly.Location); - if (CoreRuntime.TryGetVersion(out var version) && version >= new Version(5, 0)) - { - // after the merge of dotnet/corefx and dotnet/coreclr into dotnet/runtime the version should always be the same - Debug.Assert(coreclrAssemblyInfo.FileVersion == corefxAssemblyInfo.FileVersion); - - return $".NET {version} ({coreclrAssemblyInfo.FileVersion})"; - } - else - { - string runtimeVersion = version != default ? version.ToString() : Unknown; + return CoreRuntime.TryGetVersion(out var version) && version.Major >= 5 + ? $".NET {version} ({GetDetailedVersion()})" + : $".NET Core {version?.ToString() ?? Unknown} ({GetDetailedVersion()})"; - return $".NET Core {runtimeVersion} (CoreCLR {coreclrAssemblyInfo.FileVersion}, CoreFX {corefxAssemblyInfo.FileVersion})"; - } + string GetDetailedVersion() + { + string coreclrLocation = typeof(object).GetTypeInfo().Assembly.Location; + // Single-file publish has empty assembly location. + if (string.IsNullOrEmpty(coreclrLocation)) + return CoreRuntime.GetVersionFromFrameworkDescription(); + // .Net Core 2.X has confusing FrameworkDescription like 4.6.X. + if (version?.Major >= 3) + return $"{CoreRuntime.GetVersionFromFrameworkDescription()}, {FileVersionInfo.GetVersionInfo(coreclrLocation).FileVersion}"; + return FileVersionInfo.GetVersionInfo(coreclrLocation).FileVersion; } } @@ -271,7 +261,7 @@ internal static string GetJitInfo() { if (IsNativeAOT) return "NativeAOT"; - if (IsNetNative || IsAot) + if (IsAot) return "AOT"; if (IsMono || IsWasm) return ""; // There is no helpful information about JIT on Mono