Skip to content

Improve performance of SimplifyTypeNames by 5x.#40746

Closed
CyrusNajmabadi wants to merge 171 commits intodotnet:masterfrom
CyrusNajmabadi:simplifyTypeNamesPerf
Closed

Improve performance of SimplifyTypeNames by 5x.#40746
CyrusNajmabadi wants to merge 171 commits intodotnet:masterfrom
CyrusNajmabadi:simplifyTypeNamesPerf

Conversation

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor

@CyrusNajmabadi CyrusNajmabadi commented Jan 4, 2020

This should be reviewed after #40544 goes in.

This PR introduces a change in the approach the simplify-type-names feature works. Currently the feature is a standard syntax-node analyzer that effectively analyzes pretty much all identifiers in every file to see if they're simplifiable. This is unsurprisingly quite expensive.

The approach taken here is to do the following:

  1. replace the syntax-node-analysis with a semantic-model-analysis where we can analyze files in a single pass.
  2. walk down the tree building up information to avoid having to even do analysis if there's no point to it.

For example, today every identifier is checked to see if it could possibly be replaced with an alias in scope. This can trivially be avoided if, as we walk down the tree, we keep track of the names of types that have an alias to them. i.e. if we see using MyFoo = X.Foo, then we only need to check identifiers called Foo to see if they could be aliased.

We only need to update these tracked names as we encounter them down the tree. That happens vastly less times than the number of times we need to analyze some identifier.

Importantly, we still go through the core simplification system to determine if something is actually simplifiable. THe new system does not make this determination. It just attempts to call into the main system much less as it is very costly.

--

Using hte AnalyzerRunner on Roslyn.sln itself for CSharpSimplifyTypeNamesDiagnosticAnalyzer yields a change from:

CSharpSimplifyTypeNamesDiagnosticAnalyzer: 7386702   to
CSharpSimplifyTypeNamesDiagnosticAnalyzer: 1529353

An improvement of 5x. There are likely other avenues for improvement. However, my primary concern was safety and correctness. in other words, the simplifier feature is still very conservative and will call into the simplifier engine every time it think there is a potential simplification it could perform.

This is likely unnecessary in many cases as we could probably tell immediately in the feature taht things are safe. However, this would likely involve duplicating some amount of simplification logic (which would then need to be kept in sync).

This approach avoids taht (for now). But does not limit further improvements that could be made here by refactoring the simplification engine and making is smarter and more reusable for situations like this.

// A qualified cref could be many different types of things. It could be referencing a
// namespace, type or member (including static and instance members). Because of this
// we basically have no avenues for bailing early and we have to try out all possible
// simplifications paths.
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.

note: we could bail out earlier if we store instance members in our indices as well as static members.

@sharwell
Copy link
Copy Markdown
Contributor

Baseline:

Found 4961 diagnostics in 54896ms (87846714152 bytes allocated)
Execution times (ms):
CSharpSimplifyTypeNamesDiagnosticAnalyzer: 1497472
  IDE0001: 1431 instances
  IDE0002: 2386 instances
  IDE0049: 1144 instances

With this pull request:

Found 4961 diagnostics in 48346ms (84183359608 bytes allocated)
Execution times (ms):
CSharpSimplifyTypeNamesDiagnosticAnalyzer:  961078
  IDE0001: 1431 instances
  IDE0002: 2386 instances
  IDE0049: 1144 instances

I see an improvement in analyzer callback times, but "only" by about 33%.

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

I'm wondering if there's an issue where with your core count and mine. Will rnu some more test and try to break down teh individual costs.

@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner January 15, 2020 22:35
Comment thread src/Compilers/Core/Portable/Collections/UnionCollection.cs Outdated
Comment thread src/Compilers/Core/Portable/Collections/UnionCollection.cs Outdated
_preferPredefinedTypeInDecl = optionSet.GetOption(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInDeclaration, semanticModel.Language)!.Value;
_preferPredefinedTypeInMemberAccess = optionSet.GetOption(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, semanticModel.Language)!.Value;

_visitBaseCompilationUnit = n => base.VisitCompilationUnit(n);
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.

you're caching it anyways, maybe not wrap in lambda?

using System.Collections.Generic;
using System.Linq;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Immutable;
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.

These are the only changes in the file now. Consider reverting.

@CyrusNajmabadi
Copy link
Copy Markdown
Contributor Author

Closing out . The majority of these changes went in.

@CyrusNajmabadi CyrusNajmabadi deleted the simplifyTypeNamesPerf branch April 11, 2021 18:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area-IDE Community The pull request was submitted by a contributor who is not a Microsoft employee.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants