How-To's

Performance improvements in ReSharper 2018.2 EAP: EditorConfig support

In a previous series of blog posts about ReSharper’s performance, we promised to continue sharing our activities in that area. This post will talk about a significant refactoring of EditorConfig support and other fixes we’ve implemented based on the performance snapshots you’ve sent us (thanks!).

In this series:

Let’s have a look at these in more detail.

Performance improvements around EditorConfig support

Back in ReSharper 2017.3, we added EditorConfig support to adjust ReSharper inspections settings via .editorconfig and StyleCop configuration files using both ReSharper-specific and Roslyn-specific records. However, it was slow and added a noticeable performance impact on Visual Studio – which is why there was a setting called Read settings from editorconfig and project settings, disabled by default.

ReadSettingsFromEditorConfig

The slowdown happened because we had performed a lot of work to calculate the severity of each issue found in a file. Without file-level settings from .editorconfig and StyleCop, we could just cache the severity of all inspections in a semi-static dictionary for all files in a solution. When file-level settings were present, we had to query our settings and configuration files for every issue. Now, we’ve figured out a way to share common data between all queries in a file, which yields huge performance benefits.

The next problem came from the fact that EditorConfig format supports masks with extended syntax (which came from Unix utilities). ReSharper had an open-source implementation of EditorConfig, which used the Minimatcher library to work with file masks. As it turned out, the library was not robust enough to work at this scale. We ended up writing our own “matcher” to overcome this issue.

To create a perfect matcher, we had to think of a better design. We rejected regular expressions as they can be too slow with their unconstrained backtracking. First, our matcher analyzes the last part of a mask that (most of the time) consists of the file extension (like *.cs). Our matcher works with any path “as is,” which allows us to get rid of preparatory steps like changing Windows path separators to Unix ones, dividing the path to components, etc.

Then, we need to resolve another big problem: the original matcher was not able to correctly handle a double asterisk (**) with prefixes or suffixes. For example, let’s consider the mask a/b**c/e.cs. The original matcher treated the double asterisk as a single asterisk. As a result, a path like a/bbbb/something/cccc/e.cs was not matched by the mask, which was totally wrong and didn’t follow the EditorConfig standards. For this reason, the EditorConfig engine had to change ** to a monstrous structure {*,*/**/*}, which slowed everything down even more. Our own matcher does not have this problem and follows the EditorConfig standards to support double asterisks.

Finally, in our matcher implementation, we avoid recursion in case there is multiple single asterisks, e.g., *Test*.cs.

root = true

[*]
indent_style = space

[lib/**.js]
indent_size = 2

[Views/**/*.cshtml]
indent_size = 4

As a result, our matcher implementation outperforms the original one by far. In fact, we’ve contributed the new Glob matcher implementation back to the EditorConfig community, and our pull request is pending approval.

Upcoming updates

Now, let’s talk about our plans for the upcoming updates. Right now the impact of enabling Read settings from editorconfig and project settings option is less than 4% of the total SWEA (Solution-Wide Analysis) time. We are planning to apply several more optimizations to make it even better:

  • Fix unresponsiveness when many errors/warnings are selected in the SWEA tool window. Some changes in core source code may cause many errors to be generated, and ReSharper iterates all of them every 50 ms. The fix is undergoing QA and hopefully will be released in the 2018.2 EAP soon.
  • Move slow parts of presenting found inspections in SWEA to a background thread, to increase responsiveness. We hope this will be done in the 2018.3 release cycle.
  • Add a global cache of configuration files parsing results. This will have to wait until the 2018.3 release cycle.

After these changes, we plan to enable the option Read settings from editorconfig and project settings by default and eventually remove the check-box.

In the next post, we’ll take a look at the list of performance reports on YouTrack that we’ve fixed in the ReSharper 2018.2 EAP (Early Access Program). Stay tuned!

Make sure to also check the Performance guide for Visual Studio (ReSharper 2017.3+) and our KB article Speeding up ReSharper (and Visual Studio) if you are experiencing performance issues. If you have a specific performance issue you can reproduce, we would greatly appreciate it if you could collect a performance snapshot and send it over. Thanks!

image description