Skip to content

Commit a798816

Browse files
authored
when user specifies both --runtimes and --corerun, multiple independent jobs should be created (#2002)
* update tests * when user specifies both --runtimes and --corerun, multiple independent jobs should be created
1 parent 9e173d3 commit a798816

File tree

2 files changed

+95
-24
lines changed

2 files changed

+95
-24
lines changed

src/BenchmarkDotNet/ConsoleArguments/ConfigParser.cs

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public static (bool isSuccess, IConfig config, CommandLineOptions options) Parse
7878
{
7979
parser
8080
.ParseArguments<CommandLineOptions>(args)
81-
.WithParsed(options => result = Validate(options, logger) ? (true, CreateConfig(options, globalConfig), options) : (false, default, default))
81+
.WithParsed(options => result = Validate(options, logger) ? (true, CreateConfig(options, globalConfig, args), options) : (false, default, default))
8282
.WithNotParsed(errors => result = (false, default, default));
8383
}
8484

@@ -163,9 +163,9 @@ private static bool Validate(CommandLineOptions options, ILogger logger)
163163
return false;
164164
}
165165

166-
if (options.Runtimes.Count() > 1 && !options.CoreRunPaths.IsNullOrEmpty())
166+
if (!options.CoreRunPaths.IsNullOrEmpty() && !RuntimeInformation.IsNetCore)
167167
{
168-
logger.WriteLineError("CoreRun path can't be combined with multiple .NET Runtimes");
168+
logger.WriteLineError("CoreRun path can be used only for .NET Core host processes.");
169169
return false;
170170
}
171171

@@ -197,12 +197,12 @@ private static bool Validate(CommandLineOptions options, ILogger logger)
197197
return true;
198198
}
199199

200-
private static IConfig CreateConfig(CommandLineOptions options, IConfig globalConfig)
200+
private static IConfig CreateConfig(CommandLineOptions options, IConfig globalConfig, string[] args)
201201
{
202202
var config = new ManualConfig();
203203

204204
var baseJob = GetBaseJob(options, globalConfig);
205-
var expanded = Expand(baseJob.UnfreezeCopy(), options).ToArray(); // UnfreezeCopy ensures that each of the expanded jobs will have it's own ID
205+
var expanded = Expand(baseJob.UnfreezeCopy(), options, args).ToArray(); // UnfreezeCopy ensures that each of the expanded jobs will have it's own ID
206206
if (expanded.Length > 1)
207207
expanded[0] = expanded[0].AsBaseline(); // if the user provides multiple jobs, then the first one should be a baseline
208208
config.AddJob(expanded);
@@ -313,20 +313,46 @@ private static Job GetBaseJob(CommandLineOptions options, IConfig globalConfig)
313313
.AsMutator(); // we mark it as mutator so it will be applied to other jobs defined via attributes and merged later in GetRunnableJobs method
314314
}
315315

316-
private static IEnumerable<Job> Expand(Job baseJob, CommandLineOptions options)
316+
private static IEnumerable<Job> Expand(Job baseJob, CommandLineOptions options, string[] args)
317317
{
318318
if (options.RunInProcess)
319+
{
319320
yield return baseJob.WithToolchain(InProcessEmitToolchain.Instance);
321+
}
320322
else if (!string.IsNullOrEmpty(options.ClrVersion))
323+
{
321324
yield return baseJob.WithRuntime(ClrRuntime.CreateForLocalFullNetFrameworkBuild(options.ClrVersion)); // local builds of .NET Runtime
322-
else if (options.CoreRunPaths.Any())
323-
foreach (var coreRunPath in options.CoreRunPaths)
324-
yield return CreateCoreRunJob(baseJob, options, coreRunPath); // local CoreFX and CoreCLR builds
325-
else if (options.CliPath != null && options.Runtimes.IsEmpty())
325+
}
326+
else if (options.CliPath != null && options.Runtimes.IsEmpty() && options.CoreRunPaths.IsEmpty())
327+
{
326328
yield return CreateCoreJobWithCli(baseJob, options);
329+
}
327330
else
328-
foreach (string runtime in options.Runtimes) // known runtimes
329-
yield return CreateJobForGivenRuntime(baseJob, runtime, options);
331+
{
332+
// in case both --runtimes and --corerun are specified, the first one is returned first and becomes a baseline job
333+
string first = args.FirstOrDefault(arg =>
334+
arg.Equals("--runtimes", StringComparison.OrdinalIgnoreCase)
335+
|| arg.Equals("-r", StringComparison.OrdinalIgnoreCase)
336+
337+
|| arg.Equals("--corerun", StringComparison.OrdinalIgnoreCase));
338+
339+
if (first is null || first.Equals("--corerun", StringComparison.OrdinalIgnoreCase))
340+
{
341+
foreach (var coreRunPath in options.CoreRunPaths)
342+
yield return CreateCoreRunJob(baseJob, options, coreRunPath); // local dotnet/runtime builds
343+
344+
foreach (string runtime in options.Runtimes) // known runtimes
345+
yield return CreateJobForGivenRuntime(baseJob, runtime, options);
346+
}
347+
else
348+
{
349+
foreach (string runtime in options.Runtimes) // known runtimes
350+
yield return CreateJobForGivenRuntime(baseJob, runtime, options);
351+
352+
foreach (var coreRunPath in options.CoreRunPaths)
353+
yield return CreateCoreRunJob(baseJob, options, coreRunPath); // local dotnet/runtime builds
354+
}
355+
}
330356
}
331357

