sammccall added a comment.

Had some discussion offline.

- having ASTWorker not worry about preamble validity before dispatching to 
preambleworker seems like a win
- for this, preambleworker needs to call preambleReady whether it's new or not, 
so ASTWorker can produce diagnostics
- AST reuse from diagnostics->request seems much more useful than the other way 
around (e.g. it reduces request latency), so don't bother with the latter. (And 
we can drop diagnostic computation in some cases)

This yields pseudocode like:

  ASTWorker::update(): enqueue({
    currentInputs = inputs
    preambleworker::update(inputs)
  })
  ASTWorker::runWithAST(): enqueue({
    ast = cache.get()
    if (!ast) patch preamble and build ast
    action(ast)
    cache.put(ast)
  })
  PreambleWorker::update(): enqueue({
    if (!preamble.compatible(inputs))
      build preamble
    ASTWorker::preambleReady(preamble)
  })
  ASTWorker::preambleReady(): enqueue({
    preamble = p
    build ast
    publish ast.diagnostics
    if (inputs == currentInputs) cache.put(ast)
    else if (preamble != oldPreamble) cache.get() // force next read to use 
this preamble
  })

(I'm not sure how simple the actual code can be. I do think defining the 
methods in that order may help readability)



================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:8
 
//===----------------------------------------------------------------------===//
-// For each file, managed by TUScheduler, we create a single ASTWorker that
-// manages an AST for that file. All operations that modify or read the AST are
-// run on a separate dedicated thread asynchronously in FIFO order.
+// TUScheduler stores a worker per active file. This worker is called ASTWorker
+// and manages updates(modifications to file contents) and reads(actions
----------------
nit: just "This ASTWorker manages updates..."


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:8
 
//===----------------------------------------------------------------------===//
-// For each file, managed by TUScheduler, we create a single ASTWorker that
-// manages an AST for that file. All operations that modify or read the AST are
-// run on a separate dedicated thread asynchronously in FIFO order.
+// TUScheduler stores a worker per active file. This worker is called ASTWorker
+// and manages updates(modifications to file contents) and reads(actions
----------------
sammccall wrote:
> nit: just "This ASTWorker manages updates..."
uber-nit: I'd say the scheduler *manages* workers and the worker *processes* 
updates.
(Just to avoid mixing metaphors)


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:9
+// TUScheduler stores a worker per active file. This worker is called ASTWorker
+// and manages updates(modifications to file contents) and reads(actions
+// performed on preamble/AST) to the file.
----------------
nit: space before open parens (not a big deal, but occurs several times)


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:16
 //
-// The processing thread of the ASTWorker is also responsible for building the
-// preamble. However, unlike AST, the same preamble can be read concurrently, 
so
-// we run each of async preamble reads on its own thread.
+// An update request changes latest inputs to ensure any subsequent read sees
+// the version of the file they were requested. In addition to that it might
----------------
changes latest inputs -> replaces the current parser inputs

