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

Support incremental document updates #1141

Open
wants to merge 22 commits into
base: master
Choose a base branch
from

Conversation

david-driscoll
Copy link

Hi All,

I've recently run into a slow performance issue like #1126, and figured I would try an do something about it.

After doing some debugging and live testing, I determined that the issue is diagnostics are taking to long process. At that point I noticed the comment on IScriptSnapshot...

        /**
         * Gets the TextChangeRange that describe how the text changed between this text and
         * an older version.  This information is used by the incremental parser to determine
         * what sections of the script need to be re-parsed.  'undefined' can be returned if the
         * change range cannot be determined.  However, in that case, incremental parsing will
         * not happen and the entire document will be re - parsed.
         */
        getChangeRange(oldSnapshot: IScriptSnapshot): TextChangeRange | undefined;

My hypothesis is that all documents are being parsed and diagnostics are being recalculated for the entire process.

This changes does the following...

  1. Adds support for incremental updates over lsp
  2. Uses text edits to make incremental changes to documents
  3. Adds a new DocumentInfo class that contains the parsed regions for a given vue document, which are only recomputed on update.

With the new DocumentInfo class we can properly create a IScriptSnapshot for vue related files, which greatly improves the time it takes for diagnostics to be computed.

Things I'm still working on / would love help with.

  1. Unit Tests
    I seem to have broken something around stylus, not sure why.
  2. e2e tests
    The behaviors I'm seeing locally everything is working "normally" (this doesn't mean it's correct, it just appears to be working for me).

I have just recently got these changes working locally, so over the next few days I'll be using my updated server on some projects I'm working on to validate the changes.

@david-driscoll david-driscoll marked this pull request as ready for review March 8, 2019 03:59
@david-driscoll david-driscoll changed the title WIP: Incremental updates Support incremental document updates Mar 9, 2019
@david-driscoll
Copy link
Author

I think I've squared away most of the outstanding issues and I've gotten the integration tests passing successfully. Please feel free to let me know what other changes need to be made (commit messages, etc).

Thanks!

@octref
Copy link
Member

octref commented Mar 20, 2019

Wow, thank you so much for the contribution. I'm just starting to look into this.
Looks mostly fine. Let me upgrade to TS 3.3 and get back to you.

Meanwhile can you allow edits from maintainers?

@octref octref mentioned this pull request Mar 21, 2019
@david-driscoll
Copy link
Author

@octref I've checked off the allow maintainers to commit checkbox.

I'm also going to update to the latest master as well.

client/client.ts Outdated
@@ -29,11 +29,74 @@ export function initializeLanguageClient(vlsModulePath: string): LanguageClient
debug: { module: serverPath, transport: TransportKind.ipc, options: debugOptions }
};