332358
private static Job CreateJobForGivenRuntime(Job baseJob, string runtimeId, CommandLineOptions options)
@@ -479,7 +505,7 @@ private static Job CreateCoreRunJob(Job baseJob, CommandLineOptions options, Fil
479505
.WithToolchain(new CoreRunToolchain(
480506
coreRunPath,
481507
createCopy: true,
482-
targetFrameworkMoniker: options.Runtimes.SingleOrDefault() ?? RuntimeInformation.GetCurrentRuntime().MsBuildMoniker,
508+
targetFrameworkMoniker: RuntimeInformation.GetCurrentRuntime().MsBuildMoniker,
483509
customDotNetCliPath: options.CliPath,
484510
restorePath: options.RestorePath,
485511
displayName: GetCoreRunToolchainDisplayName(options.CoreRunPaths, coreRunPath)));

tests/BenchmarkDotNet.Tests/ConfigParserTests.cs

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -150,25 +150,70 @@ public void CoreRunConfigParsedCorrectlyWhenRuntimeNotSpecified()
150150
Assert.Equal(fakeRestorePackages, toolchain.RestorePath.FullName);
151151
}
152152

153-
[Fact]
154-
public void CoreRunConfigParsedCorrectlyWhenRuntimeSpecified()
153+
[FactClassicDotNetOnly("It's impossible to determine TFM for CoreRunToolchain if host process is not .NET (Core) process")]
154+
public void SpecifyingCoreRunWithFullFrameworkHostGivesError()
155+
{
156+
var fakePath = typeof(object).Assembly.Location;
157+
Assert.False(ConfigParser.Parse(new[] { "--corerun", fakePath }, new OutputLogger(Output)).isSuccess);
158+
}
159+
160+
[FactDotNetCoreOnly("It's impossible to determine TFM for CoreRunToolchain if host process is not .NET (Core) process")]
161+
public void SpecifyingCoreRunAndRuntimeCreatesTwoJobs()
155162
{
156-
const string runtime = "netcoreapp3.0";
163+
const string runtime = "net7.0";
157164
var fakeDotnetCliPath = typeof(object).Assembly.Location;
158165
var fakeCoreRunPath = typeof(ConfigParserTests).Assembly.Location;
159166
var fakeRestorePackages = Path.GetTempPath();
160167
var config = ConfigParser.Parse(new[] { "--job=Dry", "--coreRun", fakeCoreRunPath, "--cli", fakeDotnetCliPath, "--packages", fakeRestorePackages, "-r", runtime }, new OutputLogger(Output)).config;
161168

162-
Assert.Single(config.GetJobs());
163-
CoreRunToolchain toolchain = config.GetJobs().Single().GetToolchain() as CoreRunToolchain;
164-
Assert.NotNull(toolchain);
165-
Assert.Equal(runtime, ((DotNetCliGenerator)toolchain.Generator).TargetFrameworkMoniker); // runtime was provided and used
166-
Assert.Equal(fakeCoreRunPath, toolchain.SourceCoreRun.FullName);
167-
Assert.Equal(fakeDotnetCliPath, toolchain.CustomDotNetCliPath.FullName);
168-
Assert.Equal(fakeRestorePackages, toolchain.RestorePath.FullName);
169+
Assert.Equal(2, config.GetJobs().Count());
170+
171+
Job coreRunJob = config.GetJobs().Single(job => job.GetToolchain() is CoreRunToolchain);
172+
Job runtimeJob = config.GetJobs().Single(job => job.GetToolchain() is CsProjCoreToolchain);
173+
174+
CoreRunToolchain coreRunToolchain = (CoreRunToolchain)coreRunJob.GetToolchain();
175+
DotNetCliGenerator generator = (DotNetCliGenerator)coreRunToolchain.Generator;
176+
Assert.Equal(RuntimeInformation.GetCurrentRuntime().MsBuildMoniker, generator.TargetFrameworkMoniker);
177+
Assert.Equal(fakeCoreRunPath, coreRunToolchain.SourceCoreRun.FullName);
178+
Assert.Equal(fakeDotnetCliPath, coreRunToolchain.CustomDotNetCliPath.FullName);
179+
Assert.Equal(fakeRestorePackages, coreRunToolchain.RestorePath.FullName);
180+
181+
CsProjCoreToolchain coreToolchain = (CsProjCoreToolchain)runtimeJob.GetToolchain();
182+
generator = (DotNetCliGenerator)coreToolchain.Generator;
183+
Assert.Equal(runtime, ((DotNetCliGenerator)coreToolchain.Generator).TargetFrameworkMoniker);
184+
Assert.Equal(fakeDotnetCliPath, coreToolchain.CustomDotNetCliPath);
185+
Assert.Equal(fakeRestorePackages, generator.PackagesPath);
169186
}
170187