("changes" suggests some tricky mutation, and inputs isn't defined here)


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:17
+// An update request changes latest inputs to ensure any subsequent read sees
+// the version of the file they were requested. In addition to that it might
+// result in publishing diagnostics.
----------------
You need to mention "building an AST" here, as you reference it below.


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:25
 //
-// Rationale for cancelling updates.
-// LSP clients can send updates to clangd on each keystroke. Some files take
-// significant time to parse (e.g. a few seconds) and clangd can get starved by
-// the updates to those files. Therefore we try to process only the last 
update,
-// if possible.
-// Our current strategy to do that is the following:
-// - For each update we immediately schedule rebuild of the AST.
-// - Rebuild of the AST checks if it was cancelled before doing any actual 
work.
-//   If it was, it does not do an actual rebuild, only reports llvm::None to 
the
-//   callback
-// - When adding an update, we cancel the last update in the queue if it didn't
-//   have any reads.
-// There is probably a optimal ways to do that. One approach we might take is
-// the following:
-// - For each update we remember the pending inputs, but delay rebuild of the
-//   AST for some timeout.
-// - If subsequent updates come before rebuild was started, we replace the
-//   pending inputs and reset the timer.
-// - If any reads of the AST are scheduled, we start building the AST
-//   immediately.
+// ASTWorker processes the file in two parts, a preamble and a mainfile
+// section. A preamble can be reused between multiple versions of the file if 
it
----------------
nit: we use "main file" or "main-file" much more often than "mainfile".


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:26
+// ASTWorker processes the file in two parts, a preamble and a mainfile
+// section. A preamble can be reused between multiple versions of the file if 
it
+// isn't invalidated by a modification to a header, compile commands or
----------------
it it isn't -> until?


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:29
+// modification to relevant part of the current file. Such a preamble is called
+// usable.
+// In the presence of stale(non-usable) preambles, ASTWorker won't publish
----------------
I don't think "usable" is a good name for this, because we *use* preambles that 
are not "usable".

I think "compatible" or "up-to-date" or "fresh" or so would have enough 
semantic distance to make this less confusing.


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:37
+// invalidated by an update request, a new build will be requested on
+// PreambleThread. PreambleThread serves those requests by building preambles 
on
+// a dedicated thread. Since PreambleThread only receives requests for newer
----------------
 Nit: first and third sentences in this paragraph say the same thing, drop the 
third?


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:43
+//
+// Whenever PreambleThread finishes a build, ASTWorker will enqueue a task to
+// build a new AST using that preamble, called golden AST to publish
----------------
This gets a bit far into implementation details (uses of queues etc) and is 
hard to follow. Maybe:

When a new preamble is built, a "golden" AST is immediately built from that 
version of the file.
This ensures diagnostics get updated even if the queue is full.


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:48
+// ASTWorker queue is full.
+// These golden ASTs also ensures diagnostics are always for newer versions of
+// the file. As diagnostics are only published for update requests after a
----------------
This is talking about the subtleties of ordering/version guarantees - not 
really interesting from the outside, and not enough detail here to avoid 
reading the code. I'd suggest moving these to preambleReady or so.


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:233
+              std::vector<Diag> CIDiags, WantDiagnostics WantDiags) {
     // Make possibly expensive copy while not holding the lock.
+    Request Req = {std::make_unique<CompilerInvocation>(CI), std::move(PI),
----------------
Some params get copied explicitly, others get passed by value. Pick one 
strategy?


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:235
+    Request Req = {std::make_unique<CompilerInvocation>(CI), std::move(PI),
+                   std::move(CIDiags), std::move(WantDiags),
+                   Context::current().clone()};
----------------
nit: WantDiags is an enum, no move


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:254
   void run() {
-    dlog("Starting preamble worker for {0}", FileName);
+    dlog("PreambleThread: Starting worker for {0}", FileName);
     while (true) {
----------------
The prefix "PreambleThread" implies that there's something in the code called 
PreambleThread, and that there's one such thing, neither are true.

(I also think there's a risk in adding ad-hoc prefixes to things that it adds 
noise and becomes less readable to people with little context, though at dlog 
that's less of an issue)


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:322
 
-  /// Builds a preamble for Req and caches it. Might re-use the latest built
-  /// preamble if it is valid for Req. Also signals waiters about the build.
-  /// FIXME: We shouldn't cache failed preambles, if we've got a successful
-  /// build before.
-  void build(Request Req) {
-    assert(Req.CI && "Got preamble request with null compiler invocation");
-    const ParseInputs &Inputs = Req.Inputs;
-    std::shared_ptr<const PreambleData> OldPreamble =
-        Inputs.ForceRebuild ? nullptr : latest();
-
-    Status.update([&](TUStatus &Status) {
-      Status.PreambleActivity = PreambleAction::Building;
-    });
-
-    auto Preamble = clang::clangd::buildPreamble(
-        FileName, std::move(*Req.CI), OldPreamble, Inputs, StoreInMemory,
-        [this, Version(Inputs.Version)](
-            ASTContext &Ctx, std::shared_ptr<clang::Preprocessor> PP,
-            const CanonicalIncludes &CanonIncludes) {
-          Callbacks.onPreambleAST(FileName, Version, Ctx, std::move(PP),
-                                  CanonIncludes);
-        });
-    {
-      std::lock_guard<std::mutex> Lock(Mutex);
-      // LatestBuild might be the last reference to old preamble, do not 
trigger
-      // destructor while holding the lock.
-      std::swap(LatestBuild, Preamble);
-    }
-  }
+  /// Builds a preamble for \p Req will reuse LatestBuild if possible. Notifies
+  /// ASTWorker.
----------------
this sentence doesn't parse :-)


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:341
   SynchronizedTUStatus &Status;
+  ASTWorker &AW;
 };
----------------
Please don't use initialisms like this for members, they're hard to follow out 
of context.
I'd suggest ASTPeer (and PreamblePeer) or just Peer, to indicate these threads 
are tightly-coupled partners.


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:402
+  /// Used to inform ASTWorker about a new preamble build by PreambleThread.
+  void preambleReady(std::unique_ptr<CompilerInvocation> CI, ParseInputs PI,
+                     std::shared_ptr<const PreambleData> Preamble,
----------------
nit: move somewhere more appropriate (near getCurrentPreamble or update if 
modelling as public, else into the private section?)


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:402
+  /// Used to inform ASTWorker about a new preamble build by PreambleThread.
+  void preambleReady(std::unique_ptr<CompilerInvocation> CI, ParseInputs PI,
+                     std::shared_ptr<const PreambleData> Preamble,
----------------
sammccall wrote:
> nit: move somewhere more appropriate (near getCurrentPreamble or update if 
> modelling as public, else into the private section?)
nit: use a verb for mutating operations (updatePreamble)?


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:409
+  /// cached one if applicable. Assumes LatestPreamble is usable by \p Inputs.
+  void publishDiagnostics(std::unique_ptr<CompilerInvocation> Invocation,
+                          ParseInputs Inputs, std::vector<Diag> CIDiags);
----------------
This name is confusing, almost all of its implementation is building AST.

generateDiagnostics?


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:481
   std::deque<Request> Requests;           /* GUARDED_BY(Mutex) */
+  std::queue<Request> ReceivedPreambles;  /* GUARDED_BY(Mutex) */
   llvm::Optional<Request> CurrentRequest; /* GUARDED_BY(Mutex) */
----------------
PreambleRequests or GoldenASTRequests or so? The queue doens't actually contain 
preambles.


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:541
 
+void PreambleThread::build(Request Req) {
+  assert(Req.CI && "Got preamble request with null compiler invocation");
----------------
Placing this between ASTWorker and its implementation seems confusing - move it 
down?


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:554
+          LatestBuild->Version, Inputs.Version, FileName);
+      // We still notify the ASTWorker to make sure diagnostics are updated to
+      // the latest version of the file without requiring user update.
----------------
This is going to trigger a rebuild of the fileindex - is it really necessary?


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:630
+                              WantDiagnostics WantDiags) {
+  std::string TaskName = llvm::formatv("Preamble Update ({0})", PI.Version);
+  // Store preamble and build diagnostics with new preamble if requested.
----------------
"Golden AST from preamble"?
Current text is not terribly descriptive...


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:644
+    }
+    // Give up our ownership to old preamble before starting expensive
+    Preamble.reset();
----------------
incomplete comment


================
Comment at: clang-tools-extra/clangd/TUScheduler.cpp:675
+  assert(LatestPreamble);
+  assert(isPreambleUsable(*LatestPreamble, Inputs, FileName, *Invocation));
+
----------------
this isn't a safe assert - it does IO and could transiently become true/false


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D76725/new/

https://reviews.llvm.org/D76725



_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to