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

more stable autocomplete #442

Merged
merged 2 commits into from
Aug 2, 2023
Merged

more stable autocomplete #442

merged 2 commits into from
Aug 2, 2023

Conversation

sqs
Copy link
Member

@sqs sqs commented Jul 28, 2023

Makes autocomplete not jitter as much as you type, with a cache and a few other techniques to help increase the (1) cache hit rate and (2) VS Code's ability to reuse and not invalidate existing completion results.

Why this change?

  • Extract the non-VS Code-specific parts of getInlineCompletions so we can separately test it and the InlineCompletionItemProvider logic.
    • All test cases were ported to the new getInlineCompletions (and all pass without modification in substance).
    • This also helps with extracting completions to the agent.
  • Make the cache and RequestManager simpler and dumber by exploiting VS Code's existing behavior (of showing w/o jitter a full-line inline completion while it is refreshed in the background).
    • Remove the existing cache entirely and replace it with a simpler cache that just memoizes calls (inside RequestManager) and does not have any other text logic.
    • Make the RequestManager not need to support logId rewriting or retesting caches for a document (see below).
  • Separately handle the case of "typing the last suggestion" (e.g., typing as suggested by the ghost text) vs. the general case of cached network requests. This case is the only one where we want to reuse the previous logId, and we can do so simply instead of (if the 2 cases are conflated) requiring the cache to support logId rewriting.

Examples of bugs or undesirable behaviors this fixes:

  • Absolute minimum jitter when deleting or typing ghost text.
  • As long as you are still typing ghost text exactly as suggested, it won't replace it underneath you with a new completion.
  • If you delete through ghost text past the initial trigger point, it will always suggest something new.
  • When you press delete on an empty but indented line with ghost text, the ghost text remains in place (no jitter) until you type something different.

Test plan

Use completions and watch the logIds. Try typing or deleting over ghost text.

@sqs sqs requested a review from a team July 28, 2023 11:25
Copy link
Contributor

@philipp-spiess philipp-spiess left a comment

Choose a reason for hiding this comment

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

Nice! I like the changes. Some comments inline. I think with this approach, the LRUCache map doesn't really make sense as a data-structure. I think the way we use it, we also don't count when a cached completion is retrieved so this behaves more like a fifo queue now where an array might be enough?

The changes look good though. I would argue that it's not simpler though, there's more custom behavior that the cache now implements (previously it conceptually was just a map). However, the implementation is easier - the map lookup was definitely a premature optimization from my side!

vscode/src/completions/cache/cache.ts Outdated Show resolved Hide resolved
vscode/src/completions/completion.test.ts Outdated Show resolved Hide resolved
vscode/src/completions/index.ts Outdated Show resolved Hide resolved
vscode/src/completions/index.ts Outdated Show resolved Hide resolved
@sqs
Copy link
Member Author

sqs commented Jul 28, 2023

@philipp-spiess Thank you for the comments! All great points. And after sleeping on it, I see a bunch more places where it needs work. Will keep this in draft and keep working on it.

@sqs sqs force-pushed the sqs/autocomplete-frequency branch from 8491fd5 to cb7484a Compare July 28, 2023 22:05
@sqs sqs force-pushed the sqs/autocomplete-frequency branch from cb7484a to 4598931 Compare July 28, 2023 22:07
@sqs
Copy link
Member Author

sqs commented Jul 28, 2023

@philipp-spiess I think we can significantly simplify the cache from what I have here and use VS Code's builtin "reuse" logic more. Stay tuned...

@sqs sqs force-pushed the sqs/autocomplete-frequency branch 2 times, most recently from 0574363 to 4f13667 Compare July 29, 2023 00:27
@sqs sqs force-pushed the sqs/autocomplete-frequency branch from 4f13667 to f52b135 Compare July 29, 2023 04:14
sqs added a commit that referenced this pull request Jul 29, 2023
This just makes it harder to debug. VS Code catches errors at a higher level anyway.

TODO See #442 (comment)
sqs added a commit that referenced this pull request Jul 29, 2023
This just makes it harder to debug. VS Code catches errors at a higher level anyway.

TODO See #442 (comment)
@sqs sqs force-pushed the sqs/autocomplete-frequency branch 7 times, most recently from facee19 to 1cecf95 Compare July 29, 2023 05:51
sqs added a commit that referenced this pull request Jul 29, 2023
This just makes it harder to debug. VS Code catches errors at a higher level anyway.

TODO See #442 (comment)
@sqs sqs force-pushed the sqs/autocomplete-frequency branch 4 times, most recently from d320ecd to 59bdab1 Compare July 29, 2023 09:30
@sqs sqs force-pushed the sqs/autocomplete-frequency branch 2 times, most recently from 369992c to 7931ba6 Compare August 1, 2023 05:20
sqs added a commit that referenced this pull request Aug 1, 2023
This just makes it harder to debug. VS Code catches errors at a higher level anyway.

