Skip to content
46 changes: 46 additions & 0 deletions src/BenchmarkDotNet/Extensions/RuntimeMonikerExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,51 @@ internal static Runtime GetRuntime(this RuntimeMoniker runtimeMoniker)
throw new ArgumentOutOfRangeException(nameof(runtimeMoniker), runtimeMoniker, "Runtime Moniker not supported");
}
}

internal static Version GetRuntimeVersion(this RuntimeMoniker runtimeMoniker) => runtimeMoniker switch
{
RuntimeMoniker.Net461 => new Version(4, 6, 1),
RuntimeMoniker.Net462 => new Version(4, 6, 2),
RuntimeMoniker.Net47 => new Version(4, 7),
RuntimeMoniker.Net471 => new Version(4, 7, 1),
RuntimeMoniker.Net472 => new Version(4, 7, 2),
RuntimeMoniker.Net48 => new Version(4, 8),
RuntimeMoniker.Net481 => new Version(4, 8, 1),
RuntimeMoniker.NetCoreApp20 => new Version(2, 0),
RuntimeMoniker.NetCoreApp21 => new Version(2, 1),
RuntimeMoniker.NetCoreApp22 => new Version(2, 2),
RuntimeMoniker.NetCoreApp30 => new Version(3, 0),
RuntimeMoniker.NetCoreApp31 => new Version(3, 1),
RuntimeMoniker.Net50 => new Version(5, 0),
RuntimeMoniker.Net60 => new Version(6, 0),
RuntimeMoniker.Net70 => new Version(7, 0),
RuntimeMoniker.Net80 => new Version(8, 0),
RuntimeMoniker.Net90 => new Version(9, 0),
RuntimeMoniker.Net10_0 => new Version(10, 0),
RuntimeMoniker.NativeAot60 => new Version(6, 0),
RuntimeMoniker.NativeAot70 => new Version(7, 0),
RuntimeMoniker.NativeAot80 => new Version(8, 0),
RuntimeMoniker.NativeAot90 => new Version(9, 0),
RuntimeMoniker.NativeAot10_0 => new Version(10, 0),
RuntimeMoniker.Mono60 => new Version(6, 0),
RuntimeMoniker.Mono70 => new Version(7, 0),
RuntimeMoniker.Mono80 => new Version(8, 0),
RuntimeMoniker.Mono90 => new Version(9, 0),
RuntimeMoniker.Mono10_0 => new Version(10, 0),
RuntimeMoniker.Wasm => Portability.RuntimeInformation.IsNetCore && CoreRuntime.TryGetVersion(out var version) ? version : new Version(5, 0),
RuntimeMoniker.WasmNet50 => new Version(5, 0),
RuntimeMoniker.WasmNet60 => new Version(6, 0),
RuntimeMoniker.WasmNet70 => new Version(7, 0),
RuntimeMoniker.WasmNet80 => new Version(8, 0),
RuntimeMoniker.WasmNet90 => new Version(9, 0),
RuntimeMoniker.WasmNet10_0 => new Version(10, 0),
RuntimeMoniker.MonoAOTLLVM => Portability.RuntimeInformation.IsNetCore && CoreRuntime.TryGetVersion(out var version) ? version : new Version(6, 0),
RuntimeMoniker.MonoAOTLLVMNet60 => new Version(6, 0),
RuntimeMoniker.MonoAOTLLVMNet70 => new Version(7, 0),
RuntimeMoniker.MonoAOTLLVMNet80 => new Version(8, 0),
RuntimeMoniker.MonoAOTLLVMNet90 => new Version(9, 0),
RuntimeMoniker.MonoAOTLLVMNet10_0 => new Version(10, 0),
_ => throw new NotImplementedException($"{nameof(GetRuntimeVersion)} not implemented for {runtimeMoniker}")
};
}
}
25 changes: 15 additions & 10 deletions src/BenchmarkDotNet/Running/BenchmarkRunnerClean.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using BenchmarkDotNet.Mathematics;
using BenchmarkDotNet.Reports;
using BenchmarkDotNet.Toolchains;
using BenchmarkDotNet.Toolchains.DotNetCli;
using BenchmarkDotNet.Toolchains.Parameters;
using BenchmarkDotNet.Toolchains.Results;
using BenchmarkDotNet.Validators;
Expand Down Expand Up @@ -81,17 +82,21 @@ internal static Summary[] Run(BenchmarkRunInfo[] benchmarkRunInfos)
compositeLogger.WriteLineHeader($"// ***** Found {totalBenchmarkCount} benchmark(s) in total *****");
var globalChronometer = Chronometer.Start();

