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

High CPU caused by HashSet infinite loop in StaticClassCircularDependencyAnalyzer.StaticClassDependencyAnalyze #452

Open
AlexDelepine opened this issue Apr 5, 2023 · 1 comment

Comments

@AlexDelepine
Copy link

Description

Hello, I am on the Visual Studio performance team and our telemetry has shown that there are high amounts of CPU being consumed by the two callstacks I pasted below. It appears that there are multiple threads accessing a HashSet at the same time, causing the HashSet to enter a corrupted state. This causes multiple threads to be stuck in an infinite loop within the HashSet. HashSet is not inherently thread-safe, so having concurrent writers into a HashSet or overlapping reader + a writer can cause issues such as infinite loops, exceptions, and incorrect values. In the case with the callstacks I pasted below, 4 threads were stuck within HashSet.Contains and 1 thread within HashSet.AddIfNotPresent, causing 5 full cores of CPU to be continuously used.

Solution

I would recommend making sure that reads and writes to the HashSet within StaticClassDependencyAnalyze are thread-safe. You can do this either by using a lock for the HashSet, or using a thread-safe collection such as a ConcurrentDictionary or ConcurrentBag.

CallStack 1

++microsoft.codeanalysis.ni!Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.ExecuteAndCatchIfThrows_NoLock[System.ValueTuple`2[System.__Canon,Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext]](Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer, System.Action`1>, System.ValueTuple`2, System.Nullable`1)
++ microsoft.codeanalysis.csharp.ni!Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor+<>c__55`1[Microsoft.CodeAnalysis.CSharp.SyntaxKind].b__55_0(System.ValueTuple`2,Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext>)
++++share.analyzer!ET.Analyzer.StaticClassCircularDependencyAnalyzer+<>c__DisplayClass7_0.b__0(value class Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext)
++++ share.analyzer!StaticClassCircularDependencyAnalyzer.StaticClassDependencyAnalyze
++++++system.core.ni!System.Collections.Generic.HashSet`1[System.__Canon].Contains(System.__Canon)

CallStack 2

++microsoft.codeanalysis.ni!Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.ExecuteAndCatchIfThrows_NoLock[System.ValueTuple`2[System.__Canon,Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext]](Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer, System.Action`1>, System.ValueTuple`2, System.Nullable`1)
++ microsoft.codeanalysis.csharp.ni!Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor+<>c__55`1[Microsoft.CodeAnalysis.CSharp.SyntaxKind].b__55_0(System.ValueTuple`2,Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext>)
++++share.analyzer!ET.Analyzer.StaticClassCircularDependencyAnalyzer+<>c__DisplayClass7_0.b__0(value class Microsoft.CodeAnalysis.Diagnostics.SyntaxNodeAnalysisContext)
++++ share.analyzer!StaticClassCircularDependencyAnalyzer.StaticClassDependencyAnalyze
++++++system.core.ni!System.Collections.Generic.HashSet`1[System.__Canon].AddIfNotPresent(System.__Canon)

@egametang
Copy link
Owner

OK, thx!

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

No branches or pull requests

2 participants