-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Description
We've got a customer that has a large 91 project solution mixing legacy and new project system targeting .NET Standard 2.0 and .NET Framework and is suffering from huge performance problems including long solution loads, and UI delays when making changes to a project, unloading projects, after building, and switching configurations after moving from tranditional .NET Framework projects.
Investigating these issues, the performance issues they are experiencing all boil down to slow design-time builds. Even after turning off globbing support (which almost doubled build time), the overhead of .NET Standard/.NET Core targets is very high, and appears to have increased significantly in 2.0 vs 1.1.
Below I grabbed his solution and attempted to run just CompileDesignTime for the entire solution - this simply is supposed to return command-line arguments so that we can populate intellisense, all of below occurs to do that:
This does not include:
- Evaluation time, tracked by [Tracking] Overhead of evaluation is too high for design-time builds #1586.
- MSBuild launch time
- Restore time
| Time | Target | # | Added in 15.3/2.0 | Owner | Bug | Notes |
|---|---|---|---|---|---|---|
| 11277 ms | Total | 1 calls | ||||
| MSBuild | We now stop double-evalauting | |||||
| 1710 ms | ResolveAssemblyReferences | 91 calls | MSBuild | |||
| 1660 ms | ResolveProjectReferences | 91 calls | ||||
| 720 ms | FindReferenceAssembliesForReferences | 91 calls | ✔ | MSBuild | dotnet/msbuild#2439 | |
| 588 ms | ImplicitlyExpandDesignTimeFacades | 80 calls | ||||
| 244 ms | CoreCompile | 91 calls | ||||
| 241 ms | _HandlePackageFileConflicts | 91 calls | ✔ | |||
| 183 ms | ResolveNuGetPackageAssets | 54 calls | ||||
| 156 ms | HandlePackageFileConflicts | 54 calls | ✔ | |||
| 155 ms | ImplicitlyExpandNETStandardFacades | 80 calls | ✔ | |||
| 109 ms | _SplitProjectReferencesByFileExistence | 91 calls | ||||
| 88 ms | AssignProjectConfiguration | 87 calls | ||||
| 79 ms | ReportAssetsLogMessages | 11 calls | ✔ | |||
| 71 ms | _GenerateCompileDependencyCache | 91 calls | MSBuild | |||
| 60 ms | ValidateSolutionConfiguration | 1 calls | ||||
| 59 ms | GetTargetFrameworkProperties | 71 calls | ||||
| 47 ms | RunResolvePackageDependencies | 11 calls | ||||
| 45 ms | ResolveCodeAnalysisRuleSet | 91 calls | ||||
| 35 ms | PreXsdCodeGen | 80 calls | This, combined with CleanXsdCodeGen, are paid for every project regardless of whether they've ever had an XSD, why aren't we just using Clean for this? | |||
| 34 ms | PrepareForBuild | 91 calls | ||||
| 30 ms | GenerateCompiledExpressionsTempFile | 80 calls | ||||
| 29 ms | GetReferenceAssemblyPaths | 91 calls | ||||
| 24 ms | _ComputeLockFileCopyLocal | 11 calls | ||||
| 22 ms | CompileDesignTime <!-- Trying to call this | 91 calls | ||||
| 22 ms | _SetEmbeddedWin32ManifestProperties | 91 calls | This is running because we pass it to the compiler, but do we need for design-time purposes? | |||
| 20 ms | DesignTimeMarkupCompilation | 80 calls | ||||
| 19 ms | RunProduceContentAssets | 11 calls | ||||
| 18 ms | CleanXsdCodeGen | 80 calls | ||||
| 18 ms | GetTargetPathWithTargetPlatformMoniker | 61 calls | ||||
| 17 ms | _GenerateCompileInputs | 91 calls | ||||
| 91 calls | MSBuild | Removed | ||||
| 15 ms | GenerateTargetFrameworkMonikerAttribute | 91 calls | ||||
| 7 ms | _ComputeLockFileReferences | 11 calls | ||||
| 7 ms | ExpandSDKReferences | 91 calls | ||||
| 6 ms | _CheckCompileDesignTimePrerequisite | 91 calls | ||||
| 6 ms | CheckForDuplicateItems | 11 calls | ||||
| 5 ms | GetFrameworkPaths | 91 calls | ||||
| 3 ms | DesignTimeXamlMarkupCompilation | 80 calls | ||||
| 2 ms | BeforeResolveReferences | 91 calls | ||||
| 2 ms | GetTargetPath | 61 calls | ||||
| 2 ms | 1 calls | MSBuild | ||||
| 2 ms | ResolveReferences | 91 calls | ||||
| 2 ms | _SetTargetFrameworkMonikerAttribute | 91 calls | ||||
| 1 ms | PrepareProjectReferences | 91 calls | ||||
| 1 ms | _ComputeActiveTFMFileDependencies | 11 calls | ||||
| 1 ms | _ComputeTransitiveProjectReferences | 11 calls | ||||
| 1 ms | _AfterCompileWinFXInternal | 80 calls | ||||
| 1 ms | BeforeCompile | 91 calls | ||||
| 1 ms | ValidateProjects | 1 calls | ||||
| 1 ms | _ComputeLockFileFrameworks | 11 calls | ||||
| 1 ms | AfterCompile | 91 calls |
Some of these are built-in targets, some of these are new SDK targets, I've tried to mark them as appropriate and any bugs tracking their performance.