Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/BenchmarkDotNet/Configs/DebugConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Filters;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Locators;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Order;
using BenchmarkDotNet.Reports;
Expand Down Expand Up @@ -58,6 +59,7 @@ public abstract class DebugConfig : IConfig
public IEnumerable<IValidator> GetValidators() => Array.Empty<IValidator>();
public IEnumerable<IColumnProvider> GetColumnProviders() => DefaultColumnProviders.Instance;
public IEnumerable<IExporter> GetExporters() => Array.Empty<IExporter>();
public IEnumerable<ILocator> GetLocators() => new[] { ProjectLocator.Default };
public IEnumerable<ILogger> GetLoggers() => new[] { ConsoleLogger.Default };
public IEnumerable<IDiagnoser> GetDiagnosers() => Array.Empty<IDiagnoser>();
public IEnumerable<IAnalyser> GetAnalysers() => Array.Empty<IAnalyser>();
Expand Down
6 changes: 6 additions & 0 deletions src/BenchmarkDotNet/Configs/DefaultConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using BenchmarkDotNet.Exporters.Csv;
using BenchmarkDotNet.Filters;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Locators;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Order;
using BenchmarkDotNet.Portability;
Expand Down Expand Up @@ -40,6 +41,11 @@ public IEnumerable<IExporter> GetExporters()
yield return HtmlExporter.Default;
}

public IEnumerable<ILocator> GetLocators()
{
yield return ProjectLocator.Default;
}