var buildPartitions = BenchmarkPartitioner.CreateForBuild(supportedBenchmarks, resolver);
eventProcessor.OnStartBuildStage(buildPartitions);

var parallelBuildBenchmarks = supportedBenchmarks.Where(x => !x.Config.Options.IsSet(ConfigOptions.DisableParallelBuild)).ToArray();
var parallelBuildPartitions = BenchmarkPartitioner.CreateForBuild(parallelBuildBenchmarks, resolver);

var sequentialBuildBenchmarks = supportedBenchmarks.Where(x => x.Config.Options.IsSet(ConfigOptions.DisableParallelBuild)).ToArray();
var sequentialBuildPartitions = BenchmarkPartitioner.CreateForBuild(sequentialBuildBenchmarks, resolver);

eventProcessor.OnStartBuildStage([.. parallelBuildPartitions, .. sequentialBuildPartitions]);
var sequentialBuildPartitions = buildPartitions.Where(partition =>
partition.Benchmarks.Any(x => x.Config.Options.IsSet(ConfigOptions.DisableParallelBuild))
// .Net SDK 8+ supports ArtifactsPath for proper parallel builds.
// Older SDKs may produce builds with incorrect bindings if more than 1 partition is built in parallel.
|| (partition.RepresentativeBenchmarkCase.GetToolchain().Generator is DotNetCliGenerator
&& partition.RepresentativeBenchmarkCase.GetRuntime().RuntimeMoniker.GetRuntimeVersion().Major < 8)
)
.ToArray();
var parallelBuildPartitions = buildPartitions.Except(sequentialBuildPartitions).ToArray();

var buildResults = new Dictionary<BuildPartition, BuildResult>();
if (parallelBuildBenchmarks.Length > 0)
if (parallelBuildPartitions.Length > 0)
{
var results = BuildInParallel(compositeLogger, rootArtifactsFolderPath, parallelBuildPartitions, in globalChronometer, eventProcessor);
foreach (var kvp in results)
Expand All @@ -100,7 +105,7 @@ internal static Summary[] Run(BenchmarkRunInfo[] benchmarkRunInfos)
}
}

if (sequentialBuildBenchmarks.Length > 0)
if (sequentialBuildPartitions.Length > 0)
{
var results = BuildSequential(compositeLogger, rootArtifactsFolderPath, sequentialBuildPartitions, in globalChronometer, eventProcessor);
foreach (var kvp in results)
Expand Down Expand Up @@ -644,7 +649,7 @@ private static (BenchmarkRunInfo[], List<ValidationError>) GetSupportedBenchmark

validationErrors.AddRange(errors);

return errors.Length == 0;
return !errors.Any(error => error.IsCritical);
})
.ToArray();

Expand Down
6 changes: 3 additions & 3 deletions src/BenchmarkDotNet/Templates/WasmCsProj.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<TargetFramework>$TFM$</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<AppDir>$(MSBuildThisFileDirectory)\bin\$TFM$\browser-wasm\publish</AppDir>
<AppDir>$(PublishDir)</AppDir>
<AssemblyName>$PROGRAMNAME$</AssemblyName>
<RuntimeIdentifier>browser-wasm</RuntimeIdentifier>
<SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings>
Expand Down Expand Up @@ -50,8 +50,8 @@