171-
[Fact]
188+
[FactDotNetCoreOnly("It's impossible to determine TFM for CoreRunToolchain if host process is not .NET (Core) process")]
189+
public void FirstJobIsBaseline_RuntimesCoreRun()
190+
{
191+
const string runtime1 = "net5.0";
192+
const string runtime2 = "net6.0";
193+
string fakePath = typeof(object).Assembly.Location;
194+
var config = ConfigParser.Parse(new[] { "--runtimes", runtime1, runtime2, "--coreRun", fakePath }, new OutputLogger(Output)).config;
195+
196+
Assert.Equal(3, config.GetJobs().Count());
197+
Job baselineJob = config.GetJobs().Single(job => job.Meta.Baseline == true);
198+
Assert.False(baselineJob.GetToolchain() is CoreRunToolchain);
199+
Assert.Equal(runtime1, ((DotNetCliGenerator)baselineJob.GetToolchain().Generator).TargetFrameworkMoniker);
200+
}
201+
202+
[FactDotNetCoreOnly("It's impossible to determine TFM for CoreRunToolchain if host process is not .NET (Core) process")]
203+
public void FirstJobIsBaseline_CoreRunsRuntimes()
204+
{
205+
const string runtime1 = "net5.0";
206+
const string runtime2 = "net6.0";
207+
string fakePath1 = typeof(object).Assembly.Location;
208+
string fakePath2 = typeof(FactAttribute).Assembly.Location;
209+
var config = ConfigParser.Parse(new[] { "--coreRun", fakePath1, fakePath2, "--runtimes", runtime1, runtime2 }, new OutputLogger(Output)).config;
210+
211+
Assert.Equal(4, config.GetJobs().Count());
212+
Job baselineJob = config.GetJobs().Single(job => job.Meta.Baseline == true);
213+
Assert.Equal(fakePath1, ((CoreRunToolchain)baselineJob.GetToolchain()).SourceCoreRun.FullName);
214+
}
215+
216+
[FactDotNetCoreOnly("It's impossible to determine TFM for CoreRunToolchain if host process is not .NET (Core) process")]
172217
public void UserCanSpecifyMultipleCoreRunPaths()
173218
{
174219
var fakeCoreRunPath_1 = typeof(object).Assembly.Location;

0 commit comments

Comments
 (0)