-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Avoid x-targeting perf impact on vcxproj #1278
Avoid x-targeting perf impact on vcxproj #1278
Conversation
Was about to say looks good then saw the error is related to your change:
|
Someday I will either internalize that restriction or remove it! Looking. |
Targeted mitigation for dotnet#1276. VC++ noticed a dramatic regression in solution-load performance related to the time cost of ResolveProjectReferences. That affects all projects, but we can safely assume that a .vcxproj is NOT using cross-targeting, while it's impossible to detect from the outside whether a .csproj is. This commit avoids the regression for C++ projects by just not calling the MSBuild task again for .vcxproj references.
7267638
to
36a8c7f
Compare
Looks good to me too. Thanks! From: Nick Guerrera [mailto:[email protected]] @nguerrera approved this pull request. — |
I am confirming that a) this doesn't break cross-targeting for .csproj, and b) it does reduce time for .vcxproj. |
Validated:
|
Before cross-targeting was implemented, a project had a single output that was queried in ResolveProjectReferences by either `GetTargetPath` (in single-project-build scenarios) or the default target (`Build`) in command line builds. A cross-targeting project doesn't have a single output--it has one for each of its `TargetFrameworks`. A ProjectReference, then, has to first figure out which output to ask for--the one that's the best fit for the current project. The initial implementation of this was simple: unconditionally call `GetTargetFrameworkProperties` on every ProjectReference, passing a `ReferringTargetFramework`. Then, if the project cross-targets, specify the resulting TF on future calls to the ProjectReference. If the project has a single TF, do not specify it to avoid building it once (from the solution build) and again (from a reference, explicitly specifying the one TF). Unfortunately, adding a global property for `ReferringTargetFramework` will result in a separate evaluation for the project. This means that almost _every_ project in a solution will be evaluated at least twice--once directly, with no special global properties, and once for each unique `ReferringTargetFramework` that refers to it. This can be particularly onerous for C++ projects (.vcxproj), where evaluation time is nontrivial and doubling it is noticeable. That was mitigated by special-casing vcxproj in dotnet#1278, but that is inelegant and doesn't address the root cause. This change alters the calling pattern for `ProjectReference`s. Instead of asking all references for the correct TF, it breaks the problem into multiple phases: * Ask all references whether they cross-target, and split into cross-targeting and non-cross-targeting lists. * Perform the `GetTargetFrameworkProperties` query only on projects that reported that they cross-targeted. * Update (in place) the existing `_MSBuildProjectReferenceExistent` item to pass or undefine the relevant properties based on whether the reference cross-targets (and what TF is the best match). Fixes dotnet#1276.
Before cross-targeting was implemented, a project had a single output that was queried in ResolveProjectReferences by either `GetTargetPath` (in single-project-build scenarios) or the default target (`Build`) in command line builds. A cross-targeting project doesn't have a single output--it has one for each of its `TargetFrameworks`. A ProjectReference, then, has to first figure out which output to ask for--the one that's the best fit for the current project. The initial implementation of this was simple: unconditionally call `GetTargetFrameworkProperties` on every ProjectReference, passing a `ReferringTargetFramework`. Then, if the project cross-targets, specify the resulting TF on future calls to the ProjectReference. If the project has a single TF, do not specify it to avoid building it once (from the solution build) and again (from a reference, explicitly specifying the one TF). Unfortunately, adding a global property for `ReferringTargetFramework` will result in a separate evaluation for the project. This means that almost _every_ project in a solution will be evaluated at least twice--once directly, with no special global properties, and once for each unique `ReferringTargetFramework` that refers to it. This can be particularly onerous for C++ projects (.vcxproj), where evaluation time is nontrivial and doubling it is noticeable. That was mitigated by special-casing vcxproj in dotnet#1278, but that is inelegant and doesn't address the root cause. This change alters the calling pattern for `ProjectReference`s. Instead of asking all references for the correct TF, it breaks the problem into multiple phases: * Ask all references whether they cross-target, and split into cross-targeting and non-cross-targeting lists. * Perform the `GetTargetFrameworkProperties` query only on projects that reported that they cross-targeted. * Update (in place) the existing `_MSBuildProjectReferenceExistent` item to pass or undefine the relevant properties based on whether the reference cross-targets (and what TF is the best match). Fixes dotnet#1276.
Targeted mitigation for #1276.
VC++ noticed a dramatic regression in solution-load performance related to
the time cost of ResolveProjectReferences. That affects all projects, but
we can safely assume that a .vcxproj is NOT using cross-targeting, while
it's impossible to detect from the outside whether a .csproj is.
This commit avoids the regression for C++ projects by just not calling the
MSBuild task again for .vcxproj references.
/cc @nguerrera @olgaark @srivatsn