| File: Harness\ProjectGenerator.cs | Web Access |
| Project: src\test\Microsoft.ML.PerformanceTests\Microsoft.ML.PerformanceTests.csproj (Microsoft.ML.PerformanceTests) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.IO; using System.Linq; using BenchmarkDotNet.Loggers; using BenchmarkDotNet.Running; using BenchmarkDotNet.Toolchains; using BenchmarkDotNet.Toolchains.CsProj; namespace Microsoft.ML.PerformanceTests.Harness { /// <summary> /// to avoid side effects of benchmarks affect each other BenchmarkDotNet runs every benchmark in a standalone, dedicated process /// however to do that it needs to be able to create, build and run new executable /// /// the problem with ML.NET is that it has native dependencies, which are NOT copied by MSBuild to the output folder /// in case where A has native dependency and B references A /// /// this is why this class exists: /// 1. to tell MSBuild to copy the native dependencies to folder with .exe (NativeAssemblyReference) /// 2. to generate a .csproj file that does not exclude Directory.Build.props (default BDN behavior) which contains custom NuGet feeds that are required for restore step /// </summary> public class ProjectGenerator : CsProjGenerator { private readonly string _runtimeIdentifier = string.Empty; public ProjectGenerator(string targetFrameworkMoniker) : base(targetFrameworkMoniker, null, null, null) { #if NETFRAMEWORK _runtimeIdentifier = "win-x64"; #endif } protected override void GenerateProject(BuildPartition buildPartition, ArtifactsPaths artifactsPaths, ILogger logger) => File.WriteAllText(artifactsPaths.ProjectFilePath, $@" <Project Sdk=""Microsoft.NET.Sdk""> <PropertyGroup> <OutputType>Exe</OutputType> <OutputPath>bin\{buildPartition.BuildConfiguration}</OutputPath> <TargetFramework>{TargetFrameworkMoniker}</TargetFramework> <RuntimeIdentifier>{_runtimeIdentifier}</RuntimeIdentifier> <AssemblyName>{artifactsPaths.ProgramName}</AssemblyName> <AssemblyTitle>{artifactsPaths.ProgramName}</AssemblyTitle> <AllowUnsafeBlocks>true</AllowUnsafeBlocks> <TreatWarningsAsErrors>False</TreatWarningsAsErrors> <DebugType>pdbonly</DebugType> <DebugSymbols>true</DebugSymbols> </PropertyGroup> {GetRuntimeSettings(buildPartition.RepresentativeBenchmarkCase.Job.Environment.Gc, buildPartition.Resolver)} <ItemGroup> <Compile Include=""{Path.GetFileName(artifactsPaths.ProgramCodePath)}"" Exclude=""bin\**;obj\**;**\*.xproj;packages\**"" /> </ItemGroup> <ItemGroup> <ProjectReference Include=""{GetProjectFilePath(buildPartition.RepresentativeBenchmarkCase.Descriptor.Type, logger).FullName}"" /> {GenerateNativeReferences(buildPartition, logger)} </ItemGroup> </Project>"); // This overrides the .exe path to also involve the runtimeIdentifier for .NET Framework protected override string GetBinariesDirectoryPath(string buildArtifactsDirectoryPath, string configuration) => Path.Combine(buildArtifactsDirectoryPath, "bin", configuration, TargetFrameworkMoniker, _runtimeIdentifier); private string GenerateNativeReferences(BuildPartition buildPartition, ILogger logger) { var csproj = GetProjectFilePath(buildPartition.RepresentativeBenchmarkCase.Descriptor.Type, logger); return string.Join(Environment.NewLine, File.ReadAllLines(csproj.FullName).Where(line => line.Contains("<NativeAssemblyReference"))); } } }