Skip to content

Analyzer driver performance improvements#46508

Merged
mavasani merged 17 commits intodotnet:masterfrom
mavasani:AnalyzerDriverSemanticModelProvider
Aug 14, 2020
Merged

Analyzer driver performance improvements#46508
mavasani merged 17 commits intodotnet:masterfrom
mavasani:AnalyzerDriverSemanticModelProvider

Conversation

@mavasani
Copy link
Copy Markdown
Contributor

@mavasani mavasani commented Aug 3, 2020

This change improves the analyzer execution performance by plugging in an optional semantic model provider into the compilation. This allows analyzer callbacks to fully share semantic model and bound nodes with the compiler binding phase. Additionally, analyzers invoking compilation.GetSemanticModel also get the shared semantic model, further improving performance. Analyzer driver ensures that we do not hold onto the cached semantic model/bound nodes for the entire lifetime of the compilation by dropping the cached semantic model after processing the CompilationUnitCompletedEvent for each syntax tree, which indicates the entire syntax tree's binding and analysis phase has completed.

Performance measurements on the compiler benchmark suite for analyzer execution and real world repo shows ~10-15% improvement in analyzer execution time. There is also a large allocation improvement (~30%) in analyzer execution, though majority of this chunk comes from caching some delegates that were being created on hot paths, rather then from sharing semantic model through this provider.

Strongly recommended to review commit-by-commit

  1. Commit 1 (f06d87c): Nullable enable analyzer driver. I also have a separate PR out for this commit, if that is easier to review: Nullable enable analyzer driver #46409

  2. Commit 2 (039c424): Semantic model provider implementation for the performance improvements

Performance numbers

1. Compiler benchmark

Performance suite: https://github.com/dotnet/roslyn/blob/master/docs/wiki/Measuring-Compiler-Performance.md

Master branch

Method Mean Error StdDev Median Min Max Gen 0 Gen 1 Gen 2 Allocated
GetDiagnosticsWithAnalyzers 13.90 s 0.139 s 0.190 s 13.87 s 13.45 s 14.37 s 318000.0000 85000.0000 2000.0000 1.85 GB

This PR branch

Method Mean Error StdDev Median Min Max Gen 0 Gen 1 Gen 2 Allocated
GetDiagnosticsWithAnalyzers 12.51 s 0.124 s 0.122 s 12.53 s 12.33 s 12.73 s 216000.0000 63000.0000 2000.0000 1.27 GB

2. Building real world repo with analyzers

Scenario: Rebuild of RoslynAnalyzers.sln https://github.com/dotnet/roslyn-analyzers repo

  1. Master branch: 72 seconds
  2. This PR branch: 61 seconds

@mavasani mavasani added this to the 16.8.P2 milestone Aug 3, 2020
@mavasani mavasani requested review from a team, AlekseyTs and cston August 3, 2020 14:41
@mavasani
Copy link
Copy Markdown
Contributor Author

mavasani commented Aug 3, 2020

FYI @sharwell @CyrusNajmabadi

@AlekseyTs - this is the performance optimization in analyzer driver that we talked about a while back. We now hook up a semantic model provider to the compilation when executing analyzers, such that the analyzer driver controls the lifetime and caching of the shared semantic model with bound nodes.

@mavasani
Copy link
Copy Markdown
Contributor Author

mavasani commented Aug 3, 2020

Also tagging @gafter - this change drops the weak reference to semantic model with cached bound nodes in SymbolDeclaredCompilationEvent in favor of a semantic model provider that has strong reference to semantic model with cached bound nodes, such that analyzer driver controls its lifetime.

…lationEvent to avoid unnecessary concurrent dictionary access on hot path
…g `SuppressMessageAttributeState.IsDiagnosticSuppressed` - fixes some unit tests
@CyrusNajmabadi
Copy link
Copy Markdown
Contributor

i don't know this subsystem well enough to review. but i strongly approve of us doing something here. teh design seems sane, and i think it's good that it becomes an explicit 'owned' things by a provider, rather than an impl detail that depends on weak-refs.

@AlekseyTs
Copy link
Copy Markdown
Contributor

AlekseyTs commented Aug 3, 2020

    public new SemanticModel GetSemanticModel(SyntaxTree syntaxTree, bool ignoreAccessibility)

It looks like we are missing an overload for this API. I assume for VB as well. #Closed


Refers to: src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs:2105 in f087408. [](commit_id = f087408, deletion_comment = False)

@mavasani
Copy link
Copy Markdown
Contributor Author

mavasani commented Aug 3, 2020

It looks like we are missing an overload for this API. I assume for VB as well.

Thanks @AlekseyTs. I have addressed the feedback and also added unit tests for the same.

Comment thread src/Compilers/Core/Portable/Compilation/Compilation.cs Outdated
Comment thread src/Compilers/Core/Portable/Compilation/SemanticModelProvider.cs
Comment thread src/Compilers/Core/Portable/Compilation/SemanticModelProvider.cs Outdated
Comment thread src/Compilers/Core/Portable/Diagnostic/Diagnostic.cs Outdated
Comment thread src/Compilers/Core/Portable/Diagnostic/Diagnostic.cs Outdated
Comment thread src/Compilers/Core/Portable/DiagnosticAnalyzer/CachingSemanticModelProvider.cs Outdated
Comment thread src/Compilers/Core/Portable/DiagnosticAnalyzer/CachingSemanticModelProvider.cs Outdated
Comment thread src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs
Comment thread src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs
@mavasani
Copy link
Copy Markdown
Contributor Author

FYI: The nullable enable PR #46409 has now been merged and this branch rebased to only have the core analyzer perf improvement changes. Tagging @333fred @sharwell

@333fred
Copy link
Copy Markdown
Member

333fred commented Aug 12, 2020

Will take a look now, thanks. I was waiting on the nullable changes.

Comment thread src/Compilers/Core/Portable/Compilation/Compilation.cs
Comment thread src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerDriver.cs
_semanticModel = newSemanticModel;
Symbol = symbol;
SemanticModelWithCachedBoundNodes = semanticModelWithCachedBoundNodes;
_lazyCachedDeclaringReferences = new Lazy<ImmutableArray<SyntaxReference>>(() => symbol.DeclaringSyntaxReferences);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_lazyCachedDeclaringReferences [](start = 12, length = 30)

Consider making this a lazily-initialized ImmutableArray with ImmutableInterlocked.Initialize, instead of using a Lazy<T>.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is existing code, so I was trying to not change it in this PR.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider either doing it inline, or filling an issue to follow up. We already do perf-sensitive work in this class, and this is a very-commonly-allocated class type.


In reply to: 469652219 [](ancestors = 469652219)

Comment thread src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs
Comment thread src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs
Comment thread src/Compilers/CSharp/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.cs Outdated
Comment thread src/Compilers/VisualBasic/Test/Semantic/Diagnostics/DiagnosticAnalyzerTests.vb Outdated
@333fred
Copy link
Copy Markdown
Member

333fred commented Aug 13, 2020

Done review pass (commit 15) #Closed

Comment thread src/Compilers/Core/Portable/DiagnosticAnalyzer/CachingSemanticModelProvider.cs Outdated
Comment thread src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs
@333fred
Copy link
Copy Markdown
Member

333fred commented Aug 13, 2020

Done review pass (commit 16). One minor comment about delegate caching, but this approach with the CWT looks very promising and I'll be happy to have it :)

Copy link
Copy Markdown
Member

@333fred 333fred left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (commit 17). Thanks Manish!

@mavasani
Copy link
Copy Markdown
Contributor Author

@jaredpar Any further feedback?

@mavasani
Copy link
Copy Markdown
Contributor Author

Thanks for the reviews!

@mavasani mavasani merged commit 897d928 into dotnet:master Aug 14, 2020
@ghost ghost modified the milestones: 16.8.P2, Next Aug 14, 2020
@mavasani mavasani deleted the AnalyzerDriverSemanticModelProvider branch August 14, 2020 17:55
@allisonchou allisonchou modified the milestones: Next, 16.8.P3 Aug 31, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants