From 7de44dc93cbfbebfb847ff284b678254a1647883 Mon Sep 17 00:00:00 2001
From: filzrev <103790468+filzrev@users.noreply.github.com>
Date: Sun, 27 Apr 2025 18:34:10 +0900
Subject: [PATCH] feat: add option to disable parallel build
---
src/BenchmarkDotNet/Configs/ConfigOptions.cs | 6 +++-
.../Running/BenchmarkRunnerClean.cs | 31 ++++++++++++++++++-
2 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/src/BenchmarkDotNet/Configs/ConfigOptions.cs b/src/BenchmarkDotNet/Configs/ConfigOptions.cs
index c1ad75d642..06bc7768c7 100644
--- a/src/BenchmarkDotNet/Configs/ConfigOptions.cs
+++ b/src/BenchmarkDotNet/Configs/ConfigOptions.cs
@@ -48,7 +48,11 @@ public enum ConfigOptions
///
/// Continue the execution if the last run was stopped.
///
- Resume = 1 << 9
+ Resume = 1 << 9,
+ ///
+ /// Determines whether parallel build of benchmark projects should be disabled.
+ ///
+ DisableParallelBuild = 1 << 10,
}
internal static class ConfigOptionsExtensions
diff --git a/src/BenchmarkDotNet/Running/BenchmarkRunnerClean.cs b/src/BenchmarkDotNet/Running/BenchmarkRunnerClean.cs
index 4f520da38d..12773880fc 100644
--- a/src/BenchmarkDotNet/Running/BenchmarkRunnerClean.cs
+++ b/src/BenchmarkDotNet/Running/BenchmarkRunnerClean.cs
@@ -88,7 +88,11 @@ internal static Summary[] Run(BenchmarkRunInfo[] benchmarkRunInfos)
var buildPartitions = BenchmarkPartitioner.CreateForBuild(supportedBenchmarks, resolver);
eventProcessor.OnStartBuildStage(buildPartitions);
- var buildResults = BuildInParallel(compositeLogger, rootArtifactsFolderPath, buildPartitions, in globalChronometer, eventProcessor);
+
+ bool useParallelBuild = !supportedBenchmarks.Any(x => x.Config.Options.IsSet(ConfigOptions.DisableParallelBuild));
+ var buildResults = useParallelBuild
+ ? BuildInParallel(compositeLogger, rootArtifactsFolderPath, buildPartitions, in globalChronometer, eventProcessor)
+ : BuildSequential(compositeLogger, rootArtifactsFolderPath, buildPartitions, in globalChronometer, eventProcessor);
var allBuildsHaveFailed = buildResults.Values.All(buildResult => !buildResult.IsBuildSuccess);
@@ -413,6 +417,31 @@ static string GetFormattedDifference(ClockSpan before, ClockSpan after)
=> (after.GetTimeSpan() - before.GetTimeSpan()).ToFormattedTotalTime(DefaultCultureInfo.Instance);
}
+ private static Dictionary BuildSequential(ILogger logger, string rootArtifactsFolderPath, BuildPartition[] buildPartitions, in StartedClock globalChronometer, EventProcessor eventProcessor)
+ {
+ logger.WriteLineHeader($"// ***** Building {buildPartitions.Length} exe(s): Start *****");
+
+ var buildLogger = buildPartitions.Length == 1 ? logger : NullLogger.Instance; // when we have just one partition we can print to std out
+
+ var beforeBuild = globalChronometer.GetElapsed();
+
+ var buildResults = new Dictionary();
+ foreach (var buildPartition in buildPartitions)
+ {
+ buildResults[buildPartition] = Build(buildPartition, rootArtifactsFolderPath, buildLogger);
+ eventProcessor.OnBuildComplete(buildPartition, buildResults[buildPartition]);
+ }
+
+ var afterBuild = globalChronometer.GetElapsed();
+
+ logger.WriteLineHeader($"// ***** Done, took {GetFormattedDifference(beforeBuild, afterBuild)} *****");
+
+ return buildResults;
+
+ static string GetFormattedDifference(ClockSpan before, ClockSpan after)
+ => (after.GetTimeSpan() - before.GetTimeSpan()).ToFormattedTotalTime(DefaultCultureInfo.Instance);
+ }
+
private static BuildResult Build(BuildPartition buildPartition, string rootArtifactsFolderPath, ILogger buildLogger)
{
var toolchain = buildPartition.RepresentativeBenchmarkCase.GetToolchain(); // it's guaranteed that all the benchmarks in single partition have same toolchain