const watcher = (() => {
const innerWatcher = vscode.workspace.createFileSystemWatcher('{**/*.js,**/*.ts}', true, false, true);
Copy link
Member

Choose a reason for hiding this comment

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

Listen to file creation as well, see #1091.

@@ -0,0 +1,4434 @@
{
Copy link
Member

Choose a reason for hiding this comment

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

Please use yarn instead of npm

@@ -0,0 +1,7071 @@
{
Copy link
Member

Choose a reason for hiding this comment

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

Please use yarn instead of npm

@@ -57,7 +57,7 @@ async function testReferences(docUri: vscode.Uri, position: vscode.Position, exp
expectedLocations.forEach(el => {
assert.ok(
result.some(l => {
return l.range.isEqual(el.range) && l.uri.path === el.uri.path;
return l.range.isEqual(el.range) && l.uri.path.toLowerCase() === el.uri.path.toLowerCase();
Copy link
Member

Choose a reason for hiding this comment

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

Is not changing this failing some tests?

While doing https://github.com/vuejs/vetur/pull/907/files#diff-3da884033e59974c36d7c1a57a067d8dR221 I realized serviceHost default to being case insensitive. I fixed that so you probably don't need this any more.

Copy link
Member

Choose a reason for hiding this comment

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

That caused some weird behaviors for me like #1170 (comment), when I upgraded to 3.3.

const result = vscode.languages.getDiagnostics(docUri);
let result: vscode.Diagnostic[] = [];
while (result.length === 0) {
await sleep(1000);
Copy link
Member

Choose a reason for hiding this comment

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

Thanks, I totally should have done that to avoid flakey diagnostic tests...

@@ -42,5 +42,5 @@ async function testDefinition(docUri: vscode.Uri, position: vscode.Position, exp
)) as vscode.Location[];

assert.ok(result[0].range.isEqual(expectedLocation.range));
assert.equal(result[0].uri.path, expectedLocation.uri.path);
assert.equal(result[0].uri.path.toLowerCase(), expectedLocation.uri.path.toLowerCase());
Copy link
Member

Choose a reason for hiding this comment

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

See the reference test comment.

Copy link
Author

Choose a reason for hiding this comment

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

I was again getting weird casing issues on my computer (windows) where the test was failing even the path was valid. in one case the path was c:/.../ vs C:/.../

@@ -10,7 +10,7 @@ describe('Should autocomplete for <script>', () => {
await showFile(scriptDocUri);
await sleep(FILE_LOAD_SLEEP_TIME);
// TS LS completion starts slow.
await sleep(2000);
await sleep(5000);
Copy link
Member

Choose a reason for hiding this comment

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

Not sure if this is the desperate change to fix the Stylus issue. If it's failing just leave it for now.

(match.documentation as vscode.MarkdownString).value,
(ei.documentation as MarkupContent).value
(match.documentation as vscode.MarkdownString).value.replace(/\r/g, ''),
(ei.documentation as MarkupContent).value.replace(/\r/g, '\n')
Copy link
Member

Choose a reason for hiding this comment

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

Why this change?

Copy link
Author

Choose a reason for hiding this comment

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

I was running into issues locally (I'm on windows) where the carriage return was causing tests to fail.


constructor(documentRegion: DocumentRegion) {
this.textSnapshot = documentRegion.document.getText() || '';
this.version = `${documentRegion.document.version}:${documentRegion.editRanges.length}`;
Copy link
Member

Choose a reason for hiding this comment

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

Why editRanges.length?

@octref
Copy link
Member

octref commented Apr 3, 2019

Looks very promising. Impressive work!

Adds a new DocumentInfo class that contains the parsed regions for a given vue document, which are only recomputed on update.

I'm wondering if you thought about matching textChange against region boundaries to only re-parse the region that has changed. It'll probably be another set of huge changes. We can leave that for another PR.

I seem to have broken something around stylus, not sure why.

Don't worry about that for now. I can take a look later.

The behaviors I'm seeing locally everything is working "normally" (this doesn't mean it's correct, it just appears to be working for me).

Travis sometimes are flakey. But I'd say don't skip the test suites. Let them fail with messages so i can dig into them as well.

IScriptSnapshot

Correct me if I'm wrong, but here's my understanding:

  • TS asks from ServiceHost a IScriptSnapshot when it needs the updated file
  • In the old model, we trigger diagnostics on each file change, which triggers TS to re-compute diagnostics on each file change.

If my understanding are correct, is debouncing on diagnostics (not file updates, just the diagnostic) likely to improve perf?

And for the part where you try to compute the diff between snapshots, I'd suggest keeping an ordered list of (textDocument, version, edits), and when asked for snapshot between (m, n), use the edits between (m, n) to figure out the ts.TextChangeRange and then drop every item before n.

Let me check with my friends in TS team to see how they handle the snapshots exactly...

@david-driscoll
Copy link
Author

I definitely need to fix up the snapshots a bit. I had originally had computing the text change range in place, but ran into inconsistency issues, so I dropped that for the moment. As I'm still seeing some performance issues depending on the vue file I'm running in, I'm probably going to try and add it back in and see what happens.

I'll try and work on fixing the conflicts today if I can, and then look at the ranges again.

@octref
Copy link
Member

octref commented Apr 10, 2019

Thanks, no hurries, I can try to resolve a few conflicts from master as well, since I made most of those changes...

@octref octref mentioned this pull request Apr 11, 2019
3 tasks
@david-driscoll
Copy link
Author

@octref I've merged all the changes against master now, and gotten everything working on my side.

Let me know what changes need to be made and I'll make them.

After this change is in I'm going to work on support for the vue-class-component and vue-property-decorator for intellisense as well.

PS: Just playing with the new template compiler support, and it's pretty awesome!

@david-driscoll
Copy link
Author

I'm currently working on the test failures locally, but I have a different set of failures than the failures in travis... yay!

@david-driscoll
Copy link
Author

Any feedback you might have to help fix them would be great as well.

@octref
Copy link
Member

octref commented Apr 26, 2019

Sorry for my lack of response, busy on other things. I'll make sure to get back to you tomorrow.

@david-driscoll
Copy link
Author

@octref no worries, I totally get being busy with other things! :)

@octref octref mentioned this pull request May 1, 2019
9 tasks
@garyo
Copy link

garyo commented Oct 19, 2019

Hi - I'm just wondering whether this PR might see the light of day sometime soon -- I'm seeing very slow performance with VLS and emacs lsp-mode and I'm hoping this would improve it.

@lanyizi lanyizi mentioned this pull request Aug 29, 2020
3 tasks
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.

3 participants