This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Debounce streams of updates.
ClosedPublic

Authored by sammccall on Feb 22 2018, 3:46 PM.

Details

Summary

Don't actually start building ASTs for new revisions until either:

  • 500ms have passed since the last revision, or
  • we actually need the revision for something (or to unblock the queue)

In practice, this avoids the "first keystroke results in diagnostics" problem.
This is kind of awkward to test, and the test is pretty bad.
It can be observed nicely by capturing a trace, though.

Event Timeline

sammccall created this revision.Feb 22 2018, 3:46 PM
ilya-biryukov added inline comments.Feb 23 2018, 2:13 AM
clangd/TUScheduler.cpp
142

Maybe make it const and put beside RunSync? Both are scheduling options, so it probably makes sense to group them together.

324

It looks like if we unwrap Optional<Deadline> to Deadline, we could replace this code with wait helper from Threading.h.
The tracing code (e.g. if (!Requests.empty) { /*...*/}) could be changed to log only when *Deadline - steady_clock::now() is positive.
Will probably make the code simpler. WDYT?

356

NIT: I tend to find multi-level nested statements easier to read with braces, e.g.

for (const auto &R : Requests) {
  if (Cond)
    return None
}

But this is up to you.

clangd/TUScheduler.h
55

As discussed offline, we want to expose the debounce parameter in ClangdServer, as there are existing clients of the code that already send updates with low frequency and it would be wasteful for them to do any extra waits.

sammccall marked 3 inline comments as done.

Make Deadline a real type with 0/finite/inf semantics.
Pull out another wait() overload.
Expose debounce delay option in clangdserver.

clangd/TUScheduler.cpp
324

Made Deadline a real type, and added a wait() overload without a condition.

ilya-biryukov added inline comments.Feb 26 2018, 7:29 AM
clangd/TUScheduler.h
56

Maybe we could remove this default argument now that ClangdServer also has the default debounce?
I guess the key thing that bothers me is having multiple places that have the magical default constant of 500ms, it would be nice to have it in one place.

clangd/Threading.h
76

Maybe prefer grouping all the fields together? It seems we're giving that up to avoid writing one extra instance of enum Type.

enum Type { Zero, Infinite, Finite };
Deadline(enum Type Type) : Type(Type) {}

enum Type Type;
std::chrono::steady_clock::time_point Time;
83

s/Wait for on/Wait on/?

unittests/clangd/TUSchedulerTests.cpp
97

I wonder if the default debounce of 500ms will make other tests (especially those that use ClangdServer) too slow?
Maybe we should consider settings a smaller default (maybe even Deadline::zero()?) and having 500ms set only by ClangdLSPServer?

sammccall marked 4 inline comments as done.Feb 27 2018, 1:17 AM

Thanks for catching all those things!

unittests/clangd/TUSchedulerTests.cpp
97

Good point.
For now I've changed the ClangdServer default to 20ms, with a comment that this is for tests (to make sure we're testing the "real" codepath).
After pulling out the options struct, I'd like to gave a function that returns default options to be used in tests (in-memory preambles, fixed number of threads, short debounce) and make
500ms the "real" default.

sammccall updated this revision to Diff 136045.Feb 27 2018, 1:18 AM
sammccall marked an inline comment as done.

review comments

This revision is now accepted and ready to land.Feb 28 2018, 2:00 AM
This revision was automatically updated to reflect the committed changes.