From abcba162b74e98cebe89a771a928662e2ef55350 Mon Sep 17 00:00:00 2001 From: Manish Vasani Date: Wed, 2 Mar 2016 09:15:39 -0800 Subject: [PATCH] Pool per-analyzer state instances across CompilationWithAnalyzers instances --- .../AnalysisState.PerAnalyzerState.cs | 34 ++++++++++++++++++- .../DiagnosticAnalyzer/AnalysisState.cs | 24 +++++++++---- 2 files changed, 51 insertions(+), 7 deletions(-) diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.PerAnalyzerState.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.PerAnalyzerState.cs index e7ec3df4574..51d40dd3c68 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.PerAnalyzerState.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.PerAnalyzerState.cs @@ -37,6 +37,38 @@ private class PerAnalyzerState _currentlyAnalyzingDeclarationsMapPool = currentlyAnalyzingDeclarationsMapPool; } + public void Free() + { + lock (_gate) + { + foreach (var analyzerStateData in _pendingEvents.Values) + { + FreeState_NoLock(analyzerStateData, _analyzerStateDataPool); + } + + foreach (var analyzerStateData in _pendingSymbols.Values) + { + FreeState_NoLock(analyzerStateData, _analyzerStateDataPool); + } + + foreach (var declarationDataMap in _pendingDeclarations.Values) + { + foreach (var declarationStateData in declarationDataMap.Values) + { + FreeDeclarationAnalyzerState_NoLock(declarationStateData); + } + + FreeDeclarationDataMap_NoLock(declarationDataMap); + } + + _pendingEvents.Clear(); + _pendingSymbols.Clear(); + _pendingDeclarations.Clear(); + _lazySyntaxTreesWithAnalysisData = null; + _pendingSyntaxAnalysisTreesCount = 0; + } + } + public void AddPendingEvents(HashSet uniqueEvents) { lock (_gate) @@ -275,7 +307,7 @@ private void FreeDeclarationAnalyzerState_NoLock(DeclarationAnalyzerStateData st private static void FreeState_NoLock(TAnalyzerStateData state, ObjectPool pool) where TAnalyzerStateData : AnalyzerStateData { - if (state != null) + if (state != null && !ReferenceEquals(state, AnalyzerStateData.FullyProcessedInstance)) { state.Free(); pool.Free(state); diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs index 21f0c04280a..e2dbdbb57b5 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalysisState.cs @@ -63,6 +63,13 @@ internal partial class AnalysisState private readonly ObjectPool> _compilationEventsPool; private readonly HashSet _pooledEventsWithAnyActionsSet; + // Create static pools for heavily allocated per-analyzer state objects - this helps in reducing allocations across CompilationWithAnalyzer instances. + private const int PoolSize = 5000; + private static readonly ObjectPool s_analyzerStateDataPool = new ObjectPool(() => new AnalyzerStateData(), PoolSize); + private static readonly ObjectPool s_declarationAnalyzerStateDataPool = new ObjectPool(() => new DeclarationAnalyzerStateData(), PoolSize); + private static readonly ObjectPool> s_currentlyAnalyzingDeclarationsMapPool = new ObjectPool>(() => new Dictionary(), PoolSize); + private static readonly ObjectPool s_perAnalyzerStatePool = new ObjectPool(() => new PerAnalyzerState(s_analyzerStateDataPool, s_declarationAnalyzerStateDataPool, s_currentlyAnalyzingDeclarationsMapPool), PoolSize); + public AnalysisState(ImmutableArray analyzers, CompilationData compilationData) { _gate = new object(); @@ -80,19 +87,24 @@ public AnalysisState(ImmutableArray analyzers, CompilationDa _pooledEventsWithAnyActionsSet = new HashSet(); } - private static ImmutableDictionary CreateAnalyzerStateMap(ImmutableArray analyzers, out ImmutableArray analyzerStates) + ~AnalysisState() { - var analyzerStateDataPool = new ObjectPool(() => new AnalyzerStateData()); - var declarationAnalyzerStateDataPool = new ObjectPool(() => new DeclarationAnalyzerStateData()); - var currentlyAnalyzingDeclarationsMapPool = new ObjectPool>( - () => new Dictionary()); + // Free the per-analyzer state tracking objects. + foreach (var analyzerState in _analyzerStates) + { + analyzerState.Free(); + s_perAnalyzerStatePool.Free(analyzerState); + } + } + private static ImmutableDictionary CreateAnalyzerStateMap(ImmutableArray analyzers, out ImmutableArray analyzerStates) + { var statesBuilder = ImmutableArray.CreateBuilder(); var map = ImmutableDictionary.CreateBuilder(); var index = 0; foreach (var analyzer in analyzers) { - statesBuilder.Add(new PerAnalyzerState(analyzerStateDataPool, declarationAnalyzerStateDataPool, currentlyAnalyzingDeclarationsMapPool)); + statesBuilder.Add(s_perAnalyzerStatePool.Allocate()); map[analyzer] = index; index++; } -- GitLab