1
头图

a98d4a96a950533cf8f17c105095ff69.png
Nick zhu
Senior Program Manager, Developer Division at Microsoft

Hi everyone, and welcome to the latest Visual Studio Code Java update! In this article, we will deeply analyze the performance optimization of the recent code completion.

Performance improvement-faster code completion

of Java Language Server 1.0 version , we have made significant improvements to the performance of code completion. The figure below compares the code completion response time between recent versions. For common scenarios such as completion types and constructor names, the code completion performance is significantly improved compared to the previous version (v0.80, v0.81, v.0.82).

12bccd2c6e06092b3c7f0e5b138f7e4c.png

Performance improvement overview

The code completion engine consists of three stages:

  • Phase One (P1)-Search the indexer to find suggestions
  • Phase Two (P2)-Converting suggestions to supplementary information
  • Phase Three (P3)-Calculate the code snippet proposal

Based on our analysis, we found that there is room for improvement in all three stages. The following table shows the improvements we have made in the past version. We will discuss the details of these changes in more detail in the next section.

c08fe02355af9591be3654e7098a5518.png

Key change details

Version 0.81.0-Reduce Windows I/O operations. #1831

In the past performance tests, we found that a large part of the time cost was spent on calculating the file URI. This finding supports our previous observation: due to the platform-specific file system-related implementation in the JVM, the code completion performance on the Windows platform is relatively poor. By removing unnecessary URI calculations, we have improved performance, especially on the Windows platform.

Version 0.81.0-Optimization of constants/default values. #1835

When we complete a constant field (such as Constants.*), the completion pop-up window will display the suggested field name and its constant value (such as Bit1: int = 1) in the selection list. Our analysis found that when the class contains a large number of constant field members, this will make the completion very slow. This is because we calculate the field value from the AST Tree, which is very expensive when operating large files.

In order to optimize it, we decided to postpone the analysis of constant values. Code completion will simplify the suggested label and display only the field name (for example, Bit1:int). When you hover the mouse over the completion item of Javadoc, its constant value will be displayed in the Javadoc section.

The following is a performance comparison of a class with more than 1400 rows and more than 150 constant fields.

7a9bf67fb36a3d94db8021b6a489e5a4.png

Version 0.82.0-Delay resolving generic snippets. #1838

There are two types of code snippets:

  • Common fragments (such as foreach, fori, ifelse, etc.)
  • Type definition fragments (such as classes, interfaces, etc.)

For general code snippets, it evaluates the template with a given context before building the "TextEdit" of the finished item, and such evaluation can be expensive. We now postpone this type of assessment to the resolution stage. After the completion of the code completion item is created, the template mode will be filled as a placeholder. The actual value is evaluated during the resolution phase, which does not prevent the display of the completed project. This is also an experiment on the extent to which "delayed parsing of TextEdit" can improve performance, and in most cases, it should work well.

Version 0.82.0-Optimize for anonymous constructors. #1836

When we want to complete a new Runnable, the desired result is this:

Runnable() {}

It consists of two parts

  • Runnable name
  • Blank body fragment body () {\n\t\n}

Through performance analysis, we found that CodeFormatUtil.format took a lot of time.

In order to have a correct indentation and line separator, they are formatted as the current preferences. Formatting is expensive, and the same content (empty body) is repeatedly formatted for all items (sometimes as many as thousands). In order to improve it, we formatted the empty body in a one-time operation and reused it in all projects.

Version 1.0.0-Improve code completion search speed

In order to optimize index search performance, we made two key changes.

Our performance analysis shows that 97% of the CPU time of the index query task is used for I/O operations to load the index content from the disk. This is because the indexing mechanism we use tends to save memory and use very little cache in search engines. Almost every query must reload the index content from disk. A direct optimization is to reduce the frequency of I/O.

The Java indexer is composed of multiple hash tables, and each hash table is used to record a certain type of code part, such as type declarations, method declarations, references, method references, etc. A typical query job reads one or more hash tables from the index, and then joins these to index the entries into the target result.

When we complete the type/constructor name (such as Str or new Str), the index query job reads two hash tables, one is used to find the typeDecl table of the matching type name, and the other is used to find the path of the class file The documentName table declares the corresponding type. Since our purpose is only to complete the type name and automatically import the corresponding package, the typeDecl table is sufficient to meet our requirements, and the class file path is not required. Our optimization is to read only the typeDecl index table, and it turns out that reading one less index table can save a lot of I/O costs.

This change comes from the contribution of community developers to the upstream JDT project. The Java index uses UTF-8 to encode index characters. When loading the indexes, we decode them back. Since most index characters are only ASCII characters, we optimized the decoding method to make it faster to read ASCII.

Future plan

The improvements we listed above make the auto-completion faster, but we haven't done it yet. In the future, performance is still our top priority, and we will continue to optimize auto-complete performance. Here are some of the projects we plan in the coming months:

Lazy Resolve TextEdit

Since most language clients do not support delayed resolution text editing of completed items, the Java language server must calculate the text editing of all completed items in the response. This is the reason for the most expensive calculation. We are working with the author to explore support for delayed parsing text editing.

More Efficient Indexer

The current index data is not enough for some code completion scenarios such as constructors. For example, the completion of the constructor needs to know whether the class has generic type parameters, and decide whether to add a diamond <> in the constructor reference. The constructor index table does not contain such type parameter information, we must parse them from the Java model, and such parsing operations are costly. We are considering optimizing the index structure to include more information.

Feedback and suggestions

Please actively use our products! Your feedback and suggestions are very important to us and will help us do better. There are several ways to leave us feedback:

resource

The following links and resources can help you better understand Java on Visual Studio Code related information


Welcome to follow the Microsoft China MSDN subscription account for more latest releases!
image.png


微软技术栈
423 声望996 粉丝

微软技术生态官方平台。予力众生,成就不凡!微软致力于用技术改变世界,助力企业实现数字化转型。