From 77b4eadb78f36d636afce7ec3ad1633ba67de7e6 Mon Sep 17 00:00:00 2001 From: Todd Grunke Date: Tue, 10 Oct 2023 08:15:39 -0700 Subject: [PATCH 1/3] Reduce ImmutableDictionary allocations in CreateCompilationTrackerMap 1) No need to create a builder if _projectIdToTrackerMap is empty 2) No need to create a new ImmutableDictionary if it would end up having the exact same contents as projectIdToTrackerMap --- .../Workspace/Solution/SolutionState.cs | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs index 9282823dfaa2b..f15d17140a2ae 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs @@ -1549,12 +1549,27 @@ private static ProjectDependencyGraph CreateDependencyGraph( private ImmutableDictionary CreateCompilationTrackerMap(ProjectId changedProjectId, ProjectDependencyGraph dependencyGraph) { - var builder = ImmutableDictionary.CreateBuilder(); + if (_projectIdToTrackerMap.Count == 0) + return _projectIdToTrackerMap; + var newTrackerInfo = new List>(); + var allReused = true; foreach (var (id, tracker) in _projectIdToTrackerMap) - builder.Add(id, CanReuse(id) ? tracker : tracker.Fork(tracker.ProjectState, translate: null)); + { + var localTracker = tracker; + if (!CanReuse(id)) + { + localTracker = tracker.Fork(tracker.ProjectState, translate: null); + allReused = false; + } - return builder.ToImmutable(); + newTrackerInfo.Add(new KeyValuePair(id, localTracker)); + } + + if (allReused) + return _projectIdToTrackerMap; + + return ImmutableDictionary.CreateRange(newTrackerInfo); // Returns true if 'tracker' can be reused for project 'id' bool CanReuse(ProjectId id) From 2ac7cd4b254c94f693463db6fa608b723a52adaf Mon Sep 17 00:00:00 2001 From: Todd Grunke Date: Tue, 10 Oct 2023 09:34:16 -0700 Subject: [PATCH 2/3] Use ArrayBuilder instead of allocating a new list each time --- .../Core/Portable/Workspace/Solution/SolutionState.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs index f15d17140a2ae..9d3f91d5671d5 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs @@ -1552,7 +1552,7 @@ private ImmutableDictionary CreateCompilationTra if (_projectIdToTrackerMap.Count == 0) return _projectIdToTrackerMap; - var newTrackerInfo = new List>(); + var newTrackerInfo = ArrayBuilder>.GetInstance(); var allReused = true; foreach (var (id, tracker) in _projectIdToTrackerMap) { From fe911b1bbdbc9c1b5445fb7fe30bf571c8c43ab6 Mon Sep 17 00:00:00 2001 From: Todd Grunke Date: Tue, 10 Oct 2023 13:15:12 -0700 Subject: [PATCH 3/3] Forgot to add the using around the ArrayBuilder call --- .../Core/Portable/Workspace/Solution/SolutionState.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs index 9d3f91d5671d5..9f183de780782 100644 --- a/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs +++ b/src/Workspaces/Core/Portable/Workspace/Solution/SolutionState.cs @@ -1552,7 +1552,7 @@ private ImmutableDictionary CreateCompilationTra if (_projectIdToTrackerMap.Count == 0) return _projectIdToTrackerMap; - var newTrackerInfo = ArrayBuilder>.GetInstance(); + using var _ = ArrayBuilder>.GetInstance(_projectIdToTrackerMap.Count, out var newTrackerInfo); var allReused = true; foreach (var (id, tracker) in _projectIdToTrackerMap) {