Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cache and re-use type bindings for a completion invocation #2535

Merged
merged 1 commit into from
Apr 4, 2023

Conversation

snjeza
Copy link
Contributor

@snjeza snjeza commented Mar 14, 2023

A related issue - redhat-developer/vscode-java#2982

Steps to reproduce

$ git clone https://github.com/snjeza/jhipster-lite
$ cd jhipster-lite
$ code .
  • enable lombok
  • open AssertTest.java
private void test() {
    D d = new D| // try CA here
  }

See redhat-developer/vscode-java#2982 (comment)

@snjeza snjeza changed the title [WIP] Performance improvement when lombok is present Performance improvement when lombok is present Mar 15, 2023
@rgrunber rgrunber added this to the Early April 2023 milestone Mar 30, 2023
@rgrunber
Copy link
Contributor

The improvement here is huge. Goes from ~28s to ~2s on my machine, for completion response. Just 2 main questions for now :

  • Jinbo has an old patch at https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/191217 . Would that also improve this situation ? Would that allow us potentially undo this patch later ?
  • I didn't see the code action response taking long. Is the cancellation really needed for calculating each one ? I would assume some code actions might require re-parsing of certain source files, but wasn't seeing performance degradation there.

@jdneo
Copy link
Contributor

jdneo commented Mar 30, 2023

Lazy resolving is a powerful tool to solve the problem. Just one thing I would like to mention: For now, updating the text edit during resolving is still not recommended in the spec, if we decide to go that way, we are on our own for the correctness.

Personally, I think it's worth trying - considering the huge amount of boost we can get (~28s to ~2s). I believe the time cost can be even faster if we use the approach to other cases. But in case that one day the behavior of VS Code changes, which might break our completion functions. I would suggest that we introduce a switch of the completion behavior. The switch controls whether we will lazily resolve the completions. In that way, at least we have a fall back if the regression happens in the future.

@jdneo
Copy link
Contributor

jdneo commented Mar 30, 2023

I have same question as @rgrunber has for the code action part. Are all the cancellation checks necessary? How does the perf looks like if we only keep the change for the completion resolving part?

What about separating the change of adding cancellation checks for code actions to another PR? Because they are trying to solve the perf issue from different aspects.

@snjeza
Copy link
Contributor Author

snjeza commented Mar 30, 2023

Jinbo has an old patch at https://git.eclipse.org/r/c/jdt/eclipse.jdt.core/+/191217 . Would that also improve this situation ? Would that allow us potentially undo this patch later ?

I will check this patch, but it isn't related to this patch.

I didn't see the code action response taking long. Is the cancellation really needed for calculating each one ? I would assume some code actions might require re-parsing of certain source files, but wasn't seeing performance degradation there.

What about separating the change of adding cancellation checks for code actions to another PR? Because they are trying to solve the perf issue from different aspects.

I will separate them.

@snjeza snjeza changed the title Performance improvement when lombok is present [WIP] Performance improvement when lombok is present Mar 30, 2023
@snjeza
Copy link
Contributor Author

snjeza commented Mar 30, 2023

@rgrunber @jdneo @CsCherrYY I have updated the PR. It includes only the completion resolving part.

@snjeza snjeza changed the title [WIP] Performance improvement when lombok is present Performance improvement when lombok is present Mar 30, 2023
@snjeza
Copy link
Contributor Author

snjeza commented Mar 30, 2023

Lazy resolving is a powerful tool to solve the problem. Just one thing I would like to mention: For now, updating the text edit during resolving is still not recommended in the spec, if we decide to go that way, we are on our own for the correctness.

A related issue - #2453

@rgrunber
Copy link
Contributor

rgrunber commented Mar 30, 2023

Lazy resolving is a powerful tool to solve the problem. Just one thing I would like to mention: For now, updating the text edit during resolving is still not recommended in the spec, if we decide to go that way, we are on our own for the correctness.

A related issue - #2453

