Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolve Assembly Reference is not a cancelable task #11149

Open
YuliiaKovalova opened this issue Dec 16, 2024 · 1 comment
Open

Resolve Assembly Reference is not a cancelable task #11149

YuliiaKovalova opened this issue Dec 16, 2024 · 1 comment
Labels

Comments

@YuliiaKovalova
Copy link
Member

Context

This ticket is intended to track the effort to improve the performance and responsiveness of the Resolve Assembly Reference task in Visual Studio.
During recent investigations into long-running tasks in Visual Studio, we identified the Resolve Assembly Reference RAR task as a significant performance bottleneck. The current implementation is not cancelable, which can lead to severe performance issues, especially in scenarios involving:

  • Large dependency graphs
  • Interactions with Windows Defender file scanning

Call Stack Analysis:

The provided stack trace demonstrates the RAR task's deep call stack, highlighting its complexity and potential for causing hangs:

 	mscorlib.dll!System.Reflection.AssemblyName.GetAssemblyName(string assemblyFile)	Unknown
>	Microsoft.Build.Tasks.Core.dll!Microsoft.Build.Shared.AssemblyNameExtension.GetAssemblyNameEx(string path) Line 204	C#
 	Microsoft.Build.Tasks.Core.dll!Microsoft.Build.Tasks.ResolveAssemblyReference.Execute.AnonymousMethod__1(string path) Line 1615	C#
 	Microsoft.Build.Tasks.Core.dll!Microsoft.Build.Tasks.SystemState.GetAssemblyName(string path) Line 287	C#
 	Microsoft.Build.Tasks.Core.dll!Microsoft.Build.Tasks.ReferenceTable.SetPrimaryAssemblyReferenceItem(Microsoft.Build.Framework.ITaskItem referenceAssemblyName) Line 321	C#
 	Microsoft.Build.Tasks.Core.dll!Microsoft.Build.Tasks.ReferenceTable.SetPrimaryItems(Microsoft.Build.Framework.ITaskItem[] referenceAssemblyFiles, Microsoft.Build.Framework.ITaskItem[] referenceAssemblyNames, System.Collections.Generic.List<System.Exception> exceptions) Line 261	C#
 	Microsoft.Build.Tasks.Core.dll!Microsoft.Build.Tasks.ReferenceTable.ComputeClosure(System.Collections.Generic.IEnumerable<Microsoft.Build.Tasks.DependentAssembly> remappedAssembliesValue, Microsoft.Build.Framework.ITaskItem[] referenceAssemblyFiles, Microsoft.Build.Framework.ITaskItem[] referenceAssemblyNames, System.Collections.Generic.List<System.Exception> exceptions) Line 917	C#
 	Microsoft.Build.Tasks.Core.dll!Microsoft.Build.Tasks.ResolveAssemblyReference.Execute(Microsoft.Build.Shared.FileExists fileExists, Microsoft.Build.Shared.DirectoryExists directoryExists, Microsoft.Build.Tasks.GetDirectories getDirectories, Microsoft.Build.Tasks.GetAssemblyName getAssemblyName, Microsoft.Build.Tasks.GetAssemblyMetadata getAssemblyMetadata, Microsoft.Build.Shared.GetRegistrySubKeyNames getRegistrySubKeyNames, Microsoft.Build.Shared.GetRegistrySubKeyDefaultValue getRegistrySubKeyDefaultValue, Microsoft.Build.Tasks.GetLastWriteTime getLastWriteTime, Microsoft.Build.Tasks.GetAssemblyRuntimeVersion getRuntimeVersion, Microsoft.Build.Shared.OpenBaseKey openBaseKey, Microsoft.Build.Tasks.GetAssemblyPathInGac getAssemblyPathInGac, Microsoft.Build.Tasks.IsWinMDFile isWinMDFile, Microsoft.Build.Tasks.ReadMachineTypeFromPEHeader readMachineTypeFromPEHeader) Line 1674	C#
 	Microsoft.Build.Tasks.Core.dll!Microsoft.Build.Tasks.ResolveAssemblyReference.Execute() Line 2226	C#

Proposed Solutions:

I recommend pursuing one of two approaches to mitigate the performance issues:

  • Out-of-Proc Execution:

Implement an out-of-process mechanism for the RAR task
This would prevent blocking the main Visual Studio thread
Provide better isolation and potential performance improvements

  • Make RAR Cancelable:

Modify the current RAR implementation to implement the ICancelableTask interface
Allow graceful cancellation of long-running assembly reference resolution
Provide a mechanism to interrupt the task when it becomes unresponsive
! Be careful with the cache file creation - don't attempt to interrupt task execution in the middle of this process.

@KalleOlaviNiemitalo
Copy link

KalleOlaviNiemitalo commented Dec 16, 2024

I set a breakpoint at ResolveAssemblyReference.Execute() and started a build in Visual Studio, but ResolveAssemblyReference.Execute() was called on a thread that has Microsoft.Build.BackEnd.RequestBuilder.RequestThreadProc in its calls stack and is not the VS main thread. I don't know whether the VS main thread is waiting for the task to finish on the request thread; but even if it is, how would out-of-process execution help?

Compare to ToolTask, which starts a new process but then waits for the process to finish and blocks the thread that called ToolTask.Execute.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants