-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Reduce CPU costs under AnalyzerExecutor.ExecuteSyntaxNodeActions #76894
Reduce CPU costs under AnalyzerExecutor.ExecuteSyntaxNodeActions #76894
Conversation
In the scrolling speedometer test, the Roslyn CodeAnalysis process shows about 25% of CPU spent in this method. Of that, a surprising amount of it (11.2%) is spent in ImmutableSegmentedDictionary.TryGetValue. Debugging through this code, it appears this is because that is called O(m x n) times where m is the number of nodes to analyze and n is the number of items in groupedActions.GroupedActionsByAnalyzer. Instead, add a hook into GroupedAnalyzerActions to allow a mapping of kind -> analyzers. This can be used by executeNodeActionsByKind to get a much quicker way to determine whether the analyzer can contribute for the node in question. Only publishing this early so Cyrus can take a peek, as I still need to do a bit of debugging around these changes. Once Cyrus and I think the changes have merit, I will create a test insertion and publish the speedometer results once those are available. Only if all that goes well will I promote this PR out of draft mode.
src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.GroupedAnalyzerActions.cs
Outdated
Show resolved
Hide resolved
src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.GroupedAnalyzerActions.cs
Outdated
Show resolved
Hide resolved
Moving out of draft status as the speedometer numbers came back pretty good. @dotnet/roslyn-compiler -- ptal |
src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.GroupedAnalyzerActions.cs
Show resolved
Hide resolved
src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.GroupedAnalyzerActions.cs
Outdated
Show resolved
Hide resolved
@dotnet/roslyn-compiler -- ptal |
/// cref="ArrayBuilder{T}.ToImmutableAndFree"/>. The <paramref name="dictionary"/> will be freed at the end of | ||
/// this method as well, and should not be used afterwards. | ||
/// </summary> | ||
public static ImmutableSegmentedDictionary<K, ImmutableArray<V>> ToImmutableSegmentedDictionaryAndFree<K, V>(this PooledDictionary<K, ArrayBuilder<V>> dictionary) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this just helps with code hygiene around repetition.
return new GroupedAnalyzerActions(newGroupedActions, analyzersByKind, newAnalyzerActions); | ||
} | ||
|
||
private static ImmutableSegmentedDictionary<TLanguageKindEnum, ImmutableArray<DiagnosticAnalyzer>> CreateAnalyzersByKind(ImmutableArray<(DiagnosticAnalyzer, GroupedAnalyzerActionsForAnalyzer)> groupedActionsAndAnalyzers) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is a marow win by getting us to O(1) lookups per syntax node kind, which is an uber hot spot while doing analyzers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A major win? Or a narrow win? I feel like I could read the typo either way :P
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lol. Major.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM Thanks (iteration 7)
@dotnet/roslyn-compiler for second review. Thanks |
Does this change mean that in
Not saying there is any need to add such an assertion, just trying to make sure I grasp the impact/nature of the change. |
Yes. I believe that should be the case. I can add such an assert in my follow-up |
In the scrolling speedometer test, the Roslyn CodeAnalysis process shows about 25% of CPU spent in this method. Of that, a surprising amount of it (11.2%) is spent in ImmutableSegmentedDictionary.TryGetValue. Debugging through this code, it appears this is because that is called O(m x n) times where m is the number of nodes to analyze and n is the number of items in groupedActions.GroupedActionsByAnalyzer.
Instead, add a hook into GroupedAnalyzerActions to allow a mapping of kind -> analyzers. This can be used by executeNodeActionsByKind to get a much quicker way to determine whether the analyzer can contribute for the node in question.
*** before changes ***
![image](https://private-user-images.githubusercontent.com/6785178/406244758-31a5d2e7-7143-4457-91bf-551216e79a1c.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk2OTcwMTksIm5iZiI6MTczOTY5NjcxOSwicGF0aCI6Ii82Nzg1MTc4LzQwNjI0NDc1OC0zMWE1ZDJlNy03MTQzLTQ0NTctOTFiZi01NTEyMTZlNzlhMWMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxNiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTZUMDkwNTE5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZmQwZjY0MTEwNzZiNjk2Y2QzOWJkZDQxYWE2ZWRiYTE1Zjc5ODhkMzRkNzg0ZGZiNGNjYzk0NWE5ZGUyYjMwMSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.w5tdyUecJ02Yg-ro05CtznZKVdWQmh_st23Wt8HIt_k)
*** after changes ***
![image](https://private-user-images.githubusercontent.com/6785178/406642341-fcab9bec-5724-4a92-866c-8f9dea114251.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzk2OTcwMTksIm5iZiI6MTczOTY5NjcxOSwicGF0aCI6Ii82Nzg1MTc4LzQwNjY0MjM0MS1mY2FiOWJlYy01NzI0LTRhOTItODY2Yy04ZjlkZWExMTQyNTEucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxNiUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTZUMDkwNTE5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9ZDQ4MTZjYWM3NTAxNGY1ZTMxMTEyNjlmZjYyN2RkMzQzMTk5NjdkNmNjMDVlYWQ2NmRlODIyMTJjNGRiNWYzNiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.Y3WA9A90sidPVSzQIRRwVGccd7mSLq6C9EZju6S96Fg)