#2453 (comment) implies we should be ok to lazily resolve. Either way, if we're doing it in other places, we should be fine to at least do it here also.

Update: Jinbo's patch was about caching the type argument info for a constructor completion proposal. This patch completely avoid computing that until the resolve phase. That's why I thought maybe when we get that patch approved, it could provide some performance improvement without having to resolve lazily.

@snjeza snjeza force-pushed the issue-2982 branch 2 times, most recently from 9ad00f3 to 4e8ad3a Compare March 30, 2023 03:54
@jdneo
Copy link
Contributor

jdneo commented Mar 30, 2023

#2453 (comment) implies we should be ok to lazily resolve. Either way, if we're doing it in other places, we should be fine to at least do it here also.

@rgrunber Well, my comment in that issue was not correct. (After I thought about it twice)😥

My understanding of the Dirk's response is that:

  • The spec does not have any restrictions on what data cannot be resolved during completion resolve phase.
  • The choice leaves to the client implementation. To be specific, it's controlled by the resolveSupport field sent from client to server. In the case of VS Code, the supported properties are:
"resolveSupport": {
    "properties": [
        "documentation",
        "detail",
        "additionalTextEdits"
    ]
},

Which means we are violating the spec if we update the textEdit during completion/resolve.

AFAIK, besides this PR and #2453, the generic server side snippet is also lazy resolved. Luckily, they are working fine in most cases. But there is no guarantee they will still work in the future.

That's why I suggest having a setting to control the resolve behavior. With that setting exist, I'm feeling safe to leverage lazy resolve approach to more cases.

@snjeza
Copy link
Contributor Author

snjeza commented Mar 30, 2023

That's why I suggest having a setting to control the resolve behavior. With that setting exist, I'm feeling safe to leverage lazy resolve approach to more cases.

@jdneo @rgrunber We should add textEdit to resolveSupport in vscode-java.
See #2453 (comment)

@rgrunber
Copy link
Contributor

@snjeza , so could we modify this change to check the resolve support capability contains the textEdit property ? Then clients can enable/disable.

@snjeza
Copy link
Contributor Author

snjeza commented Mar 30, 2023

@rgrunber Right. See https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#completionClientCapabilities

/**
		 * Indicates which properties a client can resolve lazily on a
		 * completion item. Before version 3.16.0 only the predefined properties
		 * `documentation` and `detail` could be resolved lazily.
		 *
		 * @since 3.16.0
		 */
		resolveSupport?: {
			/**
			 * The properties that a client can resolve lazily.
			 */
			properties: string[];
		};

@rgrunber
Copy link
Contributor

rgrunber commented Apr 3, 2023

@snjeza your new change looks to save the same amount of time as before 🎉 . It makese sense to cache the known bindings for that particular instance of completion activation. However I'm not seeing any major benefit for publishing diagnostics. I'll try to see how much time is spent in that block of code you've removed. Looking at it, I'm not sure why we went from ICompilationUnit to CompilationUnit back to ICompilationUnit :\ Definitely seems simpler to remove it.

Update There's might be some improvement for publishDiagnostics. I can definitely agree that the block took a few hundred ms to run (from timing it), but comparing before/after shows only around ~100ms improvement.

Old: 604 638 669 699 714 748 786 823 923 961 1042 1255 5345
New: 463 541 560 621 650 656 661 680 728 740 767 1196 4240

@snjeza
Copy link
Contributor Author

snjeza commented Apr 3, 2023

@rgrunber Could you try the following

$ rm -rf jhisper-lite
$ git clone https://github.com/snjeza/jhipster-lite
$ cd jhipster-lite
$ code .
  • enable lombok
  • open AssertTest.java
private void test() {
    D d = new D| // try CA here
   // type
  Model56 model56 = new Model56();
  model56.getWeight()

  }
  • check line Validated X. Took XXX ms

You should test it using VS Code Pre-Release and VS Code Java 1.17.3

@snjeza
Copy link
Contributor Author

snjeza commented Apr 3, 2023

