Skip to content

perf(workspace): find the statement for completions without going over the whole file - #984

Open
psteinroe wants to merge 1 commit into
perf/workspace-walk-checkpointsfrom
perf/completions-statement-lookup
Open

psteinroe wants to merge 1 commit into
perf/workspace-walk-checkpointsfrom
perf/completions-statement-lookup

Conversation

@psteinroe

Copy link
Copy Markdown
Collaborator

Stacked on #982. It only touches the workspace, and it needs Document::split from #964 and the stack-safe ParseIterator from #956. It doesn't depend on #983, but the numbers below were measured with #983 applied too.

Every completion request had a cost linear in the file before it got to the completion itself. get_statement_for_completions called Document::count(), which runs every statement through the statement iterator: a parse-cache lookup for each statement, a check for a SQL function body, and a copy of its text. Then it ran GetCompletionsFilter over all statements to find the ones around the cursor. At 20,000 statements that was about 50 ms per keystroke.

What changed

  • The count only decides between no statement, one, or more, so it stops after two: doc.iter(DefaultMapper).take(2).count(). Document::count had no other user and is removed.
  • Document::iter_for_completions(mapper, position) runs the same filter, but only over the top-level statements that it can accept. Those contain the cursor, or end at most two characters before it. Two binary searches over the split's ranges find them. The bodies of SQL functions are inside their top-level statement, so they are still included.

Test

finds_the_statement_like_a_filter_over_all_statements builds a document with every case the filter cares about:

  • statements with and without ;;
  • two statements on one line;
  • an unterminated statement at the end;
  • a SQL function with two statements in its body;
  • blank lines.

At every position, it compares the result with the lookup from before, which filters all statements. The existing completion tests pass.

Numbers

Release build, 20 keystrokes, the scenarios from #982, with #983 applied. #982 + #983 → this PR:

per keystroke, completions 5,000 statements 20,000 statements
edit near the start, request there 20.5 → 11.9 ms 63.7 → 12.2 ms
edit in the requested statement near the end 42.1 → 31.3 ms 159 → 101 ms
edit 3 statements above, near the end 45.5 → 34.4 ms 165 → 129 ms

What remains near the end of the file is mostly pgls_completions::complete itself, which goes over the 5,000 tables, 20,000 columns and 5,000 functions that the file adds to the snapshot. A database with that many objects costs the same.

…r the whole file

get_statement_for_completions counted every statement of the document, which maps each of
them and looks up its parse result, and then filtered all statements for the ones around the
cursor. It only needs to know whether there are none, one or more statements, and the filter
only accepts statements that contain the cursor or end up to two characters before it, so it
now looks at those only.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant