Skip to content

Reduce allocations in ProjectChanges #82265

@kevingosse

Description

@kevingosse

Many methods in Microsoft.CodeAnalysis.ProjectChanges work by building a temporary hashset to compare a list of items between OldProject and NewProject. This came up as a hot spot during a profiling session, for a function that does something like:

var solutionChanges = currentSolution.GetChanges(oldSolution);

foreach (var projectChanges in solutionChanges.GetProjectChanges())
{
    var addedAnalyzerReferences = projectChanges.GetAddedAnalyzerReferences();

    ...
}

If there are no actual changes (which I expect to be the most common case), GetAddedAnalyzerReferences will still create a hashset and go over the whole collection. I believe this can be optimized with a simple check:

    public IEnumerable<AnalyzerReference> GetAddedAnalyzerReferences()
    {
        // Fast-path
        if (NewProject.AnalyzerReferences.Equals(OldProject.AnalyzerReferences))
        {
            yield break;
        }

        // Old logic
        var oldAnalyzerReferences = new HashSet<AnalyzerReference>(OldProject.AnalyzerReferences);
        foreach (var analyzerReference in NewProject.AnalyzerReferences)
        {
            if (!oldAnalyzerReferences.Contains(analyzerReference))
            {
                yield return analyzerReference;
            }
        }
    }

Same thing for all the methods in ProjectChanges that use a similar pattern. It adds a negligible cost when the collections are different, and greatly reduces the cost when the collections are identical.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions