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

Load NuGet.Frameworks into secondary AppDomain (MSBuild.exe only) #9446

Merged
merged 7 commits into from
Dec 19, 2023

Conversation

ladipro
Copy link
Member

@ladipro ladipro commented Nov 22, 2023

Related to #9303

Context

We load NuGet.Frameworks lazily by path when the project being evaluated calls one of a few property functions that need it. All standard .NET projects use such functionality so this load is executed pretty much always. Since we're loading the assembly by path, the loader is unable to take advantage of the native image and we spend 50-100 ms JITting.

Changes Made

Improved MSBuild.exe startup (or, more precisely, first evaluation) by 50-100 ms by loading NuGet.Frameworks into a separate AppDomain using Assembly.Load. The AppDomain is set up with the right binding redirects for the loader to load the assembly by strong name and use its native image.

Testing

Experimental insertions.

Notes

There are several other assemblies that require non-trivial JITting on startup. The reason why we're tackling NuGet.Frameworks here are:

  • The assembly has no dependencies other than Framework assemblies, so the AD setup is relatively simple.
  • The functionality provided by this assembly has simple signatures so the cross-domain call cost is negligible.
  • A compatible native image for this assembly already exists.

Other notes:

  • There is no impact on VS or any other MSBuild host because creating ADs may be risky and disruptive. We're changing only MSBuild.exe.
  • This PR is about the NuGet.Frameworks copy that lives in {VS-installation}\Common7\IDE\CommonExtensions\Microsoft\NuGet. The MSBuild process may also load SDK-specific copies from paths like C:\Program Files\dotnet\sdk\8.0.100\Sdks\Microsoft.NET.Sdk\tools\net472 which are out of scope here.

This is what the AD looks like in SOS:

Domain 2:           000001dff97c7e70
Stage:              OPEN
Name:               NuGetFrameworkWrapper
Assembly:           000001dff6bac490 [C:\windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll]
Assembly:           000001dff9732960 [C:\src\msbuild\artifacts\bin\bootstrap\net472\MSBuild\Current\Bin\Microsoft.Build.dll]
Assembly:           000001dff97e2410 [C:\src\msbuild\artifacts\bin\bootstrap\net472\Common7\IDE\CommonExtensions\Microsoft\NuGet\NuGet.Frameworks.dll]
Assembly:           000001dff8de7250 [C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Core\v4.0_4.0.0.0__b77a5c561934e089\System.Core.dll]
Assembly:           000001dff8dd6100 [C:\windows\Microsoft.Net\assembly\GAC_MSIL\System\v4.0_4.0.0.0__b77a5c561934e089\System.dll]
Assembly:           000001dff8e1d9a0 [C:\windows\Microsoft.Net\assembly\GAC_MSIL\System.Xml\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.dll]

Copy link
Member

@JanKrivanek JanKrivanek left a comment

Choose a reason for hiding this comment

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

Looks good from quick point of view - but I need more detailed look (kick me if I do not add approve/request changes review by EOD Thursday)

src/Build/Utilities/NuGetFrameworkWrapper.cs Outdated Show resolved Hide resolved
src/Build/Utilities/NuGetFrameworkWrapper.cs Outdated Show resolved Hide resolved
Copy link
Member

@rainersigwald rainersigwald left a comment

Choose a reason for hiding this comment

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

It looks like NuGet.Frameworks is already in the generated devenv.exe.config. Think it'd be possible to detect if we're in the VS process and call LoadWithPartialName there, too?

src/Build/Utilities/NuGetFrameworkWrapper.cs Show resolved Hide resolved
@ladipro
Copy link
Member Author

ladipro commented Nov 29, 2023

It looks like NuGet.Frameworks is already in the generated devenv.exe.config. Think it'd be possible to detect if we're in the VS process and call LoadWithPartialName there, too?

Possible, yes. It would require adding a <qualifyAssembly> entry in devenv.exe.config and there's a risk that it will break some bind somewhere, especially seeing how many copies of NuGet.Frameworks are distributed with VS. I'll get a VS PR started to get feedback from VS folks, thank you!

Copy link
Member

@JanKrivanek JanKrivanek left a comment

Choose a reason for hiding this comment

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

I have no further comments

Copy link
Member

@rainersigwald rainersigwald left a comment

Choose a reason for hiding this comment

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

I like this final version!

src/Build/Microsoft.Build.csproj Show resolved Hide resolved
src/Build/Microsoft.Build.csproj Outdated Show resolved Hide resolved
src/Build/Microsoft.Build.csproj Show resolved Hide resolved
src/Build/Microsoft.Build.csproj Outdated Show resolved Hide resolved
@ladipro
Copy link
Member Author

ladipro commented Dec 19, 2023

/var/folders/24/8k48jl6d249_n_qfxwsl6xvm0000gn/T/MSBuildTemprunner/tmp978e7f4aeded4134b8c890ce3647427b.exec.cmd: line 2: 2237 Segmentation fault: 11

https://dev.azure.com/dnceng-public/public/_build/results?buildId=504097&view=logs&j=0ddb6181-8b1d-5386-35d2-ca21a772cde8&t=a36a8187-bb52-5aa3-80a2-ccc76a822779&l=212

@ladipro
Copy link
Member Author

ladipro commented Dec 19, 2023

/azp run

Copy link

Azure Pipelines successfully started running 1 pipeline(s).

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

Successfully merging this pull request may close these issues.

3 participants