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

Visual Studio constantly consumes ~50 - 90% CPU after opening a large project #2388

Closed
davkean opened this issue Jun 6, 2017 · 12 comments
Closed
Assignees
Labels
Tenet-Performance This issue affects the "Performance" tenet.
Milestone

Comments

@davkean
Copy link
Member

davkean commented Jun 6, 2017

After fixing: #2383 which makes VS much more responsive - but Visual Studio still consumes 50% - 90% CPU after opening a large project.

  1. Apply the fix from [Regression] Visual Studio becomes unresponsive for a long time after opening a large project trying to populate Dependency node #2383
  2. git clone https://github.com/aarnott/pinvoke
  3. cd pinvoke
  4. git checkout c5642c29ddd
  5. src\pinvoke.sln

Expected: After init has finished and we've processed design-time builds for CPU to be around or close to 0%.
Actual: CPU is constantly pegged for 50% - 90%, looking at dumps lots of dependency node code still runnning.

@davkean
Copy link
Member Author

davkean commented Jun 6, 2017

I suspect this only occurs for cross-targeting projects.

@abpiskunov
Copy link
Contributor

When you say DT builds are processed - what did you mean? Dependencies are processing them when new data comes, if code is still around DT builds are not processed yet.. Or processed and sent tree update requests which could be pending/in progress by tree provider.

@davkean
Copy link
Member Author

davkean commented Jun 7, 2017

I don't know yet as I haven't dug into the details - but if I leave the project for 20 minutes we're still consuming lots of CPU.

@davkean
Copy link
Member Author

davkean commented Jun 14, 2017

I'm seeing lots of CPU usage also in Roslyn.sln.

@davkean
Copy link
Member Author

davkean commented Jun 14, 2017

I'm seeing part of the problem - looks like Test Window is doing a IsDocumentInProject on all projects - which is walking into every single dependency node:

 	System.dll!System.Uri.CreateUriInfo(System.Uri.Flags cF)	Unknown
 	System.dll!System.Uri.EnsureUriInfo()	Unknown
 	System.dll!System.Uri.ParseRemaining()	Unknown
 	System.dll!System.Uri.GetLocalPath()	Unknown
 	System.dll!System.Uri.LocalPath.get()	Unknown
 	Microsoft.VisualStudio.ProjectSystem.Implementation.dll!Microsoft.VisualStudio.ProjectSystem.UnconfiguredProjectImpl.Microsoft.VisualStudio.ProjectSystem.UnconfiguredProjectInternal.MakeRooted(string path) Line 1160	C#
 	Microsoft.VisualStudio.ProjectSystem.dll!Microsoft.VisualStudio.ProjectSystem.PathHelper.MakeRooted(Microsoft.VisualStudio.ProjectSystem.UnconfiguredProject unconfiguredProject, string path) Line 373	C#
 	Microsoft.VisualStudio.ProjectSystem.Implementation.dll!Microsoft.VisualStudio.ProjectSystem.Designers.UnattachedProjectItemTreeNode.FilePath.get() Line 75	C#
 	Microsoft.VisualStudio.ProjectSystem.Implementation.dll!Microsoft.VisualStudio.ProjectSystem.Designers.ProjectTree.FilePath.get() Line 108	C#
 	Microsoft.VisualStudio.ProjectSystem.Managed.VS.dll!Microsoft.VisualStudio.ProjectSystem.VS.IProjectTreeExtensions.FindNodeByPath.AnonymousMethod__2_0(Microsoft.VisualStudio.ProjectSystem.IProjectTree child) Line 77	C#
 	Microsoft.VisualStudio.ProjectSystem.Managed.VS.dll!Microsoft.VisualStudio.ProjectSystem.VS.IProjectTreeExtensions.FindNodeHelper.AnonymousMethod__0(Microsoft.VisualStudio.ProjectSystem.IProjectTree child) Line 98	C#
 	System.Core.dll!System.Linq.Enumerable.FirstOrDefault<Microsoft.VisualStudio.ProjectSystem.IProjectTree>(System.Collections.Generic.IEnumerable<Microsoft.VisualStudio.ProjectSystem.IProjectTree> source, System.Func<Microsoft.VisualStudio.ProjectSystem.IProjectTree, bool> predicate)	Unknown
>	Microsoft.VisualStudio.ProjectSystem.Managed.VS.dll!Microsoft.VisualStudio.ProjectSystem.VS.IProjectTreeExtensions.FindNodeHelper(Microsoft.VisualStudio.ProjectSystem.IProjectTree tree, string itemToFind, System.Func<Microsoft.VisualStudio.ProjectSystem.IProjectTree, string> childPropertyFunction) Line 97	C#
 	Microsoft.VisualStudio.ProjectSystem.Managed.VS.dll!Microsoft.VisualStudio.ProjectSystem.VS.IProjectTreeExtensions.FindNodeByPath(Microsoft.VisualStudio.ProjectSystem.IProjectTree tree, string itemPath) Line 77	C#
 	Microsoft.VisualStudio.ProjectSystem.Managed.VS.dll!Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.GroupedByTargetTreeViewProvider.FindByPathInternal(Microsoft.VisualStudio.ProjectSystem.IProjectTree root, string path) Line 170	C#
 	Microsoft.VisualStudio.ProjectSystem.Managed.VS.dll!Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.GroupedByTargetTreeViewProvider.FindByPath(Microsoft.VisualStudio.ProjectSystem.IProjectTree root, string path) Line 153	C#
 	Microsoft.VisualStudio.ProjectSystem.Managed.VS.dll!Microsoft.VisualStudio.ProjectSystem.VS.Tree.Dependencies.DependenciesProjectTreeProvider.FindByPath(Microsoft.VisualStudio.ProjectSystem.IProjectTree root, string path) Line 291	C#
 	Microsoft.VisualStudio.ProjectSystem.Implementation.dll!Microsoft.VisualStudio.ProjectSystem.Designers.PhysicalProjectTreeProvider.FindByPath(Microsoft.VisualStudio.ProjectSystem.IProjectTree root, string path, System.StringComparison comparisonType, bool definitelyNotOutsideProjectDirectory) Line 2109	C#
 	Microsoft.VisualStudio.ProjectSystem.Implementation.dll!Microsoft.VisualStudio.ProjectSystem.Designers.PhysicalProjectTreeProvider.FindByPath(Microsoft.VisualStudio.ProjectSystem.IProjectTree root, string path) Line 267	C#
 	Microsoft.VisualStudio.ProjectSystem.VS.Implementation.dll!Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.ProjectNode.StandardIsDocumentInProjectHandler.IsDocumentInProjectAsync(string documentMoniker) Line 6345	C#
 	Microsoft.VisualStudio.ProjectSystem.VS.Implementation.dll!Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.ProjectNode.IsDocumentInProjectInternal.AnonymousMethod__0() Line 5772	C#
 	Microsoft.VisualStudio.Threading.dll!Microsoft.VisualStudio.Threading.JoinableTaskFactory.ExecuteJob<Microsoft.VisualStudio.Threading.EmptyStruct>(System.Func<System.Threading.Tasks.Task> asyncMethod, Microsoft.VisualStudio.Threading.JoinableTask job)	Unknown
 	Microsoft.VisualStudio.Threading.dll!Microsoft.VisualStudio.Threading.JoinableTaskFactory.RunAsync(System.Func<System.Threading.Tasks.Task> asyncMethod, bool synchronouslyBlocking, Microsoft.VisualStudio.Threading.JoinableTaskCreationOptions creationOptions, System.Delegate entrypointOverride)	Unknown
 	Microsoft.VisualStudio.ProjectSystem.Implementation.dll!Microsoft.VisualStudio.ProjectSystem.ProjectMultiThreadedService.ExecuteSynchronously(System.Func<System.Threading.Tasks.Task> asyncAction) Line 127	C#
 	Microsoft.VisualStudio.ProjectSystem.VS.Implementation.dll!Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.ProjectNode.HrInvoke.AnonymousMethod__0() Line 3750	C#
 	Microsoft.VisualStudio.ProjectSystem.VS.dll!Microsoft.VisualStudio.ProjectSystem.VS.HResult.Invoke.AnonymousMethod__0() Line 294	C#
 	Microsoft.VisualStudio.ProjectSystem.VS.dll!Microsoft.VisualStudio.ProjectSystem.VS.HResult.Invoke(System.Func<Microsoft.VisualStudio.ProjectSystem.VS.HResult> action, System.IServiceProvider vsShellServiceProvider, Microsoft.VisualStudio.ProjectSystem.IProjectFaultHandlerService projectFaultHandlerService, Microsoft.VisualStudio.ProjectSystem.UnconfiguredProject project) Line 313	C#
 	Microsoft.VisualStudio.ProjectSystem.VS.Implementation.dll!Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.ProjectNode.HrInvoke(System.Func<System.Threading.Tasks.Task> asyncAction, bool registerProjectFaultHandlerService) Line 3746	C#
 	Microsoft.VisualStudio.ProjectSystem.VS.Implementation.dll!Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.ProjectNode.IsDocumentInProjectInternal(string mkDoc, bool useDocumentPriority2, out int found, out int pri, out uint itemId) Line 5769	C#
 	Microsoft.VisualStudio.ProjectSystem.VS.Implementation.dll!Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.ProjectNode.IsDocumentInProject(string mkDoc, out int found, Microsoft.VisualStudio.Shell.Interop.VSDOCUMENTPRIORITY[] pri, out uint itemId) Line 1885	C#
 	Microsoft.VisualStudio.ProjectSystem.VS.Implementation.dll!Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.ProjectNodeWrapper.IsDocumentInProject(string pszMkDocument, out int pfFound, Microsoft.VisualStudio.Shell.Interop.VSDOCUMENTPRIORITY[] pdwPriority, out uint pitemid) Line 140	C#

I've got a trace, and trying to interpret it.

@davkean
Copy link
Member Author

davkean commented Jun 14, 2017

For a 10 second period I'm seeing 400 GCs (362 Gen0, 38 Gen1), that can't be normal...

@davkean
Copy link
Member Author

davkean commented Jun 28, 2017

The test delay is something else, and being tracked by another bug.

I spent more time looking into - it looks like we're constantly getting called back with "project changes" in CrossTargetRuleSubscriberBase.OnProjectChangedAsync.

@davkean
Copy link
Member Author

davkean commented Jun 28, 2017

Looks like for each ConfiguredProject, we have 6 design-time subscription links, and 6 evaluation subscriptions link, that probably doesn't help.

@davkean
Copy link
Member Author

davkean commented Jun 28, 2017

Yeah, that 6 subscriptions should be halved because we're sync'ing to the catalog source, but basically, looks like we're adding too many subscriptions - now to figure that out.

@davkean
Copy link
Member Author

davkean commented Jun 29, 2017

The subscriptions were a red herring, they are expected, as we subscribe to 2 things per configuration.

The real issue is that we're continuously resetting subscriptions. The underlying reason is because we're expecting a user written value ("TargetFramework") to be canonical, from our guidelines:

  • DO NOT parse or attempt to reason about the values of properties that make up the dimensions for a project configuration; $(Configuration), $(Platform) and $(TargetFramework), and their plural counterparts; $(Configurations), $(Platforms) and $(TargetFrameworks).
    These properties are user "aliases" and should only be used for conditions, display and grouping purposes. Instead, the project system should be using their canonical equivalents; $(PlatformTarget) instead of $(Platform), and $(TargetFrameworkMoniker) instead of $(TargetFramework).

The end result is that we're comparing:

portable-net40+win8+wpa81 

against:

portable-net4+win8+wpa81 

And this fails.

@srivatsn
Copy link
Contributor

Fixed by #2526

AArnott added a commit to dotnet/pinvoke that referenced this issue Jun 30, 2017
@davkean davkean added the Tenet-Performance This issue affects the "Performance" tenet. label Jun 30, 2017
panopticoncentral pushed a commit that referenced this issue Jul 4, 2017
Fixes: #2388.

We were making the assumption that the literal user written short name, matched the canonical version of the short name. This wasn't the case:

The project file had:

   portable-net4+win8+wpa81

Our "canonical" version had:

    portable-net40+win8+wpa81

This was causing us to continually reset our subscriptions to the data flow, and constantly process the same data over and over again.

After my fix, we still do not handle the portable versions correctly in the project, in that we only show one of them in the dependencies tree, filed #2524 to track that.

Note also that this code shouldn't even be looking at TFMs, filed: #2525 to track that.
@grahamehorner
Copy link

I have VS 2017.3 Preview 3 showing the same symptoms, but I wouldn't consider it the big a large project; 1 project with approx. 30 bower packages ? very little in the way of C# code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Tenet-Performance This issue affects the "Performance" tenet.
Projects
None yet
Development

No branches or pull requests

5 participants