public IEnumerable<ILogger> GetLoggers()
{
if (LinqPadLogger.IsAvailable)
Expand Down
2 changes: 2 additions & 0 deletions src/BenchmarkDotNet/Configs/IConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Filters;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Locators;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Order;
using BenchmarkDotNet.Reports;
Expand All @@ -20,6 +21,7 @@ public interface IConfig
{
IEnumerable<IColumnProvider> GetColumnProviders();
IEnumerable<IExporter> GetExporters();
IEnumerable<ILocator> GetLocators();
IEnumerable<ILogger> GetLoggers();
IEnumerable<IDiagnoser> GetDiagnosers();
IEnumerable<IAnalyser> GetAnalysers();
Expand Down
7 changes: 6 additions & 1 deletion src/BenchmarkDotNet/Configs/ImmutableConfig.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
Expand All @@ -10,6 +10,7 @@
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Filters;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Locators;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Order;
using BenchmarkDotNet.Reports;
Expand All @@ -24,6 +25,7 @@ public sealed class ImmutableConfig : IConfig
// if something is an array here instead of hashset it means it must have a guaranteed order of elements
private readonly ImmutableArray<IColumnProvider> columnProviders;
private readonly ImmutableArray<IExporter> exporters;
private readonly ImmutableArray<ILocator> locators;
private readonly ImmutableHashSet<ILogger> loggers;
private readonly ImmutableHashSet<IDiagnoser> diagnosers;
private readonly ImmutableHashSet<IAnalyser> analysers;
Expand All @@ -41,6 +43,7 @@ internal ImmutableConfig(
ImmutableHashSet<HardwareCounter> uniqueHardwareCounters,
ImmutableHashSet<IDiagnoser> uniqueDiagnosers,
ImmutableArray<IExporter> uniqueExporters,
ImmutableArray<ILocator> uniqueLocators,
ImmutableHashSet<IAnalyser> uniqueAnalyzers,
ImmutableHashSet<IValidator> uniqueValidators,
ImmutableHashSet<IFilter> uniqueFilters,
Expand All @@ -63,6 +66,7 @@ internal ImmutableConfig(
hardwareCounters = uniqueHardwareCounters;
diagnosers = uniqueDiagnosers;
exporters = uniqueExporters;
locators = uniqueLocators;
analysers = uniqueAnalyzers;
validators = uniqueValidators;
filters = uniqueFilters;
Expand Down Expand Up @@ -92,6 +96,7 @@ internal ImmutableConfig(

public IEnumerable<IColumnProvider> GetColumnProviders() => columnProviders;
public IEnumerable<IExporter> GetExporters() => exporters;
public IEnumerable<ILocator> GetLocators() => locators;
public IEnumerable<ILogger> GetLoggers() => loggers;
public IEnumerable<IDiagnoser> GetDiagnosers() => diagnosers;
public IEnumerable<IAnalyser> GetAnalysers() => analysers;
Expand Down
4 changes: 3 additions & 1 deletion src/BenchmarkDotNet/Configs/ImmutableConfigBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using BenchmarkDotNet.Analysers;
Expand Down Expand Up @@ -44,6 +44,7 @@ public static ImmutableConfig Create(IConfig source)
var uniqueHardwareCounters = source.GetHardwareCounters().Where(counter => counter != HardwareCounter.NotSet).ToImmutableHashSet();
var uniqueDiagnosers = GetDiagnosers(source.GetDiagnosers(), uniqueHardwareCounters);
var uniqueExporters = GetExporters(source.GetExporters(), uniqueDiagnosers, configAnalyse);
var uniqueLocators = source.GetLocators().ToImmutableArray();
var uniqueAnalyzers = GetAnalysers(source.GetAnalysers(), uniqueDiagnosers);

var uniqueValidators = GetValidators(source.GetValidators(), MandatoryValidators, source.Options);
Expand All @@ -61,6 +62,7 @@ public static ImmutableConfig Create(IConfig source)
uniqueHardwareCounters,
uniqueDiagnosers,
uniqueExporters,
uniqueLocators,
uniqueAnalyzers,
uniqueValidators,
uniqueFilters,
Expand Down
13 changes: 12 additions & 1 deletion src/BenchmarkDotNet/Configs/ManualConfig.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
Expand All @@ -11,6 +11,7 @@
using BenchmarkDotNet.Extensions;
using BenchmarkDotNet.Filters;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Locators;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Order;
using BenchmarkDotNet.Reports;
Expand All @@ -26,6 +27,7 @@ public class ManualConfig : IConfig

private readonly List<IColumnProvider> columnProviders = new List<IColumnProvider>();
private readonly List<IExporter> exporters = new List<IExporter>();
private readonly List<ILocator> locators = new List<ILocator>();
private readonly List<ILogger> loggers = new List<ILogger>();
private readonly List<IDiagnoser> diagnosers = new List<IDiagnoser>();
private readonly List<IAnalyser> analysers = new List<IAnalyser>();
Expand All @@ -39,6 +41,7 @@ public class ManualConfig : IConfig

public IEnumerable<IColumnProvider> GetColumnProviders() => columnProviders;
public IEnumerable<IExporter> GetExporters() => exporters;
public IEnumerable<ILocator> GetLocators() => locators;
public IEnumerable<ILogger> GetLoggers() => loggers;
public IEnumerable<IDiagnoser> GetDiagnosers() => diagnosers;
public IEnumerable<IAnalyser> GetAnalysers() => analysers;
Expand Down Expand Up @@ -139,6 +142,12 @@ public ManualConfig AddExporter(params IExporter[] newExporters)
return this;
}

public ManualConfig AddLocator(params ILocator[] newLocators)
{
locators.AddRange(newLocators);
return this;
}

[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("This method will soon be removed, please start using .AddLogger() instead.")]
public void Add(params ILogger[] newLoggers) => AddLogger(newLoggers);
Expand Down Expand Up @@ -256,6 +265,7 @@ public void Add(IConfig config)
{
columnProviders.AddRange(config.GetColumnProviders());
exporters.AddRange(config.GetExporters());
locators.AddRange(config.GetLocators());
loggers.AddRange(config.GetLoggers());
diagnosers.AddRange(config.GetDiagnosers());
analysers.AddRange(config.GetAnalysers());
Expand Down Expand Up @@ -287,6 +297,7 @@ public void Add(IConfig config)
public static ManualConfig CreateMinimumViable()
=> CreateEmpty()
.AddColumnProvider(DefaultColumnProviders.Instance)
.AddLocator(ProjectLocator.Default)
.AddLogger(ConsoleLogger.Default);

public static ManualConfig Create(IConfig config)
Expand Down
10 changes: 10 additions & 0 deletions src/BenchmarkDotNet/Locators/ILocator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;
using System.IO;

namespace BenchmarkDotNet.Locators;

public interface ILocator
{
LocatorType LocatorType { get; }
FileInfo Locate(DirectoryInfo rootDirectory, Type type);
}
6 changes: 6 additions & 0 deletions src/BenchmarkDotNet/Locators/LocatorType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace BenchmarkDotNet.Locators;

public enum LocatorType
{
ProjectFile
}
40 changes: 40 additions & 0 deletions src/BenchmarkDotNet/Locators/ProjectLocator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using BenchmarkDotNet.Exporters;

namespace BenchmarkDotNet.Locators;

public class ProjectLocator : ILocator
{
public static ProjectLocator Default { get; } = new ProjectLocator();

public LocatorType LocatorType => LocatorType.ProjectFile;

public FileInfo Locate(DirectoryInfo rootDirectory, Type type)
{
// important assumption! project's file name === output dll name
string projectName = type.GetTypeInfo().Assembly.GetName().Name;

var possibleNames = new HashSet<string> { $"{projectName}.csproj", $"{projectName}.fsproj", $"{projectName}.vbproj" };
var projectFiles = rootDirectory
.EnumerateFiles("*proj", SearchOption.AllDirectories)
.Where(file => possibleNames.Contains(file.Name))
.ToArray();

if (projectFiles.Length == 0)
{
throw new NotSupportedException(
$"Unable to find {projectName} in {rootDirectory.FullName} and its subfolders. Most probably the name of output exe is different than the name of the .(c/f)sproj");
}
else if (projectFiles.Length > 1)
{
throw new NotSupportedException(
$"Found more than one matching project file for {projectName} in {rootDirectory.FullName} and its subfolders: {string.Join(",", projectFiles.Select(pf => $"'{pf.FullName}'"))}. Benchmark project names needs to be unique.");
}

return projectFiles[0];
}
}
37 changes: 17 additions & 20 deletions src/BenchmarkDotNet/Toolchains/CsProj/CsProjGenerator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
Expand All @@ -11,6 +11,7 @@
using BenchmarkDotNet.Extensions;
using BenchmarkDotNet.Helpers;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Locators;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Toolchains.DotNetCli;
Expand Down Expand Up @@ -71,7 +72,7 @@ protected override string GetIntermediateDirectoryPath(string buildArtifactsDire
protected override void GenerateProject(BuildPartition buildPartition, ArtifactsPaths artifactsPaths, ILogger logger)
{
var benchmark = buildPartition.RepresentativeBenchmarkCase;
var projectFile = GetProjectFilePath(benchmark.Descriptor.Type, logger);
var projectFile = GetProjectFilePath(benchmark, logger);

var xmlDoc = new XmlDocument();
xmlDoc.Load(projectFile.FullName);
Expand Down Expand Up @@ -246,36 +247,32 @@ private static string GetIndentedXmlString(XmlDocument doc)
/// returns a path to the project file which defines the benchmarks
/// </summary>
[PublicAPI]
protected virtual FileInfo GetProjectFilePath(Type benchmarkTarget, ILogger logger)
protected virtual FileInfo GetProjectFilePath(BenchmarkCase benchmark, ILogger logger)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noting the breaking change to a public API.

{
var benchmarkTarget = benchmark.Descriptor.Type;

if (!GetSolutionRootDirectory(out var rootDirectory) && !GetProjectRootDirectory(out rootDirectory))
{
logger.WriteLineError(
$"Unable to find .sln or .csproj file. Will use current directory {Directory.GetCurrentDirectory()} to search for project file. If you don't use .sln file on purpose it should not be a problem.");
rootDirectory = new DirectoryInfo(Directory.GetCurrentDirectory());
}

// important assumption! project's file name === output dll name
string projectName = benchmarkTarget.GetTypeInfo().Assembly.GetName().Name;
List<string> notFound = new List<string>();
foreach (ILocator locator in benchmark.Config.GetLocators())
{
if (locator.LocatorType != LocatorType.ProjectFile)
continue;

var possibleNames = new HashSet<string> { $"{projectName}.csproj", $"{projectName}.fsproj", $"{projectName}.vbproj" };
var projectFiles = rootDirectory
.EnumerateFiles("*proj", SearchOption.AllDirectories)
.Where(file => possibleNames.Contains(file.Name))
.ToArray();
var path = locator.Locate(rootDirectory, benchmarkTarget);

if (projectFiles.Length == 0)
{
throw new NotSupportedException(
$"Unable to find {projectName} in {rootDirectory.FullName} and its subfolders. Most probably the name of output exe is different than the name of the .(c/f)sproj");
}
else if (projectFiles.Length > 1)
{
throw new NotSupportedException(
$"Found more than one matching project file for {projectName} in {rootDirectory.FullName} and its subfolders: {string.Join(",", projectFiles.Select(pf => $"'{pf.FullName}'"))}. Benchmark project names needs to be unique.");
if (path.Exists)
return path;

notFound.Add(path.FullName);
}

return projectFiles[0];
throw new NotSupportedException($"Unable to find project file in {rootDirectory}. Attempted location(s): " + string.Join(", ", notFound));
}

public override bool Equals(object obj) => obj is CsProjGenerator other && Equals(other);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public MonoAotLLVMGenerator(string targetFrameworkMoniker, string cliPath, strin
protected override void GenerateProject(BuildPartition buildPartition, ArtifactsPaths artifactsPaths, ILogger logger)
{
BenchmarkCase benchmark = buildPartition.RepresentativeBenchmarkCase;
var projectFile = GetProjectFilePath(benchmark.Descriptor.Type, logger);
var projectFile = GetProjectFilePath(benchmark, logger);

string useLLVM = AotCompilerMode == MonoAotCompilerMode.llvm ? "true" : "false";

Expand Down
2 changes: 1 addition & 1 deletion src/BenchmarkDotNet/Toolchains/MonoWasm/WasmGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ protected override void GenerateProject(BuildPartition buildPartition, Artifacts
protected void GenerateProjectFile(BuildPartition buildPartition, ArtifactsPaths artifactsPaths, bool aot, ILogger logger)
{
BenchmarkCase benchmark = buildPartition.RepresentativeBenchmarkCase;
var projectFile = GetProjectFilePath(benchmark.Descriptor.Type, logger);
var projectFile = GetProjectFilePath(benchmark, logger);

WasmRuntime runtime = (WasmRuntime) buildPartition.Runtime;

Expand Down
10 changes: 5 additions & 5 deletions src/BenchmarkDotNet/Toolchains/NativeAot/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,17 +151,17 @@ private string GenerateProjectForNuGetBuild(BuildPartition buildPartition, Artif
</ItemGroup>
<ItemGroup>
{GetILCompilerPackageReference()}
<ProjectReference Include=""{GetProjectFilePath(buildPartition.RepresentativeBenchmarkCase.Descriptor.Type, logger).FullName}"" />
<ProjectReference Include=""{GetProjectFilePath(buildPartition.RepresentativeBenchmarkCase, logger).FullName}"" />
</ItemGroup>
<ItemGroup>
{string.Join(Environment.NewLine, GetRdXmlFiles(buildPartition.RepresentativeBenchmarkCase.Descriptor.Type, logger).Select(file => $"<RdXmlFile Include=\"{file}\" />"))}
{string.Join(Environment.NewLine, GetRdXmlFiles(buildPartition.RepresentativeBenchmarkCase, logger).Select(file => $"<RdXmlFile Include=\"{file}\" />"))}
</ItemGroup>
{GetCustomProperties(buildPartition, logger)}
</Project>";

private string GetCustomProperties(BuildPartition buildPartition, ILogger logger)
{
var projectFile = GetProjectFilePath(buildPartition.RepresentativeBenchmarkCase.Descriptor.Type, logger);
var projectFile = GetProjectFilePath(buildPartition.RepresentativeBenchmarkCase, logger);
var xmlDoc = new XmlDocument();
xmlDoc.Load(projectFile.FullName);

Expand All @@ -186,11 +186,11 @@ private string GetInstructionSetSettings(BuildPartition buildPartition)
return !string.IsNullOrEmpty(instructionSet) ? $"<IlcInstructionSet>{instructionSet}</IlcInstructionSet>" : "";
}

public IEnumerable<string> GetRdXmlFiles(Type benchmarkTarget, ILogger logger)
public IEnumerable<string> GetRdXmlFiles(BenchmarkCase benchmark, ILogger logger)
{
yield return GeneratedRdXmlFileName;

var projectFile = GetProjectFilePath(benchmarkTarget, logger);
var projectFile = GetProjectFilePath(benchmark, logger);
var projectFileFolder = projectFile.DirectoryName;
var rdXml = Path.Combine(projectFileFolder, "rd.xml");
if (File.Exists(rdXml))
Expand Down
Loading
Loading