<Target Name="PrepareForWasmBuild" AfterTargets="Publish">
<ItemGroup>
<WasmAssembliesToBundle Include="$(TargetDir)publish\*.dll" Condition="'$(RunAOTCompilation)' != 'true'" />
<WasmAssembliesToBundle Include="$(TargetDir)publish\*.dll" Exclude="$(TargetDir)publish\KernelTraceControl.dll" Condition="'$(RunAOTCompilation)' == 'true'" />
<WasmAssembliesToBundle Include="$(PublishDir)*.dll" Condition="'$(RunAOTCompilation)' != 'true'" />
<WasmAssembliesToBundle Include="$(PublishDir)*.dll" Exclude="$(PublishDir)KernelTraceControl.dll" Condition="'$(RunAOTCompilation)' == 'true'" />
</ItemGroup>
</Target>

Expand Down
6 changes: 3 additions & 3 deletions src/BenchmarkDotNet/Toolchains/ArtifactsPaths.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public class ArtifactsPaths
[PublicAPI] public string RootArtifactsFolderPath { get; }
[PublicAPI] public string BuildArtifactsDirectoryPath { get; }
[PublicAPI] public string BinariesDirectoryPath { get; }
[PublicAPI] public string IntermediateDirectoryPath { get; }
[PublicAPI] public string PublishDirectoryPath { get; }
[PublicAPI] public string ProgramCodePath { get; }
[PublicAPI] public string AppConfigPath { get; }
[PublicAPI] public string NuGetConfigPath { get; }
Expand All @@ -23,7 +23,7 @@ public ArtifactsPaths(
string rootArtifactsFolderPath,
string buildArtifactsDirectoryPath,
string binariesDirectoryPath,
string intermediateDirectoryPath,
string publishDirectoryPath,
string programCodePath,
string appConfigPath,
string nuGetConfigPath,
Expand All @@ -36,7 +36,7 @@ public ArtifactsPaths(
RootArtifactsFolderPath = rootArtifactsFolderPath;
BuildArtifactsDirectoryPath = buildArtifactsDirectoryPath;
BinariesDirectoryPath = binariesDirectoryPath;
IntermediateDirectoryPath = intermediateDirectoryPath;
PublishDirectoryPath = publishDirectoryPath;
ProgramCodePath = programCodePath;
AppConfigPath = appConfigPath;
NuGetConfigPath = nuGetConfigPath;
Expand Down
3 changes: 0 additions & 3 deletions src/BenchmarkDotNet/Toolchains/CsProj/CsProjGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,6 @@ protected override string GetProjectFilePath(string buildArtifactsDirectoryPath)
protected override string GetBinariesDirectoryPath(string buildArtifactsDirectoryPath, string configuration)
=> Path.Combine(buildArtifactsDirectoryPath, "bin", configuration, TargetFrameworkMoniker);

protected override string GetIntermediateDirectoryPath(string buildArtifactsDirectoryPath, string configuration)
=> Path.Combine(buildArtifactsDirectoryPath, "obj", configuration, TargetFrameworkMoniker);

[SuppressMessage("ReSharper", "StringLiteralTypo")] // R# complains about $variables$
protected override void GenerateProject(BuildPartition buildPartition, ArtifactsPaths artifactsPaths, ILogger logger)
{
Expand Down
4 changes: 3 additions & 1 deletion src/BenchmarkDotNet/Toolchains/DotNetCli/DotNetCliCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Linq;
using System.Text;
using BenchmarkDotNet.Characteristics;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Extensions;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Loggers;
Expand Down Expand Up @@ -262,10 +263,11 @@ internal static StringBuilder MaybeAppendOutputPaths(this StringBuilder stringBu
? stringBuilder
: stringBuilder
// Use AltDirectorySeparatorChar so it's not interpreted as an escaped quote `\"`.
.AppendArgument($"/p:IntermediateOutputPath=\"{artifactsPaths.IntermediateDirectoryPath}{Path.AltDirectorySeparatorChar}\"")
.AppendArgument($"/p:ArtifactsPath=\"{artifactsPaths.BuildArtifactsDirectoryPath}{Path.AltDirectorySeparatorChar}\"")
.AppendArgument($"/p:OutDir=\"{artifactsPaths.BinariesDirectoryPath}{Path.AltDirectorySeparatorChar}\"")
// OutputPath is legacy, per-project version of OutDir. We set both just in case. https://github.com/dotnet/msbuild/issues/87
.AppendArgument($"/p:OutputPath=\"{artifactsPaths.BinariesDirectoryPath}{Path.AltDirectorySeparatorChar}\"")
.AppendArgument($"/p:PublishDir=\"{artifactsPaths.PublishDirectoryPath}{Path.AltDirectorySeparatorChar}\"")
.AppendArgument(isRestore ? string.Empty : $"--output \"{artifactsPaths.BinariesDirectoryPath}{Path.AltDirectorySeparatorChar}\"");
}
}
8 changes: 4 additions & 4 deletions src/BenchmarkDotNet/Toolchains/GeneratorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ [PublicAPI] protected virtual string GetBinariesDirectoryPath(string buildArtifa
=> buildArtifactsDirectoryPath;

/// <summary>
/// returns a path where intermediate files should be found after the build (usually \obj)
/// returns a path where the publish directory should be found after the build (usually \publish)
/// </summary>
[PublicAPI]
protected virtual string GetIntermediateDirectoryPath(string buildArtifactsDirectoryPath, string configuration)
=> string.Empty;
protected virtual string GetPublishDirectoryPath(string buildArtifactsDirectoryPath, string configuration)
=> Path.Combine(buildArtifactsDirectoryPath, "publish");

/// <summary>
/// returns OS-specific executable extension
Expand Down Expand Up @@ -138,7 +138,7 @@ private ArtifactsPaths GetArtifactsPaths(BuildPartition buildPartition, string r
rootArtifactsFolderPath: rootArtifactsFolderPath,
buildArtifactsDirectoryPath: buildArtifactsDirectoryPath,
binariesDirectoryPath: binariesDirectoryPath,
intermediateDirectoryPath: GetIntermediateDirectoryPath(buildArtifactsDirectoryPath, buildPartition.BuildConfiguration),
publishDirectoryPath: GetPublishDirectoryPath(buildArtifactsDirectoryPath, buildPartition.BuildConfiguration),
programCodePath: Path.Combine(buildArtifactsDirectoryPath, $"{programName}{codeFileExtension}"),
appConfigPath: $"{executablePath}.config",
nuGetConfigPath: Path.Combine(buildArtifactsDirectoryPath, "NuGet.config"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public InProcessEmitArtifactsPath(
baseArtifacts.RootArtifactsFolderPath,
baseArtifacts.BuildArtifactsDirectoryPath,
baseArtifacts.BinariesDirectoryPath,
baseArtifacts.IntermediateDirectoryPath,
baseArtifacts.PublishDirectoryPath,
baseArtifacts.ProgramCodePath,
baseArtifacts.AppConfigPath,
baseArtifacts.NuGetConfigPath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ private ArtifactsPaths GetArtifactsPaths(BuildPartition buildPartition, string r
rootArtifactsFolderPath: rootArtifactsFolderPath,
buildArtifactsDirectoryPath: buildArtifactsDirectoryPath,
binariesDirectoryPath: binariesDirectoryPath,
intermediateDirectoryPath: null,
publishDirectoryPath: null,
programCodePath: null,
appConfigPath: null,
nuGetConfigPath: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ protected override void GenerateProject(BuildPartition buildPartition, Artifacts
File.WriteAllText(artifactsPaths.ProjectFilePath, content);
}

protected override string GetPublishDirectoryPath(string buildArtifactsDirectoryPath, string configuration)
=> Path.Combine(GetBinariesDirectoryPath(buildArtifactsDirectoryPath, configuration), "publish");

protected override string GetExecutablePath(string binariesDirectoryPath, string programName)
=> OsDetector.IsWindows()
? Path.Combine(binariesDirectoryPath, "publish", $"{programName}.exe")
Expand Down
Loading