TODO See #442 (comment)
@sqs sqs force-pushed the sqs/autocomplete-frequency branch 4 times, most recently from 2dac20b to a65938a Compare August 1, 2023 07:31
@sqs sqs marked this pull request as ready for review August 1, 2023 07:34
@sqs sqs changed the title WIP more stable autocomplete more stable autocomplete Aug 1, 2023
@sqs
Copy link
Member Author

sqs commented Aug 1, 2023

Note: This PR is based on the following other PRs that will be merged independently (then this PR branch will be rebased):

@sqs sqs requested a review from philipp-spiess August 1, 2023 07:49
@philipp-spiess
Copy link
Contributor

Separately handle the case of "typing the last suggestion" (e.g., typing as suggested by the ghost text) vs. the general case of cached network requests. This case is the only one where we want to reuse the previous logId, and we can do so simply instead of (if the 2 cases are conflated) requiring the cache to support logId rewriting.

This is great, thanks. I was chatting with @vovakulikov yesterday and came to the same conclusion that these are two different scenarios and wanted to post a PR today to do the same 😅

@philipp-spiess
Copy link
Contributor

@sqs This feels very good to use now, wow!

I noticed one case where it's a bit funky still. If you see ghost text and press space, the previous ghost text will stay visible but we do fire off a new request that will eventually replace the visible text, causing some UI churn:

Screen.Recording.2023-08-01.at.11.40.03.mov

Copy link
Contributor

@philipp-spiess philipp-spiess left a comment

Choose a reason for hiding this comment

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

This is a great clean up! I left two inline comments + the main comment in the PR about the remaining "jitter" case (the latter is minor and I’m fine with fixing it later)

vscode/src/completions/getInlineCompletions.ts Outdated Show resolved Hide resolved
Comment on lines -102 to -121
it('serves request from cache when a prior request resolves', async () => {
const prefix1 = 'console.'
const provider1 = createProvider(prefix1)
const promise1 = createRequest(prefix1, provider1)

const prefix2 = 'console.log('
const provider2 = createProvider(prefix2)
const promise2 = createRequest(prefix2, provider2)

provider1.resolveRequest(["log('hello')"])

expect((await promise1)[0].content).toBe("log('hello')")
expect((await promise2)[0].content).toBe("'hello')")

expect(provider1.didFinishNetworkRequest).toBe(true)
expect(provider2.didFinishNetworkRequest).toBe(false)

// Ensure that the completed network request does not cause issues
provider2.resolveRequest(["'world')"])
})
Copy link
Contributor

Choose a reason for hiding this comment

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

Did you remove this logic on purpose? Looking at the logs, it does trigger on almost ~10% of requests: https://sourcegraph.looker.com/x/PEfxGviZvYk8tmvTFGIDVr

Copy link
Contributor

Choose a reason for hiding this comment

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

Thinking about this more, I guess the issue is that the new network caching is no longer able to synthesise completions. Hmm.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I did remove it for that reason. I did not realize it triggered in ~10% of requests. That is substantial. Do you think this retest-cache behavior is important to preserve for perf? I am not confident in my intuition about the impact from reading the code just now.

Copy link
Contributor

Choose a reason for hiding this comment

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

@sqs My intuition is yes. It was also the main motivation for not cancelling inflight requests when a new completion is triggered.

I’m less confident on wether it had a big impact on the overall metrics (something had in the period this rolled out, but we tweaked a bunch of different things) however I could definitely notice the change in my IDE, especially when typing because sometimes you just get immediate completion results and it feels magical.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'll keep an eye on the metrics and if the latency regresses we know what to do 👍

@sqs sqs force-pushed the sqs/autocomplete-frequency branch 3 times, most recently from 9bc8992 to 9c9ae5a Compare August 2, 2023 03:47
@sqs
Copy link
Member Author

sqs commented Aug 2, 2023

@philipp-spiess Thanks! I will address the remaining things and get this merged.

@sqs sqs force-pushed the sqs/autocomplete-frequency branch from 3048ea0 to d2b3b0b Compare August 2, 2023 09:42
@sqs sqs force-pushed the sqs/autocomplete-frequency branch from d2b3b0b to a731012 Compare August 2, 2023 09:46
@sqs sqs force-pushed the sqs/autocomplete-frequency branch from a731012 to 5a5a7c7 Compare August 2, 2023 09:51
@sqs
Copy link
Member Author

sqs commented Aug 2, 2023

@philipp-spiess Thanks! I just fixed the issue you raised at #442 (comment) and added a lot more tests for the typing-as-suggested-by-last-candidate case.

@sqs sqs enabled auto-merge (squash) August 2, 2023 09:51
@sqs sqs merged commit 1f04aaa into main Aug 2, 2023
8 checks passed
@sqs sqs deleted the sqs/autocomplete-frequency branch August 2, 2023 09:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants