roslyn: Roslyn Produces Abnormally High CPU Utilization When Many Files Are Open
Version Used: This is seen as of Visual Studio 2022 Preview 7
Steps to Reproduce:
- Open this solution
- Expand the
DragonSpark.Application
project so that theDragonSpark.Application/Security/Identity/Profile
namespace is visible. - Open all the visible files under the project with
Right-click -> Open
(this is about 60 of them): - Open this file, pressing
Enter
andBackspace
several times at the end of this line - Observe CPU usage and time (it should be nominal and expected)
- Now repeat step 3 <-- Triggering Event
- Repeat step 4
- Repeat step 5 – CPU utilization should be abnormally utilized in both amount and time
Expected Behavior: The expected behavior is seen with steps 1-5. It is expected that steps 6-8 produce the same behavior as well, but they do not.
Actual Behavior: While steps 1-5 take several seconds to complete at ~6% CPU utilization (nominal and expected), steps 6-8 take up to nearly 30 seconds to complete, with double the amount of CPU utilization during this time.
Additional notes This is (thankfully) a very easy reproduction to produce the issue. Until I was able to reproduce it using this method, I was only encountering it in impossibly complex situations where massive refactoring occurred and many files were opened. This is still the case today and I actively encounter this problem when significant refactoring is involved. When paired with issues such this one it becomes quite the challenge to keep Visual Studio open.
Note that this is also captured in developercommunity here with provided ETL/DMPs. An issue was never made here in the Roslyn repository to properly track so doing that now.
Please do let me know if you have any further questions and I will do my best to assist you. Thank you for any consideration towards addressing this issue, and for all your excellent work over there. 🙏
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 3
- Comments: 104 (53 by maintainers)
@Mike-E-angelo we’ve followed up internally and moved a few issues around to re-purpose your VS feedback issue to be the public facing issue for this particular problem (CodeLens querying non-visible files).
We’ve also raised the alarm bells with the team involved and ensured the public facing issue can be used to communicate with the team! The fix for this most likely wont make it into 17.3-P1 but we’re pushing for 17.3-P2
For your review next week, @CyrusNajmabadi: I have recorded the entire process on a brand new VM install and have posted it with chapters (found in the video description) to fast forward to the interesting parts:
https://www.youtube.com/watch?v=N4onyXKlWRo
You can see that:
Note that this was performed with a new VM install with only the Web workload to further eliminate any possible external causes. No settings, extensions, or user sign-in were applied or installed. Everything is standard and a default installation from the following location: https://visualstudio.microsoft.com/vs/community/
It took about 20 minutes to do this.
Terrific. Closing out. Thanks @Mike-E-angelo
It’s some of column A and some of column B. for example, this issue helped identify that we had a problem with Inheritance margin. We think that we’ve fixed that in 17.3. However, it also covers things outside of roslyn.
I don’t want to close this out until both the stuff we’ve fixed, and the stuff in sister teams has made it out so we can validate if the end experience is now ok. As mentioned before, OOP is enormously complex. Thinks about it as a server where dozens of microservices run, and where a single errant service can cause a bad experience. So we want to make sure that we’re actually at a good state before closing out.
All the issues are tracked with VS’ internal bug tracker. These projects are not public so there are no public links to them.
VS - CodeLens 😃 We tend to call this also Platform/Editor.
It’s the correct repository if roslyn is consuming excessive CPU based on reasonable requests of us.
For analogy, say that
List<string>
used 1GB of ram itself when someone added the string""
to it. That would be an issue withList<T>
. However, if someone added 1 billion strings toList<T>
then it’s not an issue withList<T>
if its internal array now has to hold those billion strings, it’s an issue with teh caller who is adding all those strings. Does that make sense? 😃I can probably try that next week. 😃
Looking now.
Note: there are known issues with .net 6 in that it adds source generators to every project. This deeply exacerbates some perf issues as we are unable to share as much as before due to our system not knowing what the effect will be of all the source generators. Projects that use .net 6 are not comparable currently wrt performance with projects that don’t in IDE scenarios. This continues to be something we work on, but (as per above) it’s non-trivial and will likely take a lot of time as we continue to assess how to best have a system that can run arbitrary code that affects semantics on every keystroke.
Can confirm, i have the same bug with VS 2022 Enterprise.
@sharwell we could. However while that would get us better true-positive matches. It wouldn’t help with the false-positive case. Effectively (and need to discuss with @jcouv to make sure of this) practically any downstream
new(...)
could be ina context where it is referring to the type in question. e.g.Foo(new(...))
. We’d have to still check this to see if it possibly was a reference to the constructor in question.The only ways around this are:
new(...)
is in doesn’t have othernew(...)
calls that run the gamut of the common arg counts (e.g. 0-4 args).Bar
invoid Foo(Bar bar)
, then use that information and syntax to then try to filter down to documents that have both a usage ofFoo
andnew(...)
in it. However, this sort of ‘combined knowledge’ approach is something we have no precedence for, and it would require us to enumerate all possible contextual locations and ensure that all of them have something else we can definitively search for. I actually think this is promising, but it’s def a large departure from how Find-Refs works today.@jcouv could you actually enumerate all the scenarios in teh compiler hwere
new(...)
is allowed (e.g. where hte compiler can infer the type for it?). If you can, i can start assessing if all those scenarios would have a secondary indicator that we can use to drive this.I’m using yours, following the instructions you gave in the OP about which files to open and what to repeat 😃
This is the correct repository for the parts of codelens related to roslyn (like ‘reference count’ which is the part you’re hitting). So this issue should stay here. Other parts of codelens (like the source control information) would live outside of here.
Thanks for the additional info. I’ll try repro’ing this next week with codelens on.
Following the above (OP) instructions on:
produces no strange behavior for me.
I’ll look at your traces again today @Mike-E-angelo however, they an showed work being done in find refs. So something is calling that. The likely subjects are code lens and inheritance margin. But it’s possible it’s some other feature or extension (as find refs is a public api we expose)
Based on those traces. It is likely InheritanceMargin or CodeLens. If you have those two running, can you disable and see if it clears things up for you?