• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===--- TUScheduler.cpp -----------------------------------------*-C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 // TUScheduler manages a worker per active file. This ASTWorker processes
9 // updates (modifications to file contents) and reads (actions performed on
10 // preamble/AST) to the file.
11 //
12 // Each ASTWorker owns a dedicated thread to process updates and reads to the
13 // relevant file. Any request gets queued in FIFO order to be processed by that
14 // thread.
15 //
16 // An update request replaces current praser inputs to ensure any subsequent
17 // read sees the version of the file they were requested. It will also issue a
18 // build for new inputs.
19 //
20 // ASTWorker processes the file in two parts, a preamble and a main-file
21 // section. A preamble can be reused between multiple versions of the file until
22 // invalidated by a modification to a header, compile commands or modification
23 // to relevant part of the current file. Such a preamble is called compatible.
24 // An update is considered dead if no read was issued for that version and
25 // diagnostics weren't requested by client or could be generated for a later
26 // version of the file. ASTWorker eliminates such requests as they are
27 // redundant.
28 //
29 // In the presence of stale (non-compatible) preambles, ASTWorker won't publish
30 // diagnostics for update requests. Read requests will be served with ASTs build
31 // with stale preambles, unless the read is picky and requires a compatible
32 // preamble. In such cases it will block until new preamble is built.
33 //
34 // ASTWorker owns a PreambleThread for building preambles. If the preamble gets
35 // invalidated by an update request, a new build will be requested on
36 // PreambleThread. Since PreambleThread only receives requests for newer
37 // versions of the file, in case of multiple requests it will only build the
38 // last one and skip requests in between. Unless client force requested
39 // diagnostics(WantDiagnostics::Yes).
40 //
41 // When a new preamble is built, a "golden" AST is immediately built from that
42 // version of the file. This ensures diagnostics get updated even if the queue
43 // is full.
44 //
45 // Some read requests might just need preamble. Since preambles can be read
46 // concurrently, ASTWorker runs these requests on their own thread. These
47 // requests will receive latest build preamble, which might possibly be stale.
48 
49 #include "TUScheduler.h"
50 #include "Compiler.h"
51 #include "Diagnostics.h"
52 #include "GlobalCompilationDatabase.h"
53 #include "ParsedAST.h"
54 #include "Preamble.h"
55 #include "index/CanonicalIncludes.h"
56 #include "support/Cancellation.h"
57 #include "support/Context.h"
58 #include "support/Logger.h"
59 #include "support/MemoryTree.h"
60 #include "support/Path.h"
61 #include "support/Threading.h"
62 #include "support/Trace.h"
63 #include "clang/Frontend/CompilerInvocation.h"
64 #include "clang/Tooling/CompilationDatabase.h"
65 #include "llvm/ADT/FunctionExtras.h"
66 #include "llvm/ADT/None.h"
67 #include "llvm/ADT/Optional.h"
68 #include "llvm/ADT/STLExtras.h"
69 #include "llvm/ADT/ScopeExit.h"
70 #include "llvm/ADT/SmallVector.h"
71 #include "llvm/ADT/StringExtras.h"
72 #include "llvm/ADT/StringRef.h"
73 #include "llvm/Support/Errc.h"
74 #include "llvm/Support/ErrorHandling.h"
75 #include "llvm/Support/FormatVariadic.h"
76 #include "llvm/Support/Path.h"
77 #include "llvm/Support/Threading.h"
78 #include <algorithm>
79 #include <chrono>
80 #include <condition_variable>
81 #include <functional>
82 #include <memory>
83 #include <mutex>
84 #include <queue>
85 #include <string>
86 #include <thread>
87 #include <type_traits>
88 #include <utility>
89 #include <vector>
90 
91 namespace clang {
92 namespace clangd {
93 using std::chrono::steady_clock;
94 
95 namespace {
96 class ASTWorker;
97 } // namespace
98 
99 static clang::clangd::Key<std::string> kFileBeingProcessed;
100 
getFileBeingProcessedInContext()101 llvm::Optional<llvm::StringRef> TUScheduler::getFileBeingProcessedInContext() {
102   if (auto *File = Context::current().get(kFileBeingProcessed))
103     return llvm::StringRef(*File);
104   return None;
105 }
106 
107 /// An LRU cache of idle ASTs.
108 /// Because we want to limit the overall number of these we retain, the cache
109 /// owns ASTs (and may evict them) while their workers are idle.
110 /// Workers borrow ASTs when active, and return them when done.
111 class TUScheduler::ASTCache {
112 public:
113   using Key = const ASTWorker *;
114 
ASTCache(unsigned MaxRetainedASTs)115   ASTCache(unsigned MaxRetainedASTs) : MaxRetainedASTs(MaxRetainedASTs) {}
116 
117   /// Returns result of getUsedBytes() for the AST cached by \p K.
118   /// If no AST is cached, 0 is returned.
getUsedBytes(Key K)119   std::size_t getUsedBytes(Key K) {
120     std::lock_guard<std::mutex> Lock(Mut);
121     auto It = findByKey(K);
122     if (It == LRU.end() || !It->second)
123       return 0;
124     return It->second->getUsedBytes();
125   }
126 
127   /// Store the value in the pool, possibly removing the last used AST.
128   /// The value should not be in the pool when this function is called.
put(Key K,std::unique_ptr<ParsedAST> V)129   void put(Key K, std::unique_ptr<ParsedAST> V) {
130     std::unique_lock<std::mutex> Lock(Mut);
131     assert(findByKey(K) == LRU.end());
132 
133     LRU.insert(LRU.begin(), {K, std::move(V)});
134     if (LRU.size() <= MaxRetainedASTs)
135       return;
136     // We're past the limit, remove the last element.
137     std::unique_ptr<ParsedAST> ForCleanup = std::move(LRU.back().second);
138     LRU.pop_back();
139     // Run the expensive destructor outside the lock.
140     Lock.unlock();
141     ForCleanup.reset();
142   }
143 
144   /// Returns the cached value for \p K, or llvm::None if the value is not in
145   /// the cache anymore. If nullptr was cached for \p K, this function will
146   /// return a null unique_ptr wrapped into an optional.
147   /// If \p AccessMetric is set records whether there was a hit or miss.
148   llvm::Optional<std::unique_ptr<ParsedAST>>
take(Key K,const trace::Metric * AccessMetric=nullptr)149   take(Key K, const trace::Metric *AccessMetric = nullptr) {
150     // Record metric after unlocking the mutex.
151     std::unique_lock<std::mutex> Lock(Mut);
152     auto Existing = findByKey(K);
153     if (Existing == LRU.end()) {
154       if (AccessMetric)
155         AccessMetric->record(1, "miss");
156       return None;
157     }
158     if (AccessMetric)
159       AccessMetric->record(1, "hit");
160     std::unique_ptr<ParsedAST> V = std::move(Existing->second);
161     LRU.erase(Existing);
162     // GCC 4.8 fails to compile `return V;`, as it tries to call the copy
163     // constructor of unique_ptr, so we call the move ctor explicitly to avoid
164     // this miscompile.
165     return llvm::Optional<std::unique_ptr<ParsedAST>>(std::move(V));
166   }
167 
168 private:
169   using KVPair = std::pair<Key, std::unique_ptr<ParsedAST>>;
170 
findByKey(Key K)171   std::vector<KVPair>::iterator findByKey(Key K) {
172     return llvm::find_if(LRU, [K](const KVPair &P) { return P.first == K; });
173   }
174 
175   std::mutex Mut;
176   unsigned MaxRetainedASTs;
177   /// Items sorted in LRU order, i.e. first item is the most recently accessed
178   /// one.
179   std::vector<KVPair> LRU; /* GUARDED_BY(Mut) */
180 };
181 
182 namespace {
183 /// Threadsafe manager for updating a TUStatus and emitting it after each
184 /// update.
185 class SynchronizedTUStatus {
186 public:
SynchronizedTUStatus(PathRef FileName,ParsingCallbacks & Callbacks)187   SynchronizedTUStatus(PathRef FileName, ParsingCallbacks &Callbacks)
188       : FileName(FileName), Callbacks(Callbacks) {}
189 
update(llvm::function_ref<void (TUStatus &)> Mutator)190   void update(llvm::function_ref<void(TUStatus &)> Mutator) {
191     std::lock_guard<std::mutex> Lock(StatusMu);
192     Mutator(Status);
193     emitStatusLocked();
194   }
195 
196   /// Prevents emitting of further updates.
stop()197   void stop() {
198     std::lock_guard<std::mutex> Lock(StatusMu);
199     CanPublish = false;
200   }
201 
202 private:
emitStatusLocked()203   void emitStatusLocked() {
204     if (CanPublish)
205       Callbacks.onFileUpdated(FileName, Status);
206   }
207 
208   const Path FileName;
209 
210   std::mutex StatusMu;
211   TUStatus Status;
212   bool CanPublish = true;
213   ParsingCallbacks &Callbacks;
214 };
215 
216 /// Responsible for building preambles. Whenever the thread is idle and the
217 /// preamble is outdated, it starts to build a fresh preamble from the latest
218 /// inputs. If RunSync is true, preambles are built synchronously in update()
219 /// instead.
220 class PreambleThread {
221 public:
PreambleThread(llvm::StringRef FileName,ParsingCallbacks & Callbacks,bool StorePreambleInMemory,bool RunSync,SynchronizedTUStatus & Status,ASTWorker & AW)222   PreambleThread(llvm::StringRef FileName, ParsingCallbacks &Callbacks,
223                  bool StorePreambleInMemory, bool RunSync,
224                  SynchronizedTUStatus &Status, ASTWorker &AW)
225       : FileName(FileName), Callbacks(Callbacks),
226         StoreInMemory(StorePreambleInMemory), RunSync(RunSync), Status(Status),
227         ASTPeer(AW) {}
228 
229   /// It isn't guaranteed that each requested version will be built. If there
230   /// are multiple update requests while building a preamble, only the last one
231   /// will be built.
update(std::unique_ptr<CompilerInvocation> CI,ParseInputs PI,std::vector<Diag> CIDiags,WantDiagnostics WantDiags)232   void update(std::unique_ptr<CompilerInvocation> CI, ParseInputs PI,
233               std::vector<Diag> CIDiags, WantDiagnostics WantDiags) {
234     Request Req = {std::move(CI), std::move(PI), std::move(CIDiags), WantDiags,
235                    Context::current().clone()};
236     if (RunSync) {
237       build(std::move(Req));
238       Status.update([](TUStatus &Status) {
239         Status.PreambleActivity = PreambleAction::Idle;
240       });
241       return;
242     }
243     {
244       std::unique_lock<std::mutex> Lock(Mutex);
245       // If NextReq was requested with WantDiagnostics::Yes we cannot just drop
246       // that on the floor. Block until we start building it. This won't
247       // dead-lock as we are blocking the caller thread, while builds continue
248       // on preamble thread.
249       ReqCV.wait(Lock, [this] {
250         return !NextReq || NextReq->WantDiags != WantDiagnostics::Yes;
251       });
252       NextReq = std::move(Req);
253     }
254     // Let the worker thread know there's a request, notify_one is safe as there
255     // should be a single worker thread waiting on it.
256     ReqCV.notify_all();
257   }
258 
run()259   void run() {
260     while (true) {
261       {
262         std::unique_lock<std::mutex> Lock(Mutex);
263         assert(!CurrentReq && "Already processing a request?");
264         // Wait until stop is called or there is a request.
265         ReqCV.wait(Lock, [this] { return NextReq || Done; });
266         if (Done)
267           break;
268         CurrentReq = std::move(*NextReq);
269         NextReq.reset();
270       }
271 
272       {
273         WithContext Guard(std::move(CurrentReq->Ctx));
274         // Note that we don't make use of the ContextProvider here.
275         // Preamble tasks are always scheduled by ASTWorker tasks, and we
276         // reuse the context/config that was created at that level.
277 
278         // Build the preamble and let the waiters know about it.
279         build(std::move(*CurrentReq));
280       }
281       bool IsEmpty = false;
282       {
283         std::lock_guard<std::mutex> Lock(Mutex);
284         CurrentReq.reset();
285         IsEmpty = !NextReq.hasValue();
286       }
287       if (IsEmpty) {
288         // We don't perform this above, before waiting for a request to make
289         // tests more deterministic. As there can be a race between this thread
290         // and client thread(clangdserver).
291         Status.update([](TUStatus &Status) {
292           Status.PreambleActivity = PreambleAction::Idle;
293         });
294       }
295       ReqCV.notify_all();
296     }
297     dlog("Preamble worker for {0} stopped", FileName);
298   }
299 
300   /// Signals the run loop to exit.
stop()301   void stop() {
302     dlog("Preamble worker for {0} received stop", FileName);
303     {
304       std::lock_guard<std::mutex> Lock(Mutex);
305       Done = true;
306       NextReq.reset();
307     }
308     // Let the worker thread know that it should stop.
309     ReqCV.notify_all();
310   }
311 
blockUntilIdle(Deadline Timeout) const312   bool blockUntilIdle(Deadline Timeout) const {
313     std::unique_lock<std::mutex> Lock(Mutex);
314     return wait(Lock, ReqCV, Timeout, [&] { return !NextReq && !CurrentReq; });
315   }
316 
317 private:
318   /// Holds inputs required for building a preamble. CI is guaranteed to be
319   /// non-null.
320   struct Request {
321     std::unique_ptr<CompilerInvocation> CI;
322     ParseInputs Inputs;
323     std::vector<Diag> CIDiags;
324     WantDiagnostics WantDiags;
325     Context Ctx;
326   };
327 
isDone()328   bool isDone() {
329     std::lock_guard<std::mutex> Lock(Mutex);
330     return Done;
331   }
332 
333   /// Builds a preamble for \p Req, might reuse LatestBuild if possible.
334   /// Notifies ASTWorker after build finishes.
335   void build(Request Req);
336 
337   mutable std::mutex Mutex;
338   bool Done = false;                  /* GUARDED_BY(Mutex) */
339   llvm::Optional<Request> NextReq;    /* GUARDED_BY(Mutex) */
340   llvm::Optional<Request> CurrentReq; /* GUARDED_BY(Mutex) */
341   // Signaled whenever a thread populates NextReq or worker thread builds a
342   // Preamble.
343   mutable std::condition_variable ReqCV; /* GUARDED_BY(Mutex) */
344   // Accessed only by preamble thread.
345   std::shared_ptr<const PreambleData> LatestBuild;
346 
347   const Path FileName;
348   ParsingCallbacks &Callbacks;
349   const bool StoreInMemory;
350   const bool RunSync;
351 
352   SynchronizedTUStatus &Status;
353   ASTWorker &ASTPeer;
354 };
355 
356 class ASTWorkerHandle;
357 
358 /// Owns one instance of the AST, schedules updates and reads of it.
359 /// Also responsible for building and providing access to the preamble.
360 /// Each ASTWorker processes the async requests sent to it on a separate
361 /// dedicated thread.
362 /// The ASTWorker that manages the AST is shared by both the processing thread
363 /// and the TUScheduler. The TUScheduler should discard an ASTWorker when
364 /// remove() is called, but its thread may be busy and we don't want to block.
365 /// So the workers are accessed via an ASTWorkerHandle. Destroying the handle
366 /// signals the worker to exit its run loop and gives up shared ownership of the
367 /// worker.
368 class ASTWorker {
369   friend class ASTWorkerHandle;
370   ASTWorker(PathRef FileName, const GlobalCompilationDatabase &CDB,
371             TUScheduler::ASTCache &LRUCache, Semaphore &Barrier, bool RunSync,
372             const TUScheduler::Options &Opts, ParsingCallbacks &Callbacks);
373 
374 public:
375   /// Create a new ASTWorker and return a handle to it.
376   /// The processing thread is spawned using \p Tasks. However, when \p Tasks
377   /// is null, all requests will be processed on the calling thread
378   /// synchronously instead. \p Barrier is acquired when processing each
379   /// request, it is used to limit the number of actively running threads.
380   static ASTWorkerHandle create(PathRef FileName,
381                                 const GlobalCompilationDatabase &CDB,
382                                 TUScheduler::ASTCache &IdleASTs,
383                                 AsyncTaskRunner *Tasks, Semaphore &Barrier,
384                                 const TUScheduler::Options &Opts,
385                                 ParsingCallbacks &Callbacks);
386   ~ASTWorker();
387 
388   void update(ParseInputs Inputs, WantDiagnostics);
389   void
390   runWithAST(llvm::StringRef Name,
391              llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action,
392              TUScheduler::ASTActionInvalidation);
393   bool blockUntilIdle(Deadline Timeout) const;
394 
395   std::shared_ptr<const PreambleData> getPossiblyStalePreamble() const;
396 
397   /// Used to inform ASTWorker about a new preamble build by PreambleThread.
398   /// Diagnostics are only published through this callback. This ensures they
399   /// are always for newer versions of the file, as the callback gets called in
400   /// the same order as update requests.
401   void updatePreamble(std::unique_ptr<CompilerInvocation> CI, ParseInputs PI,
402                       std::shared_ptr<const PreambleData> Preamble,
403                       std::vector<Diag> CIDiags, WantDiagnostics WantDiags);
404 
405   /// Obtain a preamble reflecting all updates so far. Threadsafe.
406   /// It may be delivered immediately, or later on the worker thread.
407   void getCurrentPreamble(
408       llvm::unique_function<void(std::shared_ptr<const PreambleData>)>);
409   /// Returns compile command from the current file inputs.
410   tooling::CompileCommand getCurrentCompileCommand() const;
411 
412   /// Wait for the first build of preamble to finish. Preamble itself can be
413   /// accessed via getPossiblyStalePreamble(). Note that this function will
414   /// return after an unsuccessful build of the preamble too, i.e. result of
415   /// getPossiblyStalePreamble() can be null even after this function returns.
416   void waitForFirstPreamble() const;
417 
418   TUScheduler::FileStats stats() const;
419   bool isASTCached() const;
420 
421 private:
422   /// Publishes diagnostics for \p Inputs. It will build an AST or reuse the
423   /// cached one if applicable. Assumes LatestPreamble is compatible for \p
424   /// Inputs.
425   void generateDiagnostics(std::unique_ptr<CompilerInvocation> Invocation,
426                            ParseInputs Inputs, std::vector<Diag> CIDiags);
427 
428   // Must be called exactly once on processing thread. Will return after
429   // stop() is called on a separate thread and all pending requests are
430   // processed.
431   void run();
432   /// Signal that run() should finish processing pending requests and exit.
433   void stop();
434   /// Adds a new task to the end of the request queue.
435   void startTask(llvm::StringRef Name, llvm::unique_function<void()> Task,
436                  llvm::Optional<WantDiagnostics> UpdateType,
437                  TUScheduler::ASTActionInvalidation);
438 
439   /// Determines the next action to perform.
440   /// All actions that should never run are discarded.
441   /// Returns a deadline for the next action. If it's expired, run now.
442   /// scheduleLocked() is called again at the deadline, or if requests arrive.
443   Deadline scheduleLocked();
444   /// Should the first task in the queue be skipped instead of run?
445   bool shouldSkipHeadLocked() const;
446 
447   struct Request {
448     llvm::unique_function<void()> Action;
449     std::string Name;
450     steady_clock::time_point AddTime;
451     Context Ctx;
452     llvm::Optional<WantDiagnostics> UpdateType;
453     TUScheduler::ASTActionInvalidation InvalidationPolicy;
454     Canceler Invalidate;
455   };
456 
457   /// Handles retention of ASTs.
458   TUScheduler::ASTCache &IdleASTs;
459   const bool RunSync;
460   /// Time to wait after an update to see whether another update obsoletes it.
461   const DebouncePolicy UpdateDebounce;
462   /// File that ASTWorker is responsible for.
463   const Path FileName;
464   /// Callback to create processing contexts for tasks.
465   const std::function<Context(llvm::StringRef)> ContextProvider;
466   const GlobalCompilationDatabase &CDB;
467   /// Callback invoked when preamble or main file AST is built.
468   ParsingCallbacks &Callbacks;
469 
470   Semaphore &Barrier;
471   /// Whether the 'onMainAST' callback ran for the current FileInputs.
472   bool RanASTCallback = false;
473   /// Guards members used by both TUScheduler and the worker thread.
474   mutable std::mutex Mutex;
475   /// File inputs, currently being used by the worker.
476   /// Writes and reads from unknown threads are locked. Reads from the worker
477   /// thread are not locked, as it's the only writer.
478   ParseInputs FileInputs; /* GUARDED_BY(Mutex) */
479   /// Times of recent AST rebuilds, used for UpdateDebounce computation.
480   llvm::SmallVector<DebouncePolicy::clock::duration, 8>
481       RebuildTimes; /* GUARDED_BY(Mutex) */
482   /// Set to true to signal run() to finish processing.
483   bool Done;                              /* GUARDED_BY(Mutex) */
484   std::deque<Request> Requests;           /* GUARDED_BY(Mutex) */
485   llvm::Optional<Request> CurrentRequest; /* GUARDED_BY(Mutex) */
486   /// Signalled whenever a new request has been scheduled or processing of a
487   /// request has completed.
488   mutable std::condition_variable RequestsCV;
489   /// Latest build preamble for current TU.
490   /// None means no builds yet, null means there was an error while building.
491   /// Only written by ASTWorker's thread.
492   llvm::Optional<std::shared_ptr<const PreambleData>> LatestPreamble;
493   std::queue<Request> PreambleRequests; /* GUARDED_BY(Mutex) */
494   /// Signaled whenever LatestPreamble changes state or there's a new
495   /// PreambleRequest.
496   mutable std::condition_variable PreambleCV;
497   /// Guards the callback that publishes results of AST-related computations
498   /// (diagnostics, highlightings) and file statuses.
499   std::mutex PublishMu;
500   // Used to prevent remove document + add document races that lead to
501   // out-of-order callbacks for publishing results of onMainAST callback.
502   //
503   // The lifetime of the old/new ASTWorkers will overlap, but their handles
504   // don't. When the old handle is destroyed, the old worker will stop reporting
505   // any results to the user.
506   bool CanPublishResults = true; /* GUARDED_BY(PublishMu) */
507   std::atomic<unsigned> ASTBuildCount = {0};
508   std::atomic<unsigned> PreambleBuildCount = {0};
509 
510   SynchronizedTUStatus Status;
511   PreambleThread PreamblePeer;
512 };
513 
514 /// A smart-pointer-like class that points to an active ASTWorker.
515 /// In destructor, signals to the underlying ASTWorker that no new requests will
516 /// be sent and the processing loop may exit (after running all pending
517 /// requests).
518 class ASTWorkerHandle {
519   friend class ASTWorker;
ASTWorkerHandle(std::shared_ptr<ASTWorker> Worker)520   ASTWorkerHandle(std::shared_ptr<ASTWorker> Worker)
521       : Worker(std::move(Worker)) {
522     assert(this->Worker);
523   }
524 
525 public:
526   ASTWorkerHandle(const ASTWorkerHandle &) = delete;
527   ASTWorkerHandle &operator=(const ASTWorkerHandle &) = delete;
528   ASTWorkerHandle(ASTWorkerHandle &&) = default;
529   ASTWorkerHandle &operator=(ASTWorkerHandle &&) = default;
530 
~ASTWorkerHandle()531   ~ASTWorkerHandle() {
532     if (Worker)
533       Worker->stop();
534   }
535 
operator *()536   ASTWorker &operator*() {
537     assert(Worker && "Handle was moved from");
538     return *Worker;
539   }
540 
operator ->()541   ASTWorker *operator->() {
542     assert(Worker && "Handle was moved from");
543     return Worker.get();
544   }
545 
546   /// Returns an owning reference to the underlying ASTWorker that can outlive
547   /// the ASTWorkerHandle. However, no new requests to an active ASTWorker can
548   /// be schedule via the returned reference, i.e. only reads of the preamble
549   /// are possible.
lock()550   std::shared_ptr<const ASTWorker> lock() { return Worker; }
551 
552 private:
553   std::shared_ptr<ASTWorker> Worker;
554 };
555 
create(PathRef FileName,const GlobalCompilationDatabase & CDB,TUScheduler::ASTCache & IdleASTs,AsyncTaskRunner * Tasks,Semaphore & Barrier,const TUScheduler::Options & Opts,ParsingCallbacks & Callbacks)556 ASTWorkerHandle ASTWorker::create(PathRef FileName,
557                                   const GlobalCompilationDatabase &CDB,
558                                   TUScheduler::ASTCache &IdleASTs,
559                                   AsyncTaskRunner *Tasks, Semaphore &Barrier,
560                                   const TUScheduler::Options &Opts,
561                                   ParsingCallbacks &Callbacks) {
562   std::shared_ptr<ASTWorker> Worker(new ASTWorker(
563       FileName, CDB, IdleASTs, Barrier, /*RunSync=*/!Tasks, Opts, Callbacks));
564   if (Tasks) {
565     Tasks->runAsync("ASTWorker:" + llvm::sys::path::filename(FileName),
566                     [Worker]() { Worker->run(); });
567     Tasks->runAsync("PreambleWorker:" + llvm::sys::path::filename(FileName),
568                     [Worker]() { Worker->PreamblePeer.run(); });
569   }
570 
571   return ASTWorkerHandle(std::move(Worker));
572 }
573 
ASTWorker(PathRef FileName,const GlobalCompilationDatabase & CDB,TUScheduler::ASTCache & LRUCache,Semaphore & Barrier,bool RunSync,const TUScheduler::Options & Opts,ParsingCallbacks & Callbacks)574 ASTWorker::ASTWorker(PathRef FileName, const GlobalCompilationDatabase &CDB,
575                      TUScheduler::ASTCache &LRUCache, Semaphore &Barrier,
576                      bool RunSync, const TUScheduler::Options &Opts,
577                      ParsingCallbacks &Callbacks)
578     : IdleASTs(LRUCache), RunSync(RunSync), UpdateDebounce(Opts.UpdateDebounce),
579       FileName(FileName), ContextProvider(Opts.ContextProvider), CDB(CDB),
580       Callbacks(Callbacks), Barrier(Barrier), Done(false),
581       Status(FileName, Callbacks),
582       PreamblePeer(FileName, Callbacks, Opts.StorePreamblesInMemory,
583                    RunSync || !Opts.AsyncPreambleBuilds, Status, *this) {
584   // Set a fallback command because compile command can be accessed before
585   // `Inputs` is initialized. Other fields are only used after initialization
586   // from client inputs.
587   FileInputs.CompileCommand = CDB.getFallbackCommand(FileName);
588 }
589 
~ASTWorker()590 ASTWorker::~ASTWorker() {
591   // Make sure we remove the cached AST, if any.
592   IdleASTs.take(this);
593 #ifndef NDEBUG
594   std::lock_guard<std::mutex> Lock(Mutex);
595   assert(Done && "handle was not destroyed");
596   assert(Requests.empty() && !CurrentRequest &&
597          "unprocessed requests when destroying ASTWorker");
598 #endif
599 }
600 
update(ParseInputs Inputs,WantDiagnostics WantDiags)601 void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags) {
602   std::string TaskName = llvm::formatv("Update ({0})", Inputs.Version);
603   auto Task = [=]() mutable {
604     // Get the actual command as `Inputs` does not have a command.
605     // FIXME: some build systems like Bazel will take time to preparing
606     // environment to build the file, it would be nice if we could emit a
607     // "PreparingBuild" status to inform users, it is non-trivial given the
608     // current implementation.
609     if (auto Cmd = CDB.getCompileCommand(FileName))
610       Inputs.CompileCommand = *Cmd;
611     else
612       // FIXME: consider using old command if it's not a fallback one.
613       Inputs.CompileCommand = CDB.getFallbackCommand(FileName);
614 
615     bool InputsAreTheSame =
616         std::tie(FileInputs.CompileCommand, FileInputs.Contents) ==
617         std::tie(Inputs.CompileCommand, Inputs.Contents);
618     // Cached AST is invalidated.
619     if (!InputsAreTheSame) {
620       IdleASTs.take(this);
621       RanASTCallback = false;
622     }
623 
624     // Update current inputs so that subsequent reads can see them.
625     {
626       std::lock_guard<std::mutex> Lock(Mutex);
627       FileInputs = Inputs;
628     }
629 
630     log("ASTWorker building file {0} version {1} with command {2}\n[{3}]\n{4}",
631         FileName, Inputs.Version, Inputs.CompileCommand.Heuristic,
632         Inputs.CompileCommand.Directory,
633         llvm::join(Inputs.CompileCommand.CommandLine, " "));
634 
635     StoreDiags CompilerInvocationDiagConsumer;
636     std::vector<std::string> CC1Args;
637     std::unique_ptr<CompilerInvocation> Invocation = buildCompilerInvocation(
638         Inputs, CompilerInvocationDiagConsumer, &CC1Args);
639     // Log cc1 args even (especially!) if creating invocation failed.
640     if (!CC1Args.empty())
641       vlog("Driver produced command: cc1 {0}", llvm::join(CC1Args, " "));
642     std::vector<Diag> CompilerInvocationDiags =
643         CompilerInvocationDiagConsumer.take();
644     if (!Invocation) {
645       elog("Could not build CompilerInvocation for file {0}", FileName);
646       // Remove the old AST if it's still in cache.
647       IdleASTs.take(this);
648       RanASTCallback = false;
649       // Report the diagnostics we collected when parsing the command line.
650       Callbacks.onFailedAST(FileName, Inputs.Version,
651                             std::move(CompilerInvocationDiags),
652                             [&](llvm::function_ref<void()> Publish) {
653                               // Ensure we only publish results from the worker
654                               // if the file was not removed, making sure there
655                               // are not race conditions.
656                               std::lock_guard<std::mutex> Lock(PublishMu);
657                               if (CanPublishResults)
658                                 Publish();
659                             });
660       // Note that this might throw away a stale preamble that might still be
661       // useful, but this is how we communicate a build error.
662       LatestPreamble.emplace();
663       // Make sure anyone waiting for the preamble gets notified it could not be
664       // built.
665       PreambleCV.notify_all();
666       return;
667     }
668 
669     PreamblePeer.update(std::move(Invocation), std::move(Inputs),
670                         std::move(CompilerInvocationDiags), WantDiags);
671     std::unique_lock<std::mutex> Lock(Mutex);
672     PreambleCV.wait(Lock, [this] {
673       // Block until we reiceve a preamble request, unless a preamble already
674       // exists, as patching an empty preamble would imply rebuilding it from
675       // scratch.
676       // We block here instead of the consumer to prevent any deadlocks. Since
677       // LatestPreamble is only populated by ASTWorker thread.
678       return LatestPreamble || !PreambleRequests.empty() || Done;
679     });
680     return;
681   };
682   startTask(TaskName, std::move(Task), WantDiags, TUScheduler::NoInvalidation);
683 }
684 
runWithAST(llvm::StringRef Name,llvm::unique_function<void (llvm::Expected<InputsAndAST>)> Action,TUScheduler::ASTActionInvalidation Invalidation)685 void ASTWorker::runWithAST(
686     llvm::StringRef Name,
687     llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action,
688     TUScheduler::ASTActionInvalidation Invalidation) {
689   // Tracks ast cache accesses for read operations.
690   static constexpr trace::Metric ASTAccessForRead(
691       "ast_access_read", trace::Metric::Counter, "result");
692   auto Task = [=, Action = std::move(Action)]() mutable {
693     if (auto Reason = isCancelled())
694       return Action(llvm::make_error<CancelledError>(Reason));
695     llvm::Optional<std::unique_ptr<ParsedAST>> AST =
696         IdleASTs.take(this, &ASTAccessForRead);
697     if (!AST) {
698       StoreDiags CompilerInvocationDiagConsumer;
699       std::unique_ptr<CompilerInvocation> Invocation =
700           buildCompilerInvocation(FileInputs, CompilerInvocationDiagConsumer);
701       // Try rebuilding the AST.
702       vlog("ASTWorker rebuilding evicted AST to run {0}: {1} version {2}", Name,
703            FileName, FileInputs.Version);
704       // FIXME: We might need to build a patched ast once preamble thread starts
705       // running async. Currently getPossiblyStalePreamble below will always
706       // return a compatible preamble as ASTWorker::update blocks.
707       llvm::Optional<ParsedAST> NewAST;
708       if (Invocation) {
709         NewAST = ParsedAST::build(FileName, FileInputs, std::move(Invocation),
710                                   CompilerInvocationDiagConsumer.take(),
711                                   getPossiblyStalePreamble());
712         ++ASTBuildCount;
713       }
714       AST = NewAST ? std::make_unique<ParsedAST>(std::move(*NewAST)) : nullptr;
715     }
716     // Make sure we put the AST back into the LRU cache.
717     auto _ = llvm::make_scope_exit(
718         [&AST, this]() { IdleASTs.put(this, std::move(*AST)); });
719     // Run the user-provided action.
720     if (!*AST)
721       return Action(error(llvm::errc::invalid_argument, "invalid AST"));
722     vlog("ASTWorker running {0} on version {2} of {1}", Name, FileName,
723          FileInputs.Version);
724     Action(InputsAndAST{FileInputs, **AST});
725   };
726   startTask(Name, std::move(Task), /*UpdateType=*/None, Invalidation);
727 }
728 
build(Request Req)729 void PreambleThread::build(Request Req) {
730   assert(Req.CI && "Got preamble request with null compiler invocation");
731   const ParseInputs &Inputs = Req.Inputs;
732 
733   Status.update([&](TUStatus &Status) {
734     Status.PreambleActivity = PreambleAction::Building;
735   });
736   auto _ = llvm::make_scope_exit([this, &Req] {
737     ASTPeer.updatePreamble(std::move(Req.CI), std::move(Req.Inputs),
738                            LatestBuild, std::move(Req.CIDiags),
739                            std::move(Req.WantDiags));
740   });
741 
742   if (!LatestBuild || Inputs.ForceRebuild) {
743     vlog("Building first preamble for {0} version {1}", FileName,
744          Inputs.Version);
745   } else if (isPreambleCompatible(*LatestBuild, Inputs, FileName, *Req.CI)) {
746     vlog("Reusing preamble version {0} for version {1} of {2}",
747          LatestBuild->Version, Inputs.Version, FileName);
748     return;
749   } else {
750     vlog("Rebuilding invalidated preamble for {0} version {1} (previous was "
751          "version {2})",
752          FileName, Inputs.Version, LatestBuild->Version);
753   }
754 
755   LatestBuild = clang::clangd::buildPreamble(
756       FileName, *Req.CI, Inputs, StoreInMemory,
757       [this, Version(Inputs.Version)](ASTContext &Ctx,
758                                       std::shared_ptr<clang::Preprocessor> PP,
759                                       const CanonicalIncludes &CanonIncludes) {
760         Callbacks.onPreambleAST(FileName, Version, Ctx, std::move(PP),
761                                 CanonIncludes);
762       });
763 }
764 
updatePreamble(std::unique_ptr<CompilerInvocation> CI,ParseInputs PI,std::shared_ptr<const PreambleData> Preamble,std::vector<Diag> CIDiags,WantDiagnostics WantDiags)765 void ASTWorker::updatePreamble(std::unique_ptr<CompilerInvocation> CI,
766                                ParseInputs PI,
767                                std::shared_ptr<const PreambleData> Preamble,
768                                std::vector<Diag> CIDiags,
769                                WantDiagnostics WantDiags) {
770   std::string TaskName = llvm::formatv("Build AST for ({0})", PI.Version);
771   // Store preamble and build diagnostics with new preamble if requested.
772   auto Task = [this, Preamble = std::move(Preamble), CI = std::move(CI),
773                PI = std::move(PI), CIDiags = std::move(CIDiags),
774                WantDiags = std::move(WantDiags)]() mutable {
775     // Update the preamble inside ASTWorker queue to ensure atomicity. As a task
776     // running inside ASTWorker assumes internals won't change until it
777     // finishes.
778     if (!LatestPreamble || Preamble != *LatestPreamble) {
779       ++PreambleBuildCount;
780       // Cached AST is no longer valid.
781       IdleASTs.take(this);
782       RanASTCallback = false;
783       std::lock_guard<std::mutex> Lock(Mutex);
784       // LatestPreamble might be the last reference to old preamble, do not
785       // trigger destructor while holding the lock.
786       if (LatestPreamble)
787         std::swap(*LatestPreamble, Preamble);
788       else
789         LatestPreamble = std::move(Preamble);
790     }
791     // Notify anyone waiting for a preamble.
792     PreambleCV.notify_all();
793     // Give up our ownership to old preamble before starting expensive AST
794     // build.
795     Preamble.reset();
796     // We only need to build the AST if diagnostics were requested.
797     if (WantDiags == WantDiagnostics::No)
798       return;
799     // Report diagnostics with the new preamble to ensure progress. Otherwise
800     // diagnostics might get stale indefinitely if user keeps invalidating the
801     // preamble.
802     generateDiagnostics(std::move(CI), std::move(PI), std::move(CIDiags));
803   };
804   if (RunSync) {
805     Task();
806     return;
807   }
808   {
809     std::lock_guard<std::mutex> Lock(Mutex);
810     PreambleRequests.push({std::move(Task), std::move(TaskName),
811                            steady_clock::now(), Context::current().clone(),
812                            llvm::None, TUScheduler::NoInvalidation, nullptr});
813   }
814   PreambleCV.notify_all();
815   RequestsCV.notify_all();
816 }
817 
generateDiagnostics(std::unique_ptr<CompilerInvocation> Invocation,ParseInputs Inputs,std::vector<Diag> CIDiags)818 void ASTWorker::generateDiagnostics(
819     std::unique_ptr<CompilerInvocation> Invocation, ParseInputs Inputs,
820     std::vector<Diag> CIDiags) {
821   // Tracks ast cache accesses for publishing diags.
822   static constexpr trace::Metric ASTAccessForDiag(
823       "ast_access_diag", trace::Metric::Counter, "result");
824   assert(Invocation);
825   assert(LatestPreamble);
826   // No need to rebuild the AST if we won't send the diagnostics.
827   {
828     std::lock_guard<std::mutex> Lock(PublishMu);
829     if (!CanPublishResults)
830       return;
831   }
832   // Used to check whether we can update AST cache.
833   bool InputsAreLatest =
834       std::tie(FileInputs.CompileCommand, FileInputs.Contents) ==
835       std::tie(Inputs.CompileCommand, Inputs.Contents);
836   // Take a shortcut and don't report the diagnostics, since they should be the
837   // same. All the clients should handle the lack of OnUpdated() call anyway to
838   // handle empty result from buildAST.
839   // FIXME: the AST could actually change if non-preamble includes changed,
840   // but we choose to ignore it.
841   if (InputsAreLatest && RanASTCallback)
842     return;
843 
844   // Get the AST for diagnostics, either build it or use the cached one.
845   std::string TaskName = llvm::formatv("Build AST ({0})", Inputs.Version);
846   Status.update([&](TUStatus &Status) {
847     Status.ASTActivity.K = ASTAction::Building;
848     Status.ASTActivity.Name = std::move(TaskName);
849   });
850   // We might be able to reuse the last we've built for a read request.
851   // FIXME: It might be better to not reuse this AST. That way queued AST builds
852   // won't be required for diags.
853   llvm::Optional<std::unique_ptr<ParsedAST>> AST =
854       IdleASTs.take(this, &ASTAccessForDiag);
855   if (!AST || !InputsAreLatest) {
856     auto RebuildStartTime = DebouncePolicy::clock::now();
857     llvm::Optional<ParsedAST> NewAST = ParsedAST::build(
858         FileName, Inputs, std::move(Invocation), CIDiags, *LatestPreamble);
859     auto RebuildDuration = DebouncePolicy::clock::now() - RebuildStartTime;
860     ++ASTBuildCount;
861     // Try to record the AST-build time, to inform future update debouncing.
862     // This is best-effort only: if the lock is held, don't bother.
863     std::unique_lock<std::mutex> Lock(Mutex, std::try_to_lock);
864     if (Lock.owns_lock()) {
865       // Do not let RebuildTimes grow beyond its small-size (i.e.
866       // capacity).
867       if (RebuildTimes.size() == RebuildTimes.capacity())
868         RebuildTimes.erase(RebuildTimes.begin());
869       RebuildTimes.push_back(RebuildDuration);
870       Lock.unlock();
871     }
872     Status.update([&](TUStatus &Status) {
873       Status.Details.ReuseAST = false;
874       Status.Details.BuildFailed = !NewAST.hasValue();
875     });
876     AST = NewAST ? std::make_unique<ParsedAST>(std::move(*NewAST)) : nullptr;
877   } else {
878     log("Skipping rebuild of the AST for {0}, inputs are the same.", FileName);
879     Status.update([](TUStatus &Status) {
880       Status.Details.ReuseAST = true;
881       Status.Details.BuildFailed = false;
882     });
883   }
884 
885   // Publish diagnostics.
886   auto RunPublish = [&](llvm::function_ref<void()> Publish) {
887     // Ensure we only publish results from the worker if the file was not
888     // removed, making sure there are not race conditions.
889     std::lock_guard<std::mutex> Lock(PublishMu);
890     if (CanPublishResults)
891       Publish();
892   };
893   if (*AST) {
894     trace::Span Span("Running main AST callback");
895     Callbacks.onMainAST(FileName, **AST, RunPublish);
896   } else {
897     // Failed to build the AST, at least report diagnostics from the
898     // command line if there were any.
899     // FIXME: we might have got more errors while trying to build the
900     // AST, surface them too.
901     Callbacks.onFailedAST(FileName, Inputs.Version, CIDiags, RunPublish);
902   }
903 
904   // AST might've been built for an older version of the source, as ASTWorker
905   // queue raced ahead while we were waiting on the preamble. In that case the
906   // queue can't reuse the AST.
907   if (InputsAreLatest) {
908     RanASTCallback = *AST != nullptr;
909     IdleASTs.put(this, std::move(*AST));
910   }
911 }
912 
913 std::shared_ptr<const PreambleData>
getPossiblyStalePreamble() const914 ASTWorker::getPossiblyStalePreamble() const {
915   std::lock_guard<std::mutex> Lock(Mutex);
916   return LatestPreamble ? *LatestPreamble : nullptr;
917 }
918 
waitForFirstPreamble() const919 void ASTWorker::waitForFirstPreamble() const {
920   std::unique_lock<std::mutex> Lock(Mutex);
921   PreambleCV.wait(Lock, [this] { return LatestPreamble.hasValue() || Done; });
922 }
923 
getCurrentCompileCommand() const924 tooling::CompileCommand ASTWorker::getCurrentCompileCommand() const {
925   std::unique_lock<std::mutex> Lock(Mutex);
926   return FileInputs.CompileCommand;
927 }
928 
stats() const929 TUScheduler::FileStats ASTWorker::stats() const {
930   TUScheduler::FileStats Result;
931   Result.ASTBuilds = ASTBuildCount;
932   Result.PreambleBuilds = PreambleBuildCount;
933   // Note that we don't report the size of ASTs currently used for processing
934   // the in-flight requests. We used this information for debugging purposes
935   // only, so this should be fine.
936   Result.UsedBytesAST = IdleASTs.getUsedBytes(this);
937   if (auto Preamble = getPossiblyStalePreamble())
938     Result.UsedBytesPreamble = Preamble->Preamble.getSize();
939   return Result;
940 }
941 
isASTCached() const942 bool ASTWorker::isASTCached() const { return IdleASTs.getUsedBytes(this) != 0; }
943 
stop()944 void ASTWorker::stop() {
945   {
946     std::lock_guard<std::mutex> Lock(PublishMu);
947     CanPublishResults = false;
948   }
949   {
950     std::lock_guard<std::mutex> Lock(Mutex);
951     assert(!Done && "stop() called twice");
952     Done = true;
953   }
954   PreamblePeer.stop();
955   // We are no longer going to build any preambles, let the waiters know that.
956   PreambleCV.notify_all();
957   Status.stop();
958   RequestsCV.notify_all();
959 }
960 
startTask(llvm::StringRef Name,llvm::unique_function<void ()> Task,llvm::Optional<WantDiagnostics> UpdateType,TUScheduler::ASTActionInvalidation Invalidation)961 void ASTWorker::startTask(llvm::StringRef Name,
962                           llvm::unique_function<void()> Task,
963                           llvm::Optional<WantDiagnostics> UpdateType,
964                           TUScheduler::ASTActionInvalidation Invalidation) {
965   if (RunSync) {
966     assert(!Done && "running a task after stop()");
967     trace::Span Tracer(Name + ":" + llvm::sys::path::filename(FileName));
968     WithContext WithProvidedContext(ContextProvider(FileName));
969     Task();
970     return;
971   }
972 
973   {
974     std::lock_guard<std::mutex> Lock(Mutex);
975     assert(!Done && "running a task after stop()");
976     // Cancel any requests invalidated by this request.
977     if (UpdateType) {
978       for (auto &R : llvm::reverse(Requests)) {
979         if (R.InvalidationPolicy == TUScheduler::InvalidateOnUpdate)
980           R.Invalidate();
981         if (R.UpdateType)
982           break; // Older requests were already invalidated by the older update.
983       }
984     }
985 
986     // Allow this request to be cancelled if invalidated.
987     Context Ctx = Context::current().derive(kFileBeingProcessed, FileName);
988     Canceler Invalidate = nullptr;
989     if (Invalidation) {
990       WithContext WC(std::move(Ctx));
991       std::tie(Ctx, Invalidate) = cancelableTask(
992           /*Reason=*/static_cast<int>(ErrorCode::ContentModified));
993     }
994     Requests.push_back({std::move(Task), std::string(Name), steady_clock::now(),
995                         std::move(Ctx), UpdateType, Invalidation,
996                         std::move(Invalidate)});
997   }
998   RequestsCV.notify_all();
999 }
1000 
run()1001 void ASTWorker::run() {
1002   while (true) {
1003     {
1004       std::unique_lock<std::mutex> Lock(Mutex);
1005       assert(!CurrentRequest && "A task is already running, multiple workers?");
1006       for (auto Wait = scheduleLocked(); !Wait.expired();
1007            Wait = scheduleLocked()) {
1008         assert(PreambleRequests.empty() &&
1009                "Preamble updates should be scheduled immediately");
1010         if (Done) {
1011           if (Requests.empty())
1012             return;
1013           else     // Even though Done is set, finish pending requests.
1014             break; // However, skip delays to shutdown fast.
1015         }
1016 
1017         // Tracing: we have a next request, attribute this sleep to it.
1018         llvm::Optional<WithContext> Ctx;
1019         llvm::Optional<trace::Span> Tracer;
1020         if (!Requests.empty()) {
1021           Ctx.emplace(Requests.front().Ctx.clone());
1022           Tracer.emplace("Debounce");
1023           SPAN_ATTACH(*Tracer, "next_request", Requests.front().Name);
1024           if (!(Wait == Deadline::infinity())) {
1025             Status.update([&](TUStatus &Status) {
1026               Status.ASTActivity.K = ASTAction::Queued;
1027               Status.ASTActivity.Name = Requests.front().Name;
1028             });
1029             SPAN_ATTACH(*Tracer, "sleep_ms",
1030                         std::chrono::duration_cast<std::chrono::milliseconds>(
1031                             Wait.time() - steady_clock::now())
1032                             .count());
1033           }
1034         }
1035 
1036         wait(Lock, RequestsCV, Wait);
1037       }
1038       // Any request in ReceivedPreambles is at least as old as the
1039       // Requests.front(), so prefer them first to preserve LSP order.
1040       if (!PreambleRequests.empty()) {
1041         CurrentRequest = std::move(PreambleRequests.front());
1042         PreambleRequests.pop();
1043       } else {
1044         CurrentRequest = std::move(Requests.front());
1045         Requests.pop_front();
1046       }
1047     } // unlock Mutex
1048 
1049     // It is safe to perform reads to CurrentRequest without holding the lock as
1050     // only writer is also this thread.
1051     {
1052       std::unique_lock<Semaphore> Lock(Barrier, std::try_to_lock);
1053       if (!Lock.owns_lock()) {
1054         Status.update([&](TUStatus &Status) {
1055           Status.ASTActivity.K = ASTAction::Queued;
1056           Status.ASTActivity.Name = CurrentRequest->Name;
1057         });
1058         Lock.lock();
1059       }
1060       WithContext Guard(std::move(CurrentRequest->Ctx));
1061       trace::Span Tracer(CurrentRequest->Name);
1062       Status.update([&](TUStatus &Status) {
1063         Status.ASTActivity.K = ASTAction::RunningAction;
1064         Status.ASTActivity.Name = CurrentRequest->Name;
1065       });
1066       WithContext WithProvidedContext(ContextProvider(FileName));
1067       CurrentRequest->Action();
1068     }
1069 
1070     bool IsEmpty = false;
1071     {
1072       std::lock_guard<std::mutex> Lock(Mutex);
1073       CurrentRequest.reset();
1074       IsEmpty = Requests.empty() && PreambleRequests.empty();
1075     }
1076     if (IsEmpty) {
1077       Status.update([&](TUStatus &Status) {
1078         Status.ASTActivity.K = ASTAction::Idle;
1079         Status.ASTActivity.Name = "";
1080       });
1081     }
1082     RequestsCV.notify_all();
1083   }
1084 }
1085 
scheduleLocked()1086 Deadline ASTWorker::scheduleLocked() {
1087   // Process new preambles immediately.
1088   if (!PreambleRequests.empty())
1089     return Deadline::zero();
1090   if (Requests.empty())
1091     return Deadline::infinity(); // Wait for new requests.
1092   // Handle cancelled requests first so the rest of the scheduler doesn't.
1093   for (auto I = Requests.begin(), E = Requests.end(); I != E; ++I) {
1094     if (!isCancelled(I->Ctx)) {
1095       // Cancellations after the first read don't affect current scheduling.
1096       if (I->UpdateType == None)
1097         break;
1098       continue;
1099     }
1100     // Cancelled reads are moved to the front of the queue and run immediately.
1101     if (I->UpdateType == None) {
1102       Request R = std::move(*I);
1103       Requests.erase(I);
1104       Requests.push_front(std::move(R));
1105       return Deadline::zero();
1106     }
1107     // Cancelled updates are downgraded to auto-diagnostics, and may be elided.
1108     if (I->UpdateType == WantDiagnostics::Yes)
1109       I->UpdateType = WantDiagnostics::Auto;
1110   }
1111 
1112   while (shouldSkipHeadLocked()) {
1113     vlog("ASTWorker skipping {0} for {1}", Requests.front().Name, FileName);
1114     Requests.pop_front();
1115   }
1116   assert(!Requests.empty() && "skipped the whole queue");
1117   // Some updates aren't dead yet, but never end up being used.
1118   // e.g. the first keystroke is live until obsoleted by the second.
1119   // We debounce "maybe-unused" writes, sleeping in case they become dead.
1120   // But don't delay reads (including updates where diagnostics are needed).
1121   for (const auto &R : Requests)
1122     if (R.UpdateType == None || R.UpdateType == WantDiagnostics::Yes)
1123       return Deadline::zero();
1124   // Front request needs to be debounced, so determine when we're ready.
1125   Deadline D(Requests.front().AddTime + UpdateDebounce.compute(RebuildTimes));
1126   return D;
1127 }
1128 
1129 // Returns true if Requests.front() is a dead update that can be skipped.
shouldSkipHeadLocked() const1130 bool ASTWorker::shouldSkipHeadLocked() const {
1131   assert(!Requests.empty());
1132   auto Next = Requests.begin();
1133   auto UpdateType = Next->UpdateType;
1134   if (!UpdateType) // Only skip updates.
1135     return false;
1136   ++Next;
1137   // An update is live if its AST might still be read.
1138   // That is, if it's not immediately followed by another update.
1139   if (Next == Requests.end() || !Next->UpdateType)
1140     return false;
1141   // The other way an update can be live is if its diagnostics might be used.
1142   switch (*UpdateType) {
1143   case WantDiagnostics::Yes:
1144     return false; // Always used.
1145   case WantDiagnostics::No:
1146     return true; // Always dead.
1147   case WantDiagnostics::Auto:
1148     // Used unless followed by an update that generates diagnostics.
1149     for (; Next != Requests.end(); ++Next)
1150       if (Next->UpdateType == WantDiagnostics::Yes ||
1151           Next->UpdateType == WantDiagnostics::Auto)
1152         return true; // Prefer later diagnostics.
1153     return false;
1154   }
1155   llvm_unreachable("Unknown WantDiagnostics");
1156 }
1157 
blockUntilIdle(Deadline Timeout) const1158 bool ASTWorker::blockUntilIdle(Deadline Timeout) const {
1159   auto WaitUntilASTWorkerIsIdle = [&] {
1160     std::unique_lock<std::mutex> Lock(Mutex);
1161     return wait(Lock, RequestsCV, Timeout, [&] {
1162       return PreambleRequests.empty() && Requests.empty() && !CurrentRequest;
1163     });
1164   };
1165   // Make sure ASTWorker has processed all requests, which might issue new
1166   // updates to PreamblePeer.
1167   WaitUntilASTWorkerIsIdle();
1168   // Now that ASTWorker processed all requests, ensure PreamblePeer has served
1169   // all update requests. This might create new PreambleRequests for the
1170   // ASTWorker.
1171   PreamblePeer.blockUntilIdle(Timeout);
1172   assert(Requests.empty() &&
1173          "No new normal tasks can be scheduled concurrently with "
1174          "blockUntilIdle(): ASTWorker isn't threadsafe");
1175   // Finally make sure ASTWorker has processed all of the preamble updates.
1176   return WaitUntilASTWorkerIsIdle();
1177 }
1178 
1179 // Render a TUAction to a user-facing string representation.
1180 // TUAction represents clangd-internal states, we don't intend to expose them
1181 // to users (say C++ programmers) directly to avoid confusion, we use terms that
1182 // are familiar by C++ programmers.
renderTUAction(const PreambleAction PA,const ASTAction & AA)1183 std::string renderTUAction(const PreambleAction PA, const ASTAction &AA) {
1184   llvm::SmallVector<std::string, 2> Result;
1185   switch (PA) {
1186   case PreambleAction::Building:
1187     Result.push_back("parsing includes");
1188     break;
1189   case PreambleAction::Idle:
1190     // We handle idle specially below.
1191     break;
1192   }
1193   switch (AA.K) {
1194   case ASTAction::Queued:
1195     Result.push_back("file is queued");
1196     break;
1197   case ASTAction::RunningAction:
1198     Result.push_back("running " + AA.Name);
1199     break;
1200   case ASTAction::Building:
1201     Result.push_back("parsing main file");
1202     break;
1203   case ASTAction::Idle:
1204     // We handle idle specially below.
1205     break;
1206   }
1207   if (Result.empty())
1208     return "idle";
1209   return llvm::join(Result, ",");
1210 }
1211 
1212 } // namespace
1213 
getDefaultAsyncThreadsCount()1214 unsigned getDefaultAsyncThreadsCount() {
1215   return llvm::heavyweight_hardware_concurrency().compute_thread_count();
1216 }
1217 
render(PathRef File) const1218 FileStatus TUStatus::render(PathRef File) const {
1219   FileStatus FStatus;
1220   FStatus.uri = URIForFile::canonicalize(File, /*TUPath=*/File);
1221   FStatus.state = renderTUAction(PreambleActivity, ASTActivity);
1222   return FStatus;
1223 }
1224 
1225 struct TUScheduler::FileData {
1226   /// Latest inputs, passed to TUScheduler::update().
1227   std::string Contents;
1228   ASTWorkerHandle Worker;
1229 };
1230 
TUScheduler(const GlobalCompilationDatabase & CDB,const Options & Opts,std::unique_ptr<ParsingCallbacks> Callbacks)1231 TUScheduler::TUScheduler(const GlobalCompilationDatabase &CDB,
1232                          const Options &Opts,
1233                          std::unique_ptr<ParsingCallbacks> Callbacks)
1234     : CDB(CDB), Opts(Opts),
1235       Callbacks(Callbacks ? move(Callbacks)
1236                           : std::make_unique<ParsingCallbacks>()),
1237       Barrier(Opts.AsyncThreadsCount),
1238       IdleASTs(
1239           std::make_unique<ASTCache>(Opts.RetentionPolicy.MaxRetainedASTs)) {
1240   // Avoid null checks everywhere.
1241   if (!Opts.ContextProvider) {
1242     this->Opts.ContextProvider = [](llvm::StringRef) {
1243       return Context::current().clone();
1244     };
1245   }
1246   if (0 < Opts.AsyncThreadsCount) {
1247     PreambleTasks.emplace();
1248     WorkerThreads.emplace();
1249   }
1250 }
1251 
~TUScheduler()1252 TUScheduler::~TUScheduler() {
1253   // Notify all workers that they need to stop.
1254   Files.clear();
1255 
1256   // Wait for all in-flight tasks to finish.
1257   if (PreambleTasks)
1258     PreambleTasks->wait();
1259   if (WorkerThreads)
1260     WorkerThreads->wait();
1261 }
1262 
blockUntilIdle(Deadline D) const1263 bool TUScheduler::blockUntilIdle(Deadline D) const {
1264   for (auto &File : Files)
1265     if (!File.getValue()->Worker->blockUntilIdle(D))
1266       return false;
1267   if (PreambleTasks)
1268     if (!PreambleTasks->wait(D))
1269       return false;
1270   return true;
1271 }
1272 
update(PathRef File,ParseInputs Inputs,WantDiagnostics WantDiags)1273 bool TUScheduler::update(PathRef File, ParseInputs Inputs,
1274                          WantDiagnostics WantDiags) {
1275   std::unique_ptr<FileData> &FD = Files[File];
1276   bool NewFile = FD == nullptr;
1277   if (!FD) {
1278     // Create a new worker to process the AST-related tasks.
1279     ASTWorkerHandle Worker =
1280         ASTWorker::create(File, CDB, *IdleASTs,
1281                           WorkerThreads ? WorkerThreads.getPointer() : nullptr,
1282                           Barrier, Opts, *Callbacks);
1283     FD = std::unique_ptr<FileData>(
1284         new FileData{Inputs.Contents, std::move(Worker)});
1285   } else {
1286     FD->Contents = Inputs.Contents;
1287   }
1288   FD->Worker->update(std::move(Inputs), WantDiags);
1289   return NewFile;
1290 }
1291 
remove(PathRef File)1292 void TUScheduler::remove(PathRef File) {
1293   bool Removed = Files.erase(File);
1294   if (!Removed)
1295     elog("Trying to remove file from TUScheduler that is not tracked: {0}",
1296          File);
1297 }
1298 
getAllFileContents() const1299 llvm::StringMap<std::string> TUScheduler::getAllFileContents() const {
1300   llvm::StringMap<std::string> Results;
1301   for (auto &It : Files)
1302     Results.try_emplace(It.getKey(), It.getValue()->Contents);
1303   return Results;
1304 }
1305 
run(llvm::StringRef Name,llvm::StringRef Path,llvm::unique_function<void ()> Action)1306 void TUScheduler::run(llvm::StringRef Name, llvm::StringRef Path,
1307                       llvm::unique_function<void()> Action) {
1308   if (!PreambleTasks) {
1309     WithContext WithProvidedContext(Opts.ContextProvider(Path));
1310     return Action();
1311   }
1312   PreambleTasks->runAsync(Name, [this, Ctx = Context::current().clone(),
1313                                  Path(Path.str()),
1314                                  Action = std::move(Action)]() mutable {
1315     std::lock_guard<Semaphore> BarrierLock(Barrier);
1316     WithContext WC(std::move(Ctx));
1317     WithContext WithProvidedContext(Opts.ContextProvider(Path));
1318     Action();
1319   });
1320 }
1321 
runWithAST(llvm::StringRef Name,PathRef File,llvm::unique_function<void (llvm::Expected<InputsAndAST>)> Action,TUScheduler::ASTActionInvalidation Invalidation)1322 void TUScheduler::runWithAST(
1323     llvm::StringRef Name, PathRef File,
1324     llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action,
1325     TUScheduler::ASTActionInvalidation Invalidation) {
1326   auto It = Files.find(File);
1327   if (It == Files.end()) {
1328     Action(llvm::make_error<LSPError>(
1329         "trying to get AST for non-added document", ErrorCode::InvalidParams));
1330     return;
1331   }
1332 
1333   It->second->Worker->runWithAST(Name, std::move(Action), Invalidation);
1334 }
1335 
runWithPreamble(llvm::StringRef Name,PathRef File,PreambleConsistency Consistency,Callback<InputsAndPreamble> Action)1336 void TUScheduler::runWithPreamble(llvm::StringRef Name, PathRef File,
1337                                   PreambleConsistency Consistency,
1338                                   Callback<InputsAndPreamble> Action) {
1339   auto It = Files.find(File);
1340   if (It == Files.end()) {
1341     Action(llvm::make_error<LSPError>(
1342         "trying to get preamble for non-added document",
1343         ErrorCode::InvalidParams));
1344     return;
1345   }
1346 
1347   if (!PreambleTasks) {
1348     trace::Span Tracer(Name);
1349     SPAN_ATTACH(Tracer, "file", File);
1350     std::shared_ptr<const PreambleData> Preamble =
1351         It->second->Worker->getPossiblyStalePreamble();
1352     WithContext WithProvidedContext(Opts.ContextProvider(File));
1353     Action(InputsAndPreamble{It->second->Contents,
1354                              It->second->Worker->getCurrentCompileCommand(),
1355                              Preamble.get()});
1356     return;
1357   }
1358 
1359   std::shared_ptr<const ASTWorker> Worker = It->second->Worker.lock();
1360   auto Task =
1361       [Worker, Consistency, Name = Name.str(), File = File.str(),
1362        Contents = It->second->Contents,
1363        Command = Worker->getCurrentCompileCommand(),
1364        Ctx = Context::current().derive(kFileBeingProcessed, std::string(File)),
1365        Action = std::move(Action), this]() mutable {
1366         std::shared_ptr<const PreambleData> Preamble;
1367         if (Consistency == PreambleConsistency::Stale) {
1368           // Wait until the preamble is built for the first time, if preamble
1369           // is required. This avoids extra work of processing the preamble
1370           // headers in parallel multiple times.
1371           Worker->waitForFirstPreamble();
1372         }
1373         Preamble = Worker->getPossiblyStalePreamble();
1374 
1375         std::lock_guard<Semaphore> BarrierLock(Barrier);
1376         WithContext Guard(std::move(Ctx));
1377         trace::Span Tracer(Name);
1378         SPAN_ATTACH(Tracer, "file", File);
1379         WithContext WithProvidedContext(Opts.ContextProvider(File));
1380         Action(InputsAndPreamble{Contents, Command, Preamble.get()});
1381       };
1382 
1383   PreambleTasks->runAsync("task:" + llvm::sys::path::filename(File),
1384                           std::move(Task));
1385 }
1386 
fileStats() const1387 llvm::StringMap<TUScheduler::FileStats> TUScheduler::fileStats() const {
1388   llvm::StringMap<TUScheduler::FileStats> Result;
1389   for (const auto &PathAndFile : Files)
1390     Result.try_emplace(PathAndFile.first(),
1391                        PathAndFile.second->Worker->stats());
1392   return Result;
1393 }
1394 
getFilesWithCachedAST() const1395 std::vector<Path> TUScheduler::getFilesWithCachedAST() const {
1396   std::vector<Path> Result;
1397   for (auto &&PathAndFile : Files) {
1398     if (!PathAndFile.second->Worker->isASTCached())
1399       continue;
1400     Result.push_back(std::string(PathAndFile.first()));
1401   }
1402   return Result;
1403 }
1404 
1405 DebouncePolicy::clock::duration
compute(llvm::ArrayRef<clock::duration> History) const1406 DebouncePolicy::compute(llvm::ArrayRef<clock::duration> History) const {
1407   assert(Min <= Max && "Invalid policy");
1408   if (History.empty())
1409     return Max; // Arbitrary.
1410 
1411   // Base the result on the median rebuild.
1412   // nth_element needs a mutable array, take the chance to bound the data size.
1413   History = History.take_back(15);
1414   llvm::SmallVector<clock::duration, 15> Recent(History.begin(), History.end());
1415   auto Median = Recent.begin() + Recent.size() / 2;
1416   std::nth_element(Recent.begin(), Median, Recent.end());
1417 
1418   clock::duration Target =
1419       std::chrono::duration_cast<clock::duration>(RebuildRatio * *Median);
1420   if (Target > Max)
1421     return Max;
1422   if (Target < Min)
1423     return Min;
1424   return Target;
1425 }
1426 
fixed(clock::duration T)1427 DebouncePolicy DebouncePolicy::fixed(clock::duration T) {
1428   DebouncePolicy P;
1429   P.Min = P.Max = T;
1430   return P;
1431 }
1432 
profile(MemoryTree & MT) const1433 void TUScheduler::profile(MemoryTree &MT) const {
1434   for (const auto &Elem : fileStats()) {
1435     MT.detail(Elem.first())
1436         .child("preamble")
1437         .addUsage(Opts.StorePreamblesInMemory ? Elem.second.UsedBytesPreamble
1438                                               : 0);
1439     MT.detail(Elem.first()).child("ast").addUsage(Elem.second.UsedBytesAST);
1440   }
1441 }
1442 } // namespace clangd
1443 } // namespace clang
1444