I'm not sure why we went from ICompilationUnit to CompilationUnit back to ICompilationUnit :\ Definitely seems simpler to remove it.

We used AST before we separated publishDiagnostics and introduced reconcile at https://github.com/eclipse/eclipse.jdt.ls/blob/master/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/handlers/BaseDocumentLifeCycleHandler.java#L306

@rgrunber
Copy link
Contributor

rgrunber commented Apr 3, 2023

I'll try again with your suggestions. FWIW I did use the validation line when comparing. Either way, I'll have a closer look, and hopefully we can merge since the change should be more acceptable now.

Comment on lines 943 to 945
if (bindings.get(keys[0]) instanceof ITypeBinding) {
return (ITypeBinding) bindings.get(keys[0]);
}
Copy link
Contributor

@testforstephen testforstephen Apr 4, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To keep consistent as previous implementation, it can be

		if (bindings.size() > 0) {
			return (ITypeBinding) bindings.get(keys[0]);
		}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

@testforstephen
Copy link
Contributor

The publish diagnostics and typebinding cache are two different optimization, you may split them to different PRs. The typebinding cache is pretty straightforward, it's safe to merge first.

@snjeza snjeza changed the title Performance improvement:constructor CA and publish diagnostics [WIP] Performance improvement:constructor CA and publish diagnostics Apr 4, 2023
@snjeza snjeza force-pushed the issue-2982 branch 2 times, most recently from fc6db2b to c0fcfe0 Compare April 4, 2023 14:47
@snjeza
Copy link
Contributor Author

snjeza commented Apr 4, 2023

The publish diagnostics and typebinding cache are two different optimization, you may split them to different PRs. The typebinding cache is pretty straightforward, it's safe to merge first.

See #2574

@snjeza
Copy link
Contributor Author

snjeza commented Apr 4, 2023

@fbricon @rgrunber @testforstephen @jdneo @CsCherrYY I have updated the PR.
You can also review #2574

@snjeza snjeza changed the title [WIP] Performance improvement:constructor CA and publish diagnostics Performance improvement:constructor CA and publish diagnostics Apr 4, 2023
@snjeza snjeza removed the in progress label Apr 4, 2023
@snjeza snjeza changed the title Performance improvement:constructor CA and publish diagnostics Performance improvement:constructor CA Apr 4, 2023
@rgrunber rgrunber removed their assignment Apr 4, 2023
Copy link
Contributor

@rgrunber rgrunber left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. Could you change the commit title to :

Cache and re-use type bindings for a completion invocation

Then feel free to merge.

@snjeza snjeza changed the title Performance improvement:constructor CA Cache and re-use type bindings for a completion invocation Apr 4, 2023
snjeza added a commit to snjeza/eclipse.jdt.ls that referenced this pull request Apr 4, 2023
Remove CoreASTProvider.getAST(...) from BaseDocumentLifeCycleHandler.publishDiagnostics(IProgressMonitor)
- eclipse-jdtls#2535

Signed-off-by: Snjezana Peco <snjezana.peco@redhat.com>
@snjeza
Copy link
Contributor Author

snjeza commented Apr 4, 2023

test this please

Signed-off-by: Snjezana Peco <snjezana.peco@redhat.com>
@snjeza snjeza merged commit c73f7a2 into eclipse-jdtls:master Apr 4, 2023
snjeza added a commit to snjeza/eclipse.jdt.ls that referenced this pull request Apr 5, 2023
Remove CoreASTProvider.getAST(...) from BaseDocumentLifeCycleHandler.publishDiagnostics(IProgressMonitor)
- eclipse-jdtls#2535

Signed-off-by: Snjezana Peco <snjezana.peco@redhat.com>
rgrunber pushed a commit that referenced this pull request Apr 6, 2023
Remove CoreASTProvider.getAST(...) from BaseDocumentLifeCycleHandler.publishDiagnostics(IProgressMonitor)
- #2535

Signed-off-by: Snjezana Peco <snjezana.peco@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants