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 "CompileCommands.h"
51 #include "Compiler.h"
52 #include "Diagnostics.h"
53 #include "GlobalCompilationDatabase.h"
54 #include "ParsedAST.h"
55 #include "Preamble.h"
56 #include "index/CanonicalIncludes.h"
57 #include "support/Cancellation.h"
58 #include "support/Context.h"
59 #include "support/Logger.h"
60 #include "support/MemoryTree.h"
61 #include "support/Path.h"
62 #include "support/ThreadCrashReporter.h"
63 #include "support/Threading.h"
64 #include "support/Trace.h"
65 #include "clang/Frontend/CompilerInvocation.h"
66 #include "clang/Tooling/CompilationDatabase.h"
67 #include "llvm/ADT/FunctionExtras.h"
68 #include "llvm/ADT/None.h"
69 #include "llvm/ADT/Optional.h"
70 #include "llvm/ADT/STLExtras.h"
71 #include "llvm/ADT/ScopeExit.h"
72 #include "llvm/ADT/SmallVector.h"
73 #include "llvm/ADT/StringExtras.h"
74 #include "llvm/ADT/StringRef.h"
75 #include "llvm/Support/Allocator.h"
76 #include "llvm/Support/Errc.h"
77 #include "llvm/Support/ErrorHandling.h"
78 #include "llvm/Support/FormatVariadic.h"
79 #include "llvm/Support/Path.h"
80 #include "llvm/Support/Threading.h"
81 #include "llvm/Support/raw_ostream.h"
82 #include <algorithm>
83 #include <atomic>
84 #include <chrono>
85 #include <condition_variable>
86 #include <functional>
87 #include <memory>
88 #include <mutex>
89 #include <queue>
90 #include <string>
91 #include <thread>
92 #include <type_traits>
93 #include <utility>
94 #include <vector>
95 
96 namespace clang {
97 namespace clangd {
98 using std::chrono::steady_clock;
99 
100 namespace {
101 // Tracks latency (in seconds) of FS operations done during a preamble build.
102 // build_type allows to split by expected VFS cache state (cold on first
103 // preamble, somewhat warm after that when building first preamble for new file,
104 // likely ~everything cached on preamble rebuild.
105 constexpr trace::Metric
106     PreambleBuildFilesystemLatency("preamble_fs_latency",
107                                    trace::Metric::Distribution, "build_type");
108 // Tracks latency of FS operations done during a preamble build as a ratio of
109 // preamble build time. build_type is same as above.
110 constexpr trace::Metric PreambleBuildFilesystemLatencyRatio(
111     "preamble_fs_latency_ratio", trace::Metric::Distribution, "build_type");
112 
113 constexpr trace::Metric PreambleBuildSize("preamble_build_size",
114                                           trace::Metric::Distribution);
115 constexpr trace::Metric PreambleSerializedSize("preamble_serialized_size",
116                                                trace::Metric::Distribution);
117 
reportPreambleBuild(const PreambleBuildStats & Stats,bool IsFirstPreamble)118 void reportPreambleBuild(const PreambleBuildStats &Stats,
119                          bool IsFirstPreamble) {
120   auto RecordWithLabel = [&Stats](llvm::StringRef Label) {
121     PreambleBuildFilesystemLatency.record(Stats.FileSystemTime, Label);
122     if (Stats.TotalBuildTime > 0) // Avoid division by zero.
123       PreambleBuildFilesystemLatencyRatio.record(
124           Stats.FileSystemTime / Stats.TotalBuildTime, Label);
125   };
126 
127   static llvm::once_flag OnceFlag;
128   llvm::call_once(OnceFlag, [&] { RecordWithLabel("first_build"); });
129   RecordWithLabel(IsFirstPreamble ? "first_build_for_file" : "rebuild");
130 
131   PreambleBuildSize.record(Stats.BuildSize);
132   PreambleSerializedSize.record(Stats.SerializedSize);
133 }
134 
135 class ASTWorker;
136 } // namespace
137 
138 static clang::clangd::Key<std::string> FileBeingProcessed;
139 
getFileBeingProcessedInContext()140 llvm::Optional<llvm::StringRef> TUScheduler::getFileBeingProcessedInContext() {
141   if (auto *File = Context::current().get(FileBeingProcessed))
142     return llvm::StringRef(*File);
143   return None;
144 }
145 
146 /// An LRU cache of idle ASTs.
147 /// Because we want to limit the overall number of these we retain, the cache
148 /// owns ASTs (and may evict them) while their workers are idle.
149 /// Workers borrow ASTs when active, and return them when done.
150 class TUScheduler::ASTCache {
151 public:
152   using Key = const ASTWorker *;
153 
ASTCache(unsigned MaxRetainedASTs)154   ASTCache(unsigned MaxRetainedASTs) : MaxRetainedASTs(MaxRetainedASTs) {}
155 
156   /// Returns result of getUsedBytes() for the AST cached by \p K.
157   /// If no AST is cached, 0 is returned.
getUsedBytes(Key K)158   std::size_t getUsedBytes(Key K) {
159     std::lock_guard<std::mutex> Lock(Mut);
160     auto It = findByKey(K);
161     if (It == LRU.end() || !It->second)
162       return 0;
163     return It->second->getUsedBytes();
164   }
165 
166   /// Store the value in the pool, possibly removing the last used AST.
167   /// The value should not be in the pool when this function is called.
put(Key K,std::unique_ptr<ParsedAST> V)168   void put(Key K, std::unique_ptr<ParsedAST> V) {
169     std::unique_lock<std::mutex> Lock(Mut);
170     assert(findByKey(K) == LRU.end());
171 
172     LRU.insert(LRU.begin(), {K, std::move(V)});
173     if (LRU.size() <= MaxRetainedASTs)
174       return;
175     // We're past the limit, remove the last element.
176     std::unique_ptr<ParsedAST> ForCleanup = std::move(LRU.back().second);
177     LRU.pop_back();
178     // Run the expensive destructor outside the lock.
179     Lock.unlock();
180     ForCleanup.reset();
181   }
182 
183   /// Returns the cached value for \p K, or llvm::None if the value is not in
184   /// the cache anymore. If nullptr was cached for \p K, this function will
185   /// return a null unique_ptr wrapped into an optional.
186   /// If \p AccessMetric is set records whether there was a hit or miss.
187   llvm::Optional<std::unique_ptr<ParsedAST>>
take(Key K,const trace::Metric * AccessMetric=nullptr)188   take(Key K, const trace::Metric *AccessMetric = nullptr) {
189     // Record metric after unlocking the mutex.
190     std::unique_lock<std::mutex> Lock(Mut);
191     auto Existing = findByKey(K);
192     if (Existing == LRU.end()) {
193       if (AccessMetric)
194         AccessMetric->record(1, "miss");
195       return None;
196     }
197     if (AccessMetric)
198       AccessMetric->record(1, "hit");
199     std::unique_ptr<ParsedAST> V = std::move(Existing->second);
200     LRU.erase(Existing);
201     // GCC 4.8 fails to compile `return V;`, as it tries to call the copy
202     // constructor of unique_ptr, so we call the move ctor explicitly to avoid
203     // this miscompile.
204     return llvm::Optional<std::unique_ptr<ParsedAST>>(std::move(V));
205   }
206 
207 private:
208   using KVPair = std::pair<Key, std::unique_ptr<ParsedAST>>;
209 
findByKey(Key K)210   std::vector<KVPair>::iterator findByKey(Key K) {
211     return llvm::find_if(LRU, [K](const KVPair &P) { return P.first == K; });
212   }
213 
214   std::mutex Mut;
215   unsigned MaxRetainedASTs;
216   /// Items sorted in LRU order, i.e. first item is the most recently accessed
217   /// one.
218   std::vector<KVPair> LRU; /* GUARDED_BY(Mut) */
219 };
220 
221 /// A map from header files to an opened "proxy" file that includes them.
222 /// If you open the header, the compile command from the proxy file is used.
223 ///
224 /// This inclusion information could also naturally live in the index, but there
225 /// are advantages to using open files instead:
226 ///  - it's easier to achieve a *stable* choice of proxy, which is important
227 ///    to avoid invalidating the preamble
228 ///  - context-sensitive flags for libraries with multiple configurations
229 ///    (e.g. C++ stdlib sensitivity to -std version)
230 ///  - predictable behavior, e.g. guarantees that go-to-def landing on a header
231 ///    will have a suitable command available
232 ///  - fewer scaling problems to solve (project include graphs are big!)
233 ///
234 /// Implementation details:
235 /// - We only record this for mainfiles where the command was trustworthy
236 ///   (i.e. not inferred). This avoids a bad inference "infecting" other files.
237 /// - Once we've picked a proxy file for a header, we stick with it until the
238 ///   proxy file is invalidated *and* a new candidate proxy file is built.
239 ///   Switching proxies is expensive, as the compile flags will (probably)
240 ///   change and therefore we'll end up rebuilding the header's preamble.
241 /// - We don't capture the actual compile command, but just the filename we
242 ///   should query to get it. This avoids getting out of sync with the CDB.
243 ///
244 /// All methods are threadsafe. In practice, update() comes from preamble
245 /// threads, remove()s mostly from the main thread, and get() from ASTWorker.
246 /// Writes are rare and reads are cheap, so we don't expect much contention.
247 class TUScheduler::HeaderIncluderCache {
248   // We should be be a little careful how we store the include graph of open
249   // files, as each can have a large number of transitive headers.
250   // This representation is O(unique transitive source files).
251   llvm::BumpPtrAllocator Arena;
252   struct Association {
253     llvm::StringRef MainFile;
254     // Circular-linked-list of associations with the same mainFile.
255     // Null indicates that the mainfile was removed.
256     Association *Next;
257   };
258   llvm::StringMap<Association, llvm::BumpPtrAllocator &> HeaderToMain;
259   llvm::StringMap<Association *, llvm::BumpPtrAllocator &> MainToFirst;
260   std::atomic<size_t> UsedBytes; // Updated after writes.
261   mutable std::mutex Mu;
262 
invalidate(Association * First)263   void invalidate(Association *First) {
264     Association *Current = First;
265     do {
266       Association *Next = Current->Next;
267       Current->Next = nullptr;
268       Current = Next;
269     } while (Current != First);
270   }
271 
272   // Create the circular list and return the head of it.
associate(llvm::StringRef MainFile,llvm::ArrayRef<std::string> Headers)273   Association *associate(llvm::StringRef MainFile,
274                          llvm::ArrayRef<std::string> Headers) {
275     Association *First = nullptr, *Prev = nullptr;
276     for (const std::string &Header : Headers) {
277       auto &Assoc = HeaderToMain[Header];
278       if (Assoc.Next)
279         continue; // Already has a valid association.
280 
281       Assoc.MainFile = MainFile;
282       Assoc.Next = Prev;
283       Prev = &Assoc;
284       if (!First)
285         First = &Assoc;
286     }
287     if (First)
288       First->Next = Prev;
289     return First;
290   }
291 
updateMemoryUsage()292   void updateMemoryUsage() {
293     auto StringMapHeap = [](const auto &Map) {
294       // StringMap stores the hashtable on the heap.
295       // It contains pointers to the entries, and a hashcode for each.
296       return Map.getNumBuckets() * (sizeof(void *) + sizeof(unsigned));
297     };
298     size_t Usage = Arena.getTotalMemory() + StringMapHeap(MainToFirst) +
299                    StringMapHeap(HeaderToMain) + sizeof(*this);
300     UsedBytes.store(Usage, std::memory_order_release);
301   }
302 
303 public:
HeaderIncluderCache()304   HeaderIncluderCache() : HeaderToMain(Arena), MainToFirst(Arena) {
305     updateMemoryUsage();
306   }
307 
308   // Associate each header with MainFile (unless already associated).
309   // Headers not in the list will have their associations removed.
update(PathRef MainFile,llvm::ArrayRef<std::string> Headers)310   void update(PathRef MainFile, llvm::ArrayRef<std::string> Headers) {
311     std::lock_guard<std::mutex> Lock(Mu);
312     auto It = MainToFirst.try_emplace(MainFile, nullptr);
313     Association *&First = It.first->second;
314     if (First)
315       invalidate(First);
316     First = associate(It.first->first(), Headers);
317     updateMemoryUsage();
318   }
319 
320   // Mark MainFile as gone.
321   // This will *not* disassociate headers with MainFile immediately, but they
322   // will be eligible for association with other files that get update()d.
remove(PathRef MainFile)323   void remove(PathRef MainFile) {
324     std::lock_guard<std::mutex> Lock(Mu);
325     Association *&First = MainToFirst[MainFile];
326     if (First) {
327       invalidate(First);
328       First = nullptr;
329     }
330     // MainToFirst entry should stay alive, as Associations might be pointing at
331     // its key.
332   }
333 
334   /// Get the mainfile associated with Header, or the empty string if none.
get(PathRef Header) const335   std::string get(PathRef Header) const {
336     std::lock_guard<std::mutex> Lock(Mu);
337     return HeaderToMain.lookup(Header).MainFile.str();
338   }
339 
getUsedBytes() const340   size_t getUsedBytes() const {
341     return UsedBytes.load(std::memory_order_acquire);
342   }
343 };
344 
345 namespace {
346 
isReliable(const tooling::CompileCommand & Cmd)347 bool isReliable(const tooling::CompileCommand &Cmd) {
348   return Cmd.Heuristic.empty();
349 }
350 
351 /// Threadsafe manager for updating a TUStatus and emitting it after each
352 /// update.
353 class SynchronizedTUStatus {
354 public:
SynchronizedTUStatus(PathRef FileName,ParsingCallbacks & Callbacks)355   SynchronizedTUStatus(PathRef FileName, ParsingCallbacks &Callbacks)
356       : FileName(FileName), Callbacks(Callbacks) {}
357 
update(llvm::function_ref<void (TUStatus &)> Mutator)358   void update(llvm::function_ref<void(TUStatus &)> Mutator) {
359     std::lock_guard<std::mutex> Lock(StatusMu);
360     Mutator(Status);
361     emitStatusLocked();
362   }
363 
364   /// Prevents emitting of further updates.
stop()365   void stop() {
366     std::lock_guard<std::mutex> Lock(StatusMu);
367     CanPublish = false;
368   }
369 
370 private:
emitStatusLocked()371   void emitStatusLocked() {
372     if (CanPublish)
373       Callbacks.onFileUpdated(FileName, Status);
374   }
375 
376   const Path FileName;
377 
378   std::mutex StatusMu;
379   TUStatus Status;
380   bool CanPublish = true;
381   ParsingCallbacks &Callbacks;
382 };
383 
384 // An attempt to acquire resources for a task using PreambleThrottler.
385 // Initially it is unsatisfied, it (hopefully) becomes satisfied later but may
386 // be destroyed before then. Destruction releases all resources.
387 class PreambleThrottlerRequest {
388 public:
389   // The condition variable is signalled when the request is satisfied.
PreambleThrottlerRequest(llvm::StringRef Filename,PreambleThrottler * Throttler,std::condition_variable & CV)390   PreambleThrottlerRequest(llvm::StringRef Filename,
391                            PreambleThrottler *Throttler,
392                            std::condition_variable &CV)
393       : Throttler(Throttler), Satisfied(Throttler == nullptr) {
394     // If there is no throttler, this dummy request is always satisfied.
395     if (!Throttler)
396       return;
397     ID = Throttler->acquire(Filename, [&] {
398       Satisfied.store(true, std::memory_order_release);
399       CV.notify_all();
400     });
401   }
402 
satisfied() const403   bool satisfied() const { return Satisfied.load(std::memory_order_acquire); }
404 
405   // When the request is destroyed:
406   //  - if resources are not yet obtained, stop trying to get them.
407   //  - if resources were obtained, release them.
~PreambleThrottlerRequest()408   ~PreambleThrottlerRequest() {
409     if (Throttler)
410       Throttler->release(ID);
411   }
412 
413 private:
414   PreambleThrottler::RequestID ID;
415   PreambleThrottler *Throttler;
416   std::atomic<bool> Satisfied = {false};
417 };
418 
419 /// Responsible for building preambles. Whenever the thread is idle and the
420 /// preamble is outdated, it starts to build a fresh preamble from the latest
421 /// inputs. If RunSync is true, preambles are built synchronously in update()
422 /// instead.
423 class PreambleThread {
424 public:
PreambleThread(llvm::StringRef FileName,ParsingCallbacks & Callbacks,bool StorePreambleInMemory,bool RunSync,PreambleThrottler * Throttler,SynchronizedTUStatus & Status,TUScheduler::HeaderIncluderCache & HeaderIncluders,ASTWorker & AW)425   PreambleThread(llvm::StringRef FileName, ParsingCallbacks &Callbacks,
426                  bool StorePreambleInMemory, bool RunSync,
427                  PreambleThrottler *Throttler, SynchronizedTUStatus &Status,
428                  TUScheduler::HeaderIncluderCache &HeaderIncluders,
429                  ASTWorker &AW)
430       : FileName(FileName), Callbacks(Callbacks),
431         StoreInMemory(StorePreambleInMemory), RunSync(RunSync),
432         Throttler(Throttler), Status(Status), ASTPeer(AW),
433         HeaderIncluders(HeaderIncluders) {}
434 
435   /// It isn't guaranteed that each requested version will be built. If there
436   /// are multiple update requests while building a preamble, only the last one
437   /// will be built.
update(std::unique_ptr<CompilerInvocation> CI,ParseInputs PI,std::vector<Diag> CIDiags,WantDiagnostics WantDiags)438   void update(std::unique_ptr<CompilerInvocation> CI, ParseInputs PI,
439               std::vector<Diag> CIDiags, WantDiagnostics WantDiags) {
440     Request Req = {std::move(CI), std::move(PI), std::move(CIDiags), WantDiags,
441                    Context::current().clone()};
442     if (RunSync) {
443       build(std::move(Req));
444       Status.update([](TUStatus &Status) {
445         Status.PreambleActivity = PreambleAction::Idle;
446       });
447       return;
448     }
449     {
450       std::unique_lock<std::mutex> Lock(Mutex);
451       // If NextReq was requested with WantDiagnostics::Yes we cannot just drop
452       // that on the floor. Block until we start building it. This won't
453       // dead-lock as we are blocking the caller thread, while builds continue
454       // on preamble thread.
455       ReqCV.wait(Lock, [this] {
456         return !NextReq || NextReq->WantDiags != WantDiagnostics::Yes;
457       });
458       NextReq = std::move(Req);
459     }
460     // Let the worker thread know there's a request, notify_one is safe as there
461     // should be a single worker thread waiting on it.
462     ReqCV.notify_all();
463   }
464 
run()465   void run() {
466     while (true) {
467       llvm::Optional<PreambleThrottlerRequest> Throttle;
468       {
469         std::unique_lock<std::mutex> Lock(Mutex);
470         assert(!CurrentReq && "Already processing a request?");
471         // Wait until stop is called or there is a request.
472         ReqCV.wait(Lock, [&] { return NextReq || Done; });
473         if (Done)
474           break;
475 
476         Throttle.emplace(FileName, Throttler, ReqCV);
477         // If acquire succeeded synchronously, avoid status jitter.
478         if (!Throttle->satisfied())
479           Status.update([&](TUStatus &Status) {
480             Status.PreambleActivity = PreambleAction::Queued;
481           });
482         ReqCV.wait(Lock, [&] { return Throttle->satisfied() || Done; });
483         if (Done)
484           break;
485         // While waiting for the throttler, the request may have been updated!
486         // That's fine though, there's still guaranteed to be some request.
487 
488         CurrentReq = std::move(*NextReq);
489         NextReq.reset();
490       }
491 
492       {
493         WithContext Guard(std::move(CurrentReq->Ctx));
494         // Note that we don't make use of the ContextProvider here.
495         // Preamble tasks are always scheduled by ASTWorker tasks, and we
496         // reuse the context/config that was created at that level.
497 
498         // Build the preamble and let the waiters know about it.
499         build(std::move(*CurrentReq));
500       }
501       // Releasing the throttle before destroying the request assists testing.
502       Throttle.reset();
503       bool IsEmpty = false;
504       {
505         std::lock_guard<std::mutex> Lock(Mutex);
506         CurrentReq.reset();
507         IsEmpty = !NextReq;
508       }
509       if (IsEmpty) {
510         // We don't perform this above, before waiting for a request to make
511         // tests more deterministic. As there can be a race between this thread
512         // and client thread(clangdserver).
513         Status.update([](TUStatus &Status) {
514           Status.PreambleActivity = PreambleAction::Idle;
515         });
516       }
517       ReqCV.notify_all();
518     }
519     dlog("Preamble worker for {0} stopped", FileName);
520   }
521 
522   /// Signals the run loop to exit.
stop()523   void stop() {
524     dlog("Preamble worker for {0} received stop", FileName);
525     {
526       std::lock_guard<std::mutex> Lock(Mutex);
527       Done = true;
528       NextReq.reset();
529     }
530     // Let the worker thread know that it should stop.
531     ReqCV.notify_all();
532   }
533 
blockUntilIdle(Deadline Timeout) const534   bool blockUntilIdle(Deadline Timeout) const {
535     std::unique_lock<std::mutex> Lock(Mutex);
536     return wait(Lock, ReqCV, Timeout, [&] { return !NextReq && !CurrentReq; });
537   }
538 
539 private:
540   /// Holds inputs required for building a preamble. CI is guaranteed to be
541   /// non-null.
542   struct Request {
543     std::unique_ptr<CompilerInvocation> CI;
544     ParseInputs Inputs;
545     std::vector<Diag> CIDiags;
546     WantDiagnostics WantDiags;
547     Context Ctx;
548   };
549 
isDone()550   bool isDone() {
551     std::lock_guard<std::mutex> Lock(Mutex);
552     return Done;
553   }
554 
555   /// Builds a preamble for \p Req, might reuse LatestBuild if possible.
556   /// Notifies ASTWorker after build finishes.
557   void build(Request Req);
558 
559   mutable std::mutex Mutex;
560   bool Done = false;                  /* GUARDED_BY(Mutex) */
561   llvm::Optional<Request> NextReq;    /* GUARDED_BY(Mutex) */
562   llvm::Optional<Request> CurrentReq; /* GUARDED_BY(Mutex) */
563   // Signaled whenever a thread populates NextReq or worker thread builds a
564   // Preamble.
565   mutable std::condition_variable ReqCV; /* GUARDED_BY(Mutex) */
566   // Accessed only by preamble thread.
567   std::shared_ptr<const PreambleData> LatestBuild;
568 
569   const Path FileName;
570   ParsingCallbacks &Callbacks;
571   const bool StoreInMemory;
572   const bool RunSync;
573   PreambleThrottler *Throttler;
574 
575   SynchronizedTUStatus &Status;
576   ASTWorker &ASTPeer;
577   TUScheduler::HeaderIncluderCache &HeaderIncluders;
578 };
579 
580 class ASTWorkerHandle;
581 
582 /// Owns one instance of the AST, schedules updates and reads of it.
583 /// Also responsible for building and providing access to the preamble.
584 /// Each ASTWorker processes the async requests sent to it on a separate
585 /// dedicated thread.
586 /// The ASTWorker that manages the AST is shared by both the processing thread
587 /// and the TUScheduler. The TUScheduler should discard an ASTWorker when
588 /// remove() is called, but its thread may be busy and we don't want to block.
589 /// So the workers are accessed via an ASTWorkerHandle. Destroying the handle
590 /// signals the worker to exit its run loop and gives up shared ownership of the
591 /// worker.
592 class ASTWorker {
593   friend class ASTWorkerHandle;
594   ASTWorker(PathRef FileName, const GlobalCompilationDatabase &CDB,
595             TUScheduler::ASTCache &LRUCache,
596             TUScheduler::HeaderIncluderCache &HeaderIncluders,
597             Semaphore &Barrier, bool RunSync, const TUScheduler::Options &Opts,
598             ParsingCallbacks &Callbacks);
599 
600 public:
601   /// Create a new ASTWorker and return a handle to it.
602   /// The processing thread is spawned using \p Tasks. However, when \p Tasks
603   /// is null, all requests will be processed on the calling thread
604   /// synchronously instead. \p Barrier is acquired when processing each
605   /// request, it is used to limit the number of actively running threads.
606   static ASTWorkerHandle
607   create(PathRef FileName, const GlobalCompilationDatabase &CDB,
608          TUScheduler::ASTCache &IdleASTs,
609          TUScheduler::HeaderIncluderCache &HeaderIncluders,
610          AsyncTaskRunner *Tasks, Semaphore &Barrier,
611          const TUScheduler::Options &Opts, ParsingCallbacks &Callbacks);
612   ~ASTWorker();
613 
614   void update(ParseInputs Inputs, WantDiagnostics, bool ContentChanged);
615   void
616   runWithAST(llvm::StringRef Name,
617              llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action,
618              TUScheduler::ASTActionInvalidation);
619   bool blockUntilIdle(Deadline Timeout) const;
620 
621   std::shared_ptr<const PreambleData> getPossiblyStalePreamble(
622       std::shared_ptr<const ASTSignals> *ASTSignals = nullptr) const;
623 
624   /// Used to inform ASTWorker about a new preamble build by PreambleThread.
625   /// Diagnostics are only published through this callback. This ensures they
626   /// are always for newer versions of the file, as the callback gets called in
627   /// the same order as update requests.
628   void updatePreamble(std::unique_ptr<CompilerInvocation> CI, ParseInputs PI,
629                       std::shared_ptr<const PreambleData> Preamble,
630                       std::vector<Diag> CIDiags, WantDiagnostics WantDiags);
631 
632   /// Obtain a preamble reflecting all updates so far. Threadsafe.
633   /// It may be delivered immediately, or later on the worker thread.
634   void getCurrentPreamble(
635       llvm::unique_function<void(std::shared_ptr<const PreambleData>)>);
636   /// Returns compile command from the current file inputs.
637   tooling::CompileCommand getCurrentCompileCommand() const;
638 
639   /// Wait for the first build of preamble to finish. Preamble itself can be
640   /// accessed via getPossiblyStalePreamble(). Note that this function will
641   /// return after an unsuccessful build of the preamble too, i.e. result of
642   /// getPossiblyStalePreamble() can be null even after this function returns.
643   void waitForFirstPreamble() const;
644 
645   TUScheduler::FileStats stats() const;
646   bool isASTCached() const;
647 
648 private:
649   // Details of an update request that are relevant to scheduling.
650   struct UpdateType {
651     // Do we want diagnostics from this version?
652     // If Yes, we must always build this version.
653     // If No, we only need to build this version if it's read.
654     // If Auto, we build if it's read or if the debounce expires.
655     WantDiagnostics Diagnostics;
656     // Did the main-file content of the document change?
657     // If so, we're allowed to cancel certain invalidated preceding reads.
658     bool ContentChanged;
659   };
660 
661   /// Publishes diagnostics for \p Inputs. It will build an AST or reuse the
662   /// cached one if applicable. Assumes LatestPreamble is compatible for \p
663   /// Inputs.
664   void generateDiagnostics(std::unique_ptr<CompilerInvocation> Invocation,
665                            ParseInputs Inputs, std::vector<Diag> CIDiags);
666 
667   void updateASTSignals(ParsedAST &AST);
668 
669   // Must be called exactly once on processing thread. Will return after
670   // stop() is called on a separate thread and all pending requests are
671   // processed.
672   void run();
673   /// Signal that run() should finish processing pending requests and exit.
674   void stop();
675 
676   /// Adds a new task to the end of the request queue.
677   void startTask(llvm::StringRef Name, llvm::unique_function<void()> Task,
678                  llvm::Optional<UpdateType> Update,
679                  TUScheduler::ASTActionInvalidation);
680   /// Runs a task synchronously.
681   void runTask(llvm::StringRef Name, llvm::function_ref<void()> Task);
682 
683   /// Determines the next action to perform.
684   /// All actions that should never run are discarded.
685   /// Returns a deadline for the next action. If it's expired, run now.
686   /// scheduleLocked() is called again at the deadline, or if requests arrive.
687   Deadline scheduleLocked();
688   /// Should the first task in the queue be skipped instead of run?
689   bool shouldSkipHeadLocked() const;
690 
691   struct Request {
692     llvm::unique_function<void()> Action;
693     std::string Name;
694     steady_clock::time_point AddTime;
695     Context Ctx;
696     llvm::Optional<Context> QueueCtx;
697     llvm::Optional<UpdateType> Update;
698     TUScheduler::ASTActionInvalidation InvalidationPolicy;
699     Canceler Invalidate;
700   };
701 
702   /// Handles retention of ASTs.
703   TUScheduler::ASTCache &IdleASTs;
704   TUScheduler::HeaderIncluderCache &HeaderIncluders;
705   const bool RunSync;
706   /// Time to wait after an update to see whether another update obsoletes it.
707   const DebouncePolicy UpdateDebounce;
708   /// File that ASTWorker is responsible for.
709   const Path FileName;
710   /// Callback to create processing contexts for tasks.
711   const std::function<Context(llvm::StringRef)> ContextProvider;
712   const GlobalCompilationDatabase &CDB;
713   /// Callback invoked when preamble or main file AST is built.
714   ParsingCallbacks &Callbacks;
715 
716   Semaphore &Barrier;
717   /// Whether the 'onMainAST' callback ran for the current FileInputs.
718   bool RanASTCallback = false;
719   /// Guards members used by both TUScheduler and the worker thread.
720   mutable std::mutex Mutex;
721   /// File inputs, currently being used by the worker.
722   /// Writes and reads from unknown threads are locked. Reads from the worker
723   /// thread are not locked, as it's the only writer.
724   ParseInputs FileInputs; /* GUARDED_BY(Mutex) */
725   /// Times of recent AST rebuilds, used for UpdateDebounce computation.
726   llvm::SmallVector<DebouncePolicy::clock::duration>
727       RebuildTimes; /* GUARDED_BY(Mutex) */
728   /// Set to true to signal run() to finish processing.
729   bool Done;                              /* GUARDED_BY(Mutex) */
730   std::deque<Request> Requests;           /* GUARDED_BY(Mutex) */
731   llvm::Optional<Request> CurrentRequest; /* GUARDED_BY(Mutex) */
732   /// Signalled whenever a new request has been scheduled or processing of a
733   /// request has completed.
734   mutable std::condition_variable RequestsCV;
735   std::shared_ptr<const ASTSignals> LatestASTSignals; /* GUARDED_BY(Mutex) */
736   /// Latest build preamble for current TU.
737   /// None means no builds yet, null means there was an error while building.
738   /// Only written by ASTWorker's thread.
739   llvm::Optional<std::shared_ptr<const PreambleData>> LatestPreamble;
740   std::deque<Request> PreambleRequests; /* GUARDED_BY(Mutex) */
741   /// Signaled whenever LatestPreamble changes state or there's a new
742   /// PreambleRequest.
743   mutable std::condition_variable PreambleCV;
744   /// Guards the callback that publishes results of AST-related computations
745   /// (diagnostics) and file statuses.
746   std::mutex PublishMu;
747   // Used to prevent remove document + add document races that lead to
748   // out-of-order callbacks for publishing results of onMainAST callback.
749   //
750   // The lifetime of the old/new ASTWorkers will overlap, but their handles
751   // don't. When the old handle is destroyed, the old worker will stop reporting
752   // any results to the user.
753   bool CanPublishResults = true; /* GUARDED_BY(PublishMu) */
754   std::atomic<unsigned> ASTBuildCount = {0};
755   std::atomic<unsigned> PreambleBuildCount = {0};
756 
757   SynchronizedTUStatus Status;
758   PreambleThread PreamblePeer;
759 };
760 
761 /// A smart-pointer-like class that points to an active ASTWorker.
762 /// In destructor, signals to the underlying ASTWorker that no new requests will
763 /// be sent and the processing loop may exit (after running all pending
764 /// requests).
765 class ASTWorkerHandle {
766   friend class ASTWorker;
ASTWorkerHandle(std::shared_ptr<ASTWorker> Worker)767   ASTWorkerHandle(std::shared_ptr<ASTWorker> Worker)
768       : Worker(std::move(Worker)) {
769     assert(this->Worker);
770   }
771 
772 public:
773   ASTWorkerHandle(const ASTWorkerHandle &) = delete;
774   ASTWorkerHandle &operator=(const ASTWorkerHandle &) = delete;
775   ASTWorkerHandle(ASTWorkerHandle &&) = default;
776   ASTWorkerHandle &operator=(ASTWorkerHandle &&) = default;
777 
~ASTWorkerHandle()778   ~ASTWorkerHandle() {
779     if (Worker)
780       Worker->stop();
781   }
782 
operator *()783   ASTWorker &operator*() {
784     assert(Worker && "Handle was moved from");
785     return *Worker;
786   }
787 
operator ->()788   ASTWorker *operator->() {
789     assert(Worker && "Handle was moved from");
790     return Worker.get();
791   }
792 
793   /// Returns an owning reference to the underlying ASTWorker that can outlive
794   /// the ASTWorkerHandle. However, no new requests to an active ASTWorker can
795   /// be schedule via the returned reference, i.e. only reads of the preamble
796   /// are possible.
lock()797   std::shared_ptr<const ASTWorker> lock() { return Worker; }
798 
799 private:
800   std::shared_ptr<ASTWorker> Worker;
801 };
802 
803 ASTWorkerHandle
create(PathRef FileName,const GlobalCompilationDatabase & CDB,TUScheduler::ASTCache & IdleASTs,TUScheduler::HeaderIncluderCache & HeaderIncluders,AsyncTaskRunner * Tasks,Semaphore & Barrier,const TUScheduler::Options & Opts,ParsingCallbacks & Callbacks)804 ASTWorker::create(PathRef FileName, const GlobalCompilationDatabase &CDB,
805                   TUScheduler::ASTCache &IdleASTs,
806                   TUScheduler::HeaderIncluderCache &HeaderIncluders,
807                   AsyncTaskRunner *Tasks, Semaphore &Barrier,
808                   const TUScheduler::Options &Opts,
809                   ParsingCallbacks &Callbacks) {
810   std::shared_ptr<ASTWorker> Worker(
811       new ASTWorker(FileName, CDB, IdleASTs, HeaderIncluders, Barrier,
812                     /*RunSync=*/!Tasks, Opts, Callbacks));
813   if (Tasks) {
814     Tasks->runAsync("ASTWorker:" + llvm::sys::path::filename(FileName),
815                     [Worker]() { Worker->run(); });
816     Tasks->runAsync("PreambleWorker:" + llvm::sys::path::filename(FileName),
817                     [Worker]() { Worker->PreamblePeer.run(); });
818   }
819 
820   return ASTWorkerHandle(std::move(Worker));
821 }
822 
ASTWorker(PathRef FileName,const GlobalCompilationDatabase & CDB,TUScheduler::ASTCache & LRUCache,TUScheduler::HeaderIncluderCache & HeaderIncluders,Semaphore & Barrier,bool RunSync,const TUScheduler::Options & Opts,ParsingCallbacks & Callbacks)823 ASTWorker::ASTWorker(PathRef FileName, const GlobalCompilationDatabase &CDB,
824                      TUScheduler::ASTCache &LRUCache,
825                      TUScheduler::HeaderIncluderCache &HeaderIncluders,
826                      Semaphore &Barrier, bool RunSync,
827                      const TUScheduler::Options &Opts,
828                      ParsingCallbacks &Callbacks)
829     : IdleASTs(LRUCache), HeaderIncluders(HeaderIncluders), RunSync(RunSync),
830       UpdateDebounce(Opts.UpdateDebounce), FileName(FileName),
831       ContextProvider(Opts.ContextProvider), CDB(CDB), Callbacks(Callbacks),
832       Barrier(Barrier), Done(false), Status(FileName, Callbacks),
833       PreamblePeer(FileName, Callbacks, Opts.StorePreamblesInMemory, RunSync,
834                    Opts.PreambleThrottler, Status, HeaderIncluders, *this) {
835   // Set a fallback command because compile command can be accessed before
836   // `Inputs` is initialized. Other fields are only used after initialization
837   // from client inputs.
838   FileInputs.CompileCommand = CDB.getFallbackCommand(FileName);
839 }
840 
~ASTWorker()841 ASTWorker::~ASTWorker() {
842   // Make sure we remove the cached AST, if any.
843   IdleASTs.take(this);
844 #ifndef NDEBUG
845   std::lock_guard<std::mutex> Lock(Mutex);
846   assert(Done && "handle was not destroyed");
847   assert(Requests.empty() && !CurrentRequest &&
848          "unprocessed requests when destroying ASTWorker");
849 #endif
850 }
851 
update(ParseInputs Inputs,WantDiagnostics WantDiags,bool ContentChanged)852 void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags,
853                        bool ContentChanged) {
854   llvm::StringLiteral TaskName = "Update";
855   auto Task = [=]() mutable {
856     // Get the actual command as `Inputs` does not have a command.
857     // FIXME: some build systems like Bazel will take time to preparing
858     // environment to build the file, it would be nice if we could emit a
859     // "PreparingBuild" status to inform users, it is non-trivial given the
860     // current implementation.
861     auto Cmd = CDB.getCompileCommand(FileName);
862     // If we don't have a reliable command for this file, it may be a header.
863     // Try to find a file that includes it, to borrow its command.
864     if (!Cmd || !isReliable(*Cmd)) {
865       std::string ProxyFile = HeaderIncluders.get(FileName);
866       if (!ProxyFile.empty()) {
867         auto ProxyCmd = CDB.getCompileCommand(ProxyFile);
868         if (!ProxyCmd || !isReliable(*ProxyCmd)) {
869           // This command is supposed to be reliable! It's probably gone.
870           HeaderIncluders.remove(ProxyFile);
871         } else {
872           // We have a reliable command for an including file, use it.
873           Cmd = tooling::transferCompileCommand(std::move(*ProxyCmd), FileName);
874         }
875       }
876     }
877     if (Cmd)
878       Inputs.CompileCommand = std::move(*Cmd);
879     else
880       Inputs.CompileCommand = CDB.getFallbackCommand(FileName);
881 
882     bool InputsAreTheSame =
883         std::tie(FileInputs.CompileCommand, FileInputs.Contents) ==
884         std::tie(Inputs.CompileCommand, Inputs.Contents);
885     // Cached AST is invalidated.
886     if (!InputsAreTheSame) {
887       IdleASTs.take(this);
888       RanASTCallback = false;
889     }
890 
891     // Update current inputs so that subsequent reads can see them.
892     {
893       std::lock_guard<std::mutex> Lock(Mutex);
894       FileInputs = Inputs;
895     }
896 
897     log("ASTWorker building file {0} version {1} with command {2}\n[{3}]\n{4}",
898         FileName, Inputs.Version, Inputs.CompileCommand.Heuristic,
899         Inputs.CompileCommand.Directory,
900         printArgv(Inputs.CompileCommand.CommandLine));
901 
902     StoreDiags CompilerInvocationDiagConsumer;
903     std::vector<std::string> CC1Args;
904     std::unique_ptr<CompilerInvocation> Invocation = buildCompilerInvocation(
905         Inputs, CompilerInvocationDiagConsumer, &CC1Args);
906     // Log cc1 args even (especially!) if creating invocation failed.
907     if (!CC1Args.empty())
908       vlog("Driver produced command: cc1 {0}", printArgv(CC1Args));
909     std::vector<Diag> CompilerInvocationDiags =
910         CompilerInvocationDiagConsumer.take();
911     if (!Invocation) {
912       elog("Could not build CompilerInvocation for file {0}", FileName);
913       // Remove the old AST if it's still in cache.
914       IdleASTs.take(this);
915       RanASTCallback = false;
916       // Report the diagnostics we collected when parsing the command line.
917       Callbacks.onFailedAST(FileName, Inputs.Version,
918                             std::move(CompilerInvocationDiags),
919                             [&](llvm::function_ref<void()> Publish) {
920                               // Ensure we only publish results from the worker
921                               // if the file was not removed, making sure there
922                               // are not race conditions.
923                               std::lock_guard<std::mutex> Lock(PublishMu);
924                               if (CanPublishResults)
925                                 Publish();
926                             });
927       // Note that this might throw away a stale preamble that might still be
928       // useful, but this is how we communicate a build error.
929       LatestPreamble.emplace();
930       // Make sure anyone waiting for the preamble gets notified it could not be
931       // built.
932       PreambleCV.notify_all();
933       return;
934     }
935 
936     PreamblePeer.update(std::move(Invocation), std::move(Inputs),
937                         std::move(CompilerInvocationDiags), WantDiags);
938     std::unique_lock<std::mutex> Lock(Mutex);
939     PreambleCV.wait(Lock, [this] {
940       // Block until we reiceve a preamble request, unless a preamble already
941       // exists, as patching an empty preamble would imply rebuilding it from
942       // scratch.
943       // We block here instead of the consumer to prevent any deadlocks. Since
944       // LatestPreamble is only populated by ASTWorker thread.
945       return LatestPreamble || !PreambleRequests.empty() || Done;
946     });
947   };
948   startTask(TaskName, std::move(Task), UpdateType{WantDiags, ContentChanged},
949             TUScheduler::NoInvalidation);
950 }
951 
runWithAST(llvm::StringRef Name,llvm::unique_function<void (llvm::Expected<InputsAndAST>)> Action,TUScheduler::ASTActionInvalidation Invalidation)952 void ASTWorker::runWithAST(
953     llvm::StringRef Name,
954     llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action,
955     TUScheduler::ASTActionInvalidation Invalidation) {
956   // Tracks ast cache accesses for read operations.
957   static constexpr trace::Metric ASTAccessForRead(
958       "ast_access_read", trace::Metric::Counter, "result");
959   auto Task = [=, Action = std::move(Action)]() mutable {
960     if (auto Reason = isCancelled())
961       return Action(llvm::make_error<CancelledError>(Reason));
962     llvm::Optional<std::unique_ptr<ParsedAST>> AST =
963         IdleASTs.take(this, &ASTAccessForRead);
964     if (!AST) {
965       StoreDiags CompilerInvocationDiagConsumer;
966       std::unique_ptr<CompilerInvocation> Invocation =
967           buildCompilerInvocation(FileInputs, CompilerInvocationDiagConsumer);
968       // Try rebuilding the AST.
969       vlog("ASTWorker rebuilding evicted AST to run {0}: {1} version {2}", Name,
970            FileName, FileInputs.Version);
971       // FIXME: We might need to build a patched ast once preamble thread starts
972       // running async. Currently getPossiblyStalePreamble below will always
973       // return a compatible preamble as ASTWorker::update blocks.
974       llvm::Optional<ParsedAST> NewAST;
975       if (Invocation) {
976         NewAST = ParsedAST::build(FileName, FileInputs, std::move(Invocation),
977                                   CompilerInvocationDiagConsumer.take(),
978                                   getPossiblyStalePreamble());
979         ++ASTBuildCount;
980       }
981       AST = NewAST ? std::make_unique<ParsedAST>(std::move(*NewAST)) : nullptr;
982     }
983     // Make sure we put the AST back into the LRU cache.
984     auto _ = llvm::make_scope_exit(
985         [&AST, this]() { IdleASTs.put(this, std::move(*AST)); });
986     // Run the user-provided action.
987     if (!*AST)
988       return Action(error(llvm::errc::invalid_argument, "invalid AST"));
989     vlog("ASTWorker running {0} on version {2} of {1}", Name, FileName,
990          FileInputs.Version);
991     Action(InputsAndAST{FileInputs, **AST});
992   };
993   startTask(Name, std::move(Task), /*Update=*/None, Invalidation);
994 }
995 
996 /// To be called from ThreadCrashReporter's signal handler.
crashDumpCompileCommand(llvm::raw_ostream & OS,const tooling::CompileCommand & Command)997 static void crashDumpCompileCommand(llvm::raw_ostream &OS,
998                                     const tooling::CompileCommand &Command) {
999   OS << "  Filename: " << Command.Filename << "\n";
1000   OS << "  Directory: " << Command.Directory << "\n";
1001   OS << "  Command Line:";
1002   for (auto &Arg : Command.CommandLine) {
1003     OS << " " << Arg;
1004   }
1005   OS << "\n";
1006 }
1007 
1008 /// To be called from ThreadCrashReporter's signal handler.
crashDumpFileContents(llvm::raw_ostream & OS,const std::string & Contents)1009 static void crashDumpFileContents(llvm::raw_ostream &OS,
1010                                   const std::string &Contents) {
1011   // Avoid flooding the terminal with source code by default, but allow clients
1012   // to opt in. Use an env var to preserve backwards compatibility of the
1013   // command line interface, while allowing it to be set outside the clangd
1014   // launch site for more flexibility.
1015   if (getenv("CLANGD_CRASH_DUMP_SOURCE")) {
1016     OS << "  Contents:\n";
1017     OS << Contents << "\n";
1018   }
1019 }
1020 
1021 /// To be called from ThreadCrashReporter's signal handler.
crashDumpParseInputs(llvm::raw_ostream & OS,const ParseInputs & FileInputs)1022 static void crashDumpParseInputs(llvm::raw_ostream &OS,
1023                                  const ParseInputs &FileInputs) {
1024   auto &Command = FileInputs.CompileCommand;
1025   crashDumpCompileCommand(OS, Command);
1026   OS << "  Version: " << FileInputs.Version << "\n";
1027   crashDumpFileContents(OS, FileInputs.Contents);
1028 }
1029 
build(Request Req)1030 void PreambleThread::build(Request Req) {
1031   assert(Req.CI && "Got preamble request with null compiler invocation");
1032   const ParseInputs &Inputs = Req.Inputs;
1033   bool ReusedPreamble = false;
1034 
1035   Status.update([&](TUStatus &Status) {
1036     Status.PreambleActivity = PreambleAction::Building;
1037   });
1038   auto _ = llvm::make_scope_exit([this, &Req, &ReusedPreamble] {
1039     ASTPeer.updatePreamble(std::move(Req.CI), std::move(Req.Inputs),
1040                            LatestBuild, std::move(Req.CIDiags),
1041                            std::move(Req.WantDiags));
1042     if (!ReusedPreamble)
1043       Callbacks.onPreamblePublished(FileName);
1044   });
1045 
1046   if (!LatestBuild || Inputs.ForceRebuild) {
1047     vlog("Building first preamble for {0} version {1}", FileName,
1048          Inputs.Version);
1049   } else if (isPreambleCompatible(*LatestBuild, Inputs, FileName, *Req.CI)) {
1050     vlog("Reusing preamble version {0} for version {1} of {2}",
1051          LatestBuild->Version, Inputs.Version, FileName);
1052     ReusedPreamble = true;
1053     return;
1054   } else {
1055     vlog("Rebuilding invalidated preamble for {0} version {1} (previous was "
1056          "version {2})",
1057          FileName, Inputs.Version, LatestBuild->Version);
1058   }
1059 
1060   ThreadCrashReporter ScopedReporter([&Inputs]() {
1061     llvm::errs() << "Signalled while building preamble\n";
1062     crashDumpParseInputs(llvm::errs(), Inputs);
1063   });
1064 
1065   PreambleBuildStats Stats;
1066   bool IsFirstPreamble = !LatestBuild;
1067   LatestBuild = clang::clangd::buildPreamble(
1068       FileName, *Req.CI, Inputs, StoreInMemory,
1069       [&](ASTContext &Ctx, Preprocessor &PP,
1070           const CanonicalIncludes &CanonIncludes) {
1071         Callbacks.onPreambleAST(FileName, Inputs.Version, *Req.CI, Ctx, PP,
1072                                 CanonIncludes);
1073       },
1074       &Stats);
1075   if (!LatestBuild)
1076     return;
1077   reportPreambleBuild(Stats, IsFirstPreamble);
1078   if (isReliable(LatestBuild->CompileCommand))
1079     HeaderIncluders.update(FileName, LatestBuild->Includes.allHeaders());
1080 }
1081 
updatePreamble(std::unique_ptr<CompilerInvocation> CI,ParseInputs PI,std::shared_ptr<const PreambleData> Preamble,std::vector<Diag> CIDiags,WantDiagnostics WantDiags)1082 void ASTWorker::updatePreamble(std::unique_ptr<CompilerInvocation> CI,
1083                                ParseInputs PI,
1084                                std::shared_ptr<const PreambleData> Preamble,
1085                                std::vector<Diag> CIDiags,
1086                                WantDiagnostics WantDiags) {
1087   llvm::StringLiteral TaskName = "Build AST";
1088   // Store preamble and build diagnostics with new preamble if requested.
1089   auto Task = [this, Preamble = std::move(Preamble), CI = std::move(CI),
1090                PI = std::move(PI), CIDiags = std::move(CIDiags),
1091                WantDiags = std::move(WantDiags)]() mutable {
1092     // Update the preamble inside ASTWorker queue to ensure atomicity. As a task
1093     // running inside ASTWorker assumes internals won't change until it
1094     // finishes.
1095     if (!LatestPreamble || Preamble != *LatestPreamble) {
1096       ++PreambleBuildCount;
1097       // Cached AST is no longer valid.
1098       IdleASTs.take(this);
1099       RanASTCallback = false;
1100       std::lock_guard<std::mutex> Lock(Mutex);
1101       // LatestPreamble might be the last reference to old preamble, do not
1102       // trigger destructor while holding the lock.
1103       if (LatestPreamble)
1104         std::swap(*LatestPreamble, Preamble);
1105       else
1106         LatestPreamble = std::move(Preamble);
1107     }
1108     // Notify anyone waiting for a preamble.
1109     PreambleCV.notify_all();
1110     // Give up our ownership to old preamble before starting expensive AST
1111     // build.
1112     Preamble.reset();
1113     // We only need to build the AST if diagnostics were requested.
1114     if (WantDiags == WantDiagnostics::No)
1115       return;
1116     // Report diagnostics with the new preamble to ensure progress. Otherwise
1117     // diagnostics might get stale indefinitely if user keeps invalidating the
1118     // preamble.
1119     generateDiagnostics(std::move(CI), std::move(PI), std::move(CIDiags));
1120   };
1121   if (RunSync) {
1122     runTask(TaskName, Task);
1123     return;
1124   }
1125   {
1126     std::lock_guard<std::mutex> Lock(Mutex);
1127     PreambleRequests.push_back({std::move(Task), std::string(TaskName),
1128                                 steady_clock::now(), Context::current().clone(),
1129                                 llvm::None, llvm::None,
1130                                 TUScheduler::NoInvalidation, nullptr});
1131   }
1132   PreambleCV.notify_all();
1133   RequestsCV.notify_all();
1134 }
1135 
updateASTSignals(ParsedAST & AST)1136 void ASTWorker::updateASTSignals(ParsedAST &AST) {
1137   auto Signals = std::make_shared<const ASTSignals>(ASTSignals::derive(AST));
1138   // Existing readers of ASTSignals will have their copy preserved until the
1139   // read is completed. The last reader deletes the old ASTSignals.
1140   {
1141     std::lock_guard<std::mutex> Lock(Mutex);
1142     std::swap(LatestASTSignals, Signals);
1143   }
1144 }
1145 
generateDiagnostics(std::unique_ptr<CompilerInvocation> Invocation,ParseInputs Inputs,std::vector<Diag> CIDiags)1146 void ASTWorker::generateDiagnostics(
1147     std::unique_ptr<CompilerInvocation> Invocation, ParseInputs Inputs,
1148     std::vector<Diag> CIDiags) {
1149   // Tracks ast cache accesses for publishing diags.
1150   static constexpr trace::Metric ASTAccessForDiag(
1151       "ast_access_diag", trace::Metric::Counter, "result");
1152   assert(Invocation);
1153   assert(LatestPreamble);
1154   // No need to rebuild the AST if we won't send the diagnostics.
1155   {
1156     std::lock_guard<std::mutex> Lock(PublishMu);
1157     if (!CanPublishResults)
1158       return;
1159   }
1160   // Used to check whether we can update AST cache.
1161   bool InputsAreLatest =
1162       std::tie(FileInputs.CompileCommand, FileInputs.Contents) ==
1163       std::tie(Inputs.CompileCommand, Inputs.Contents);
1164   // Take a shortcut and don't report the diagnostics, since they should be the
1165   // same. All the clients should handle the lack of OnUpdated() call anyway to
1166   // handle empty result from buildAST.
1167   // FIXME: the AST could actually change if non-preamble includes changed,
1168   // but we choose to ignore it.
1169   if (InputsAreLatest && RanASTCallback)
1170     return;
1171 
1172   // Get the AST for diagnostics, either build it or use the cached one.
1173   std::string TaskName = llvm::formatv("Build AST ({0})", Inputs.Version);
1174   Status.update([&](TUStatus &Status) {
1175     Status.ASTActivity.K = ASTAction::Building;
1176     Status.ASTActivity.Name = std::move(TaskName);
1177   });
1178   // We might be able to reuse the last we've built for a read request.
1179   // FIXME: It might be better to not reuse this AST. That way queued AST builds
1180   // won't be required for diags.
1181   llvm::Optional<std::unique_ptr<ParsedAST>> AST =
1182       IdleASTs.take(this, &ASTAccessForDiag);
1183   if (!AST || !InputsAreLatest) {
1184     auto RebuildStartTime = DebouncePolicy::clock::now();
1185     llvm::Optional<ParsedAST> NewAST = ParsedAST::build(
1186         FileName, Inputs, std::move(Invocation), CIDiags, *LatestPreamble);
1187     auto RebuildDuration = DebouncePolicy::clock::now() - RebuildStartTime;
1188     ++ASTBuildCount;
1189     // Try to record the AST-build time, to inform future update debouncing.
1190     // This is best-effort only: if the lock is held, don't bother.
1191     std::unique_lock<std::mutex> Lock(Mutex, std::try_to_lock);
1192     if (Lock.owns_lock()) {
1193       // Do not let RebuildTimes grow beyond its small-size (i.e.
1194       // capacity).
1195       if (RebuildTimes.size() == RebuildTimes.capacity())
1196         RebuildTimes.erase(RebuildTimes.begin());
1197       RebuildTimes.push_back(RebuildDuration);
1198       Lock.unlock();
1199     }
1200     Status.update([&](TUStatus &Status) {
1201       Status.Details.ReuseAST = false;
1202       Status.Details.BuildFailed = !NewAST;
1203     });
1204     AST = NewAST ? std::make_unique<ParsedAST>(std::move(*NewAST)) : nullptr;
1205   } else {
1206     log("Skipping rebuild of the AST for {0}, inputs are the same.", FileName);
1207     Status.update([](TUStatus &Status) {
1208       Status.Details.ReuseAST = true;
1209       Status.Details.BuildFailed = false;
1210     });
1211   }
1212 
1213   // Publish diagnostics.
1214   auto RunPublish = [&](llvm::function_ref<void()> Publish) {
1215     // Ensure we only publish results from the worker if the file was not
1216     // removed, making sure there are not race conditions.
1217     std::lock_guard<std::mutex> Lock(PublishMu);
1218     if (CanPublishResults)
1219       Publish();
1220   };
1221   if (*AST) {
1222     trace::Span Span("Running main AST callback");
1223     Callbacks.onMainAST(FileName, **AST, RunPublish);
1224     updateASTSignals(**AST);
1225   } else {
1226     // Failed to build the AST, at least report diagnostics from the
1227     // command line if there were any.
1228     // FIXME: we might have got more errors while trying to build the
1229     // AST, surface them too.
1230     Callbacks.onFailedAST(FileName, Inputs.Version, CIDiags, RunPublish);
1231   }
1232 
1233   // AST might've been built for an older version of the source, as ASTWorker
1234   // queue raced ahead while we were waiting on the preamble. In that case the
1235   // queue can't reuse the AST.
1236   if (InputsAreLatest) {
1237     RanASTCallback = *AST != nullptr;
1238     IdleASTs.put(this, std::move(*AST));
1239   }
1240 }
1241 
getPossiblyStalePreamble(std::shared_ptr<const ASTSignals> * ASTSignals) const1242 std::shared_ptr<const PreambleData> ASTWorker::getPossiblyStalePreamble(
1243     std::shared_ptr<const ASTSignals> *ASTSignals) const {
1244   std::lock_guard<std::mutex> Lock(Mutex);
1245   if (ASTSignals)
1246     *ASTSignals = LatestASTSignals;
1247   return LatestPreamble ? *LatestPreamble : nullptr;
1248 }
1249 
waitForFirstPreamble() const1250 void ASTWorker::waitForFirstPreamble() const {
1251   std::unique_lock<std::mutex> Lock(Mutex);
1252   PreambleCV.wait(Lock, [this] { return LatestPreamble || Done; });
1253 }
1254 
getCurrentCompileCommand() const1255 tooling::CompileCommand ASTWorker::getCurrentCompileCommand() const {
1256   std::unique_lock<std::mutex> Lock(Mutex);
1257   return FileInputs.CompileCommand;
1258 }
1259 
stats() const1260 TUScheduler::FileStats ASTWorker::stats() const {
1261   TUScheduler::FileStats Result;
1262   Result.ASTBuilds = ASTBuildCount;
1263   Result.PreambleBuilds = PreambleBuildCount;
1264   // Note that we don't report the size of ASTs currently used for processing
1265   // the in-flight requests. We used this information for debugging purposes
1266   // only, so this should be fine.
1267   Result.UsedBytesAST = IdleASTs.getUsedBytes(this);
1268   if (auto Preamble = getPossiblyStalePreamble())
1269     Result.UsedBytesPreamble = Preamble->Preamble.getSize();
1270   return Result;
1271 }
1272 
isASTCached() const1273 bool ASTWorker::isASTCached() const { return IdleASTs.getUsedBytes(this) != 0; }
1274 
stop()1275 void ASTWorker::stop() {
1276   {
1277     std::lock_guard<std::mutex> Lock(PublishMu);
1278     CanPublishResults = false;
1279   }
1280   {
1281     std::lock_guard<std::mutex> Lock(Mutex);
1282     assert(!Done && "stop() called twice");
1283     Done = true;
1284   }
1285   PreamblePeer.stop();
1286   // We are no longer going to build any preambles, let the waiters know that.
1287   PreambleCV.notify_all();
1288   Status.stop();
1289   RequestsCV.notify_all();
1290 }
1291 
runTask(llvm::StringRef Name,llvm::function_ref<void ()> Task)1292 void ASTWorker::runTask(llvm::StringRef Name, llvm::function_ref<void()> Task) {
1293   ThreadCrashReporter ScopedReporter([this, Name]() {
1294     llvm::errs() << "Signalled during AST worker action: " << Name << "\n";
1295     crashDumpParseInputs(llvm::errs(), FileInputs);
1296   });
1297   trace::Span Tracer(Name);
1298   WithContext WithProvidedContext(ContextProvider(FileName));
1299   Task();
1300 }
1301 
startTask(llvm::StringRef Name,llvm::unique_function<void ()> Task,llvm::Optional<UpdateType> Update,TUScheduler::ASTActionInvalidation Invalidation)1302 void ASTWorker::startTask(llvm::StringRef Name,
1303                           llvm::unique_function<void()> Task,
1304                           llvm::Optional<UpdateType> Update,
1305                           TUScheduler::ASTActionInvalidation Invalidation) {
1306   if (RunSync) {
1307     assert(!Done && "running a task after stop()");
1308     runTask(Name, Task);
1309     return;
1310   }
1311 
1312   {
1313     std::lock_guard<std::mutex> Lock(Mutex);
1314     assert(!Done && "running a task after stop()");
1315     // Cancel any requests invalidated by this request.
1316     if (Update && Update->ContentChanged) {
1317       for (auto &R : llvm::reverse(Requests)) {
1318         if (R.InvalidationPolicy == TUScheduler::InvalidateOnUpdate)
1319           R.Invalidate();
1320         if (R.Update && R.Update->ContentChanged)
1321           break; // Older requests were already invalidated by the older update.
1322       }
1323     }
1324 
1325     // Allow this request to be cancelled if invalidated.
1326     Context Ctx = Context::current().derive(FileBeingProcessed, FileName);
1327     Canceler Invalidate = nullptr;
1328     if (Invalidation) {
1329       WithContext WC(std::move(Ctx));
1330       std::tie(Ctx, Invalidate) = cancelableTask(
1331           /*Reason=*/static_cast<int>(ErrorCode::ContentModified));
1332     }
1333     // Trace the time the request spends in the queue, and the requests that
1334     // it's going to wait for.
1335     llvm::Optional<Context> QueueCtx;
1336     if (trace::enabled()) {
1337       // Tracers that follow threads and need strict nesting will see a tiny
1338       // instantaneous event "we're enqueueing", and sometime later it runs.
1339       WithContext WC(Ctx.clone());
1340       trace::Span Tracer("Queued:" + Name);
1341       if (Tracer.Args) {
1342         if (CurrentRequest)
1343           SPAN_ATTACH(Tracer, "CurrentRequest", CurrentRequest->Name);
1344         llvm::json::Array PreambleRequestsNames;
1345         for (const auto &Req : PreambleRequests)
1346           PreambleRequestsNames.push_back(Req.Name);
1347         SPAN_ATTACH(Tracer, "PreambleRequestsNames",
1348                     std::move(PreambleRequestsNames));
1349         llvm::json::Array RequestsNames;
1350         for (const auto &Req : Requests)
1351           RequestsNames.push_back(Req.Name);
1352         SPAN_ATTACH(Tracer, "RequestsNames", std::move(RequestsNames));
1353       }
1354       // For tracers that follow contexts, keep the trace span's context alive
1355       // until we dequeue the request, so they see the full duration.
1356       QueueCtx = Context::current().clone();
1357     }
1358     Requests.push_back({std::move(Task), std::string(Name), steady_clock::now(),
1359                         std::move(Ctx), std::move(QueueCtx), Update,
1360                         Invalidation, std::move(Invalidate)});
1361   }
1362   RequestsCV.notify_all();
1363 }
1364 
run()1365 void ASTWorker::run() {
1366   while (true) {
1367     {
1368       std::unique_lock<std::mutex> Lock(Mutex);
1369       assert(!CurrentRequest && "A task is already running, multiple workers?");
1370       for (auto Wait = scheduleLocked(); !Wait.expired();
1371            Wait = scheduleLocked()) {
1372         assert(PreambleRequests.empty() &&
1373                "Preamble updates should be scheduled immediately");
1374         if (Done) {
1375           if (Requests.empty())
1376             return;
1377           // Even though Done is set, finish pending requests.
1378           break; // However, skip delays to shutdown fast.
1379         }
1380 
1381         // Tracing: we have a next request, attribute this sleep to it.
1382         llvm::Optional<WithContext> Ctx;
1383         llvm::Optional<trace::Span> Tracer;
1384         if (!Requests.empty()) {
1385           Ctx.emplace(Requests.front().Ctx.clone());
1386           Tracer.emplace("Debounce");
1387           SPAN_ATTACH(*Tracer, "next_request", Requests.front().Name);
1388           if (!(Wait == Deadline::infinity())) {
1389             Status.update([&](TUStatus &Status) {
1390               Status.ASTActivity.K = ASTAction::Queued;
1391               Status.ASTActivity.Name = Requests.front().Name;
1392             });
1393             SPAN_ATTACH(*Tracer, "sleep_ms",
1394                         std::chrono::duration_cast<std::chrono::milliseconds>(
1395                             Wait.time() - steady_clock::now())
1396                             .count());
1397           }
1398         }
1399 
1400         wait(Lock, RequestsCV, Wait);
1401       }
1402       // Any request in ReceivedPreambles is at least as old as the
1403       // Requests.front(), so prefer them first to preserve LSP order.
1404       if (!PreambleRequests.empty()) {
1405         CurrentRequest = std::move(PreambleRequests.front());
1406         PreambleRequests.pop_front();
1407       } else {
1408         CurrentRequest = std::move(Requests.front());
1409         Requests.pop_front();
1410       }
1411     } // unlock Mutex
1412 
1413     // Inform tracing that the request was dequeued.
1414     CurrentRequest->QueueCtx.reset();
1415 
1416     // It is safe to perform reads to CurrentRequest without holding the lock as
1417     // only writer is also this thread.
1418     {
1419       std::unique_lock<Semaphore> Lock(Barrier, std::try_to_lock);
1420       if (!Lock.owns_lock()) {
1421         Status.update([&](TUStatus &Status) {
1422           Status.ASTActivity.K = ASTAction::Queued;
1423           Status.ASTActivity.Name = CurrentRequest->Name;
1424         });
1425         Lock.lock();
1426       }
1427       WithContext Guard(std::move(CurrentRequest->Ctx));
1428       Status.update([&](TUStatus &Status) {
1429         Status.ASTActivity.K = ASTAction::RunningAction;
1430         Status.ASTActivity.Name = CurrentRequest->Name;
1431       });
1432       runTask(CurrentRequest->Name, CurrentRequest->Action);
1433     }
1434 
1435     bool IsEmpty = false;
1436     {
1437       std::lock_guard<std::mutex> Lock(Mutex);
1438       CurrentRequest.reset();
1439       IsEmpty = Requests.empty() && PreambleRequests.empty();
1440     }
1441     if (IsEmpty) {
1442       Status.update([&](TUStatus &Status) {
1443         Status.ASTActivity.K = ASTAction::Idle;
1444         Status.ASTActivity.Name = "";
1445       });
1446     }
1447     RequestsCV.notify_all();
1448   }
1449 }
1450 
scheduleLocked()1451 Deadline ASTWorker::scheduleLocked() {
1452   // Process new preambles immediately.
1453   if (!PreambleRequests.empty())
1454     return Deadline::zero();
1455   if (Requests.empty())
1456     return Deadline::infinity(); // Wait for new requests.
1457   // Handle cancelled requests first so the rest of the scheduler doesn't.
1458   for (auto I = Requests.begin(), E = Requests.end(); I != E; ++I) {
1459     if (!isCancelled(I->Ctx)) {
1460       // Cancellations after the first read don't affect current scheduling.
1461       if (I->Update == None)
1462         break;
1463       continue;
1464     }
1465     // Cancelled reads are moved to the front of the queue and run immediately.
1466     if (I->Update == None) {
1467       Request R = std::move(*I);
1468       Requests.erase(I);
1469       Requests.push_front(std::move(R));
1470       return Deadline::zero();
1471     }
1472     // Cancelled updates are downgraded to auto-diagnostics, and may be elided.
1473     if (I->Update->Diagnostics == WantDiagnostics::Yes)
1474       I->Update->Diagnostics = WantDiagnostics::Auto;
1475   }
1476 
1477   while (shouldSkipHeadLocked()) {
1478     vlog("ASTWorker skipping {0} for {1}", Requests.front().Name, FileName);
1479     Requests.pop_front();
1480   }
1481   assert(!Requests.empty() && "skipped the whole queue");
1482   // Some updates aren't dead yet, but never end up being used.
1483   // e.g. the first keystroke is live until obsoleted by the second.
1484   // We debounce "maybe-unused" writes, sleeping in case they become dead.
1485   // But don't delay reads (including updates where diagnostics are needed).
1486   for (const auto &R : Requests)
1487     if (R.Update == None || R.Update->Diagnostics == WantDiagnostics::Yes)
1488       return Deadline::zero();
1489   // Front request needs to be debounced, so determine when we're ready.
1490   Deadline D(Requests.front().AddTime + UpdateDebounce.compute(RebuildTimes));
1491   return D;
1492 }
1493 
1494 // Returns true if Requests.front() is a dead update that can be skipped.
shouldSkipHeadLocked() const1495 bool ASTWorker::shouldSkipHeadLocked() const {
1496   assert(!Requests.empty());
1497   auto Next = Requests.begin();
1498   auto Update = Next->Update;
1499   if (!Update) // Only skip updates.
1500     return false;
1501   ++Next;
1502   // An update is live if its AST might still be read.
1503   // That is, if it's not immediately followed by another update.
1504   if (Next == Requests.end() || !Next->Update)
1505     return false;
1506   // The other way an update can be live is if its diagnostics might be used.
1507   switch (Update->Diagnostics) {
1508   case WantDiagnostics::Yes:
1509     return false; // Always used.
1510   case WantDiagnostics::No:
1511     return true; // Always dead.
1512   case WantDiagnostics::Auto:
1513     // Used unless followed by an update that generates diagnostics.
1514     for (; Next != Requests.end(); ++Next)
1515       if (Next->Update && Next->Update->Diagnostics != WantDiagnostics::No)
1516         return true; // Prefer later diagnostics.
1517     return false;
1518   }
1519   llvm_unreachable("Unknown WantDiagnostics");
1520 }
1521 
blockUntilIdle(Deadline Timeout) const1522 bool ASTWorker::blockUntilIdle(Deadline Timeout) const {
1523   auto WaitUntilASTWorkerIsIdle = [&] {
1524     std::unique_lock<std::mutex> Lock(Mutex);
1525     return wait(Lock, RequestsCV, Timeout, [&] {
1526       return PreambleRequests.empty() && Requests.empty() && !CurrentRequest;
1527     });
1528   };
1529   // Make sure ASTWorker has processed all requests, which might issue new
1530   // updates to PreamblePeer.
1531   if (!WaitUntilASTWorkerIsIdle())
1532     return false;
1533   // Now that ASTWorker processed all requests, ensure PreamblePeer has served
1534   // all update requests. This might create new PreambleRequests for the
1535   // ASTWorker.
1536   if (!PreamblePeer.blockUntilIdle(Timeout))
1537     return false;
1538   assert(Requests.empty() &&
1539          "No new normal tasks can be scheduled concurrently with "
1540          "blockUntilIdle(): ASTWorker isn't threadsafe");
1541   // Finally make sure ASTWorker has processed all of the preamble updates.
1542   return WaitUntilASTWorkerIsIdle();
1543 }
1544 
1545 // Render a TUAction to a user-facing string representation.
1546 // TUAction represents clangd-internal states, we don't intend to expose them
1547 // to users (say C++ programmers) directly to avoid confusion, we use terms that
1548 // are familiar by C++ programmers.
renderTUAction(const PreambleAction PA,const ASTAction & AA)1549 std::string renderTUAction(const PreambleAction PA, const ASTAction &AA) {
1550   llvm::SmallVector<std::string, 2> Result;
1551   switch (PA) {
1552   case PreambleAction::Building:
1553     Result.push_back("parsing includes");
1554     break;
1555   case PreambleAction::Queued:
1556     Result.push_back("includes are queued");
1557     break;
1558   case PreambleAction::Idle:
1559     // We handle idle specially below.
1560     break;
1561   }
1562   switch (AA.K) {
1563   case ASTAction::Queued:
1564     Result.push_back("file is queued");
1565     break;
1566   case ASTAction::RunningAction:
1567     Result.push_back("running " + AA.Name);
1568     break;
1569   case ASTAction::Building:
1570     Result.push_back("parsing main file");
1571     break;
1572   case ASTAction::Idle:
1573     // We handle idle specially below.
1574     break;
1575   }
1576   if (Result.empty())
1577     return "idle";
1578   return llvm::join(Result, ", ");
1579 }
1580 
1581 } // namespace
1582 
getDefaultAsyncThreadsCount()1583 unsigned getDefaultAsyncThreadsCount() {
1584   return llvm::heavyweight_hardware_concurrency().compute_thread_count();
1585 }
1586 
render(PathRef File) const1587 FileStatus TUStatus::render(PathRef File) const {
1588   FileStatus FStatus;
1589   FStatus.uri = URIForFile::canonicalize(File, /*TUPath=*/File);
1590   FStatus.state = renderTUAction(PreambleActivity, ASTActivity);
1591   return FStatus;
1592 }
1593 
1594 struct TUScheduler::FileData {
1595   /// Latest inputs, passed to TUScheduler::update().
1596   std::string Contents;
1597   ASTWorkerHandle Worker;
1598 };
1599 
TUScheduler(const GlobalCompilationDatabase & CDB,const Options & Opts,std::unique_ptr<ParsingCallbacks> Callbacks)1600 TUScheduler::TUScheduler(const GlobalCompilationDatabase &CDB,
1601                          const Options &Opts,
1602                          std::unique_ptr<ParsingCallbacks> Callbacks)
1603     : CDB(CDB), Opts(Opts),
1604       Callbacks(Callbacks ? std::move(Callbacks)
1605                           : std::make_unique<ParsingCallbacks>()),
1606       Barrier(Opts.AsyncThreadsCount), QuickRunBarrier(Opts.AsyncThreadsCount),
1607       IdleASTs(
1608           std::make_unique<ASTCache>(Opts.RetentionPolicy.MaxRetainedASTs)),
1609       HeaderIncluders(std::make_unique<HeaderIncluderCache>()) {
1610   // Avoid null checks everywhere.
1611   if (!Opts.ContextProvider) {
1612     this->Opts.ContextProvider = [](llvm::StringRef) {
1613       return Context::current().clone();
1614     };
1615   }
1616   if (0 < Opts.AsyncThreadsCount) {
1617     PreambleTasks.emplace();
1618     WorkerThreads.emplace();
1619   }
1620 }
1621 
~TUScheduler()1622 TUScheduler::~TUScheduler() {
1623   // Notify all workers that they need to stop.
1624   Files.clear();
1625 
1626   // Wait for all in-flight tasks to finish.
1627   if (PreambleTasks)
1628     PreambleTasks->wait();
1629   if (WorkerThreads)
1630     WorkerThreads->wait();
1631 }
1632 
blockUntilIdle(Deadline D) const1633 bool TUScheduler::blockUntilIdle(Deadline D) const {
1634   for (auto &File : Files)
1635     if (!File.getValue()->Worker->blockUntilIdle(D))
1636       return false;
1637   if (PreambleTasks)
1638     if (!PreambleTasks->wait(D))
1639       return false;
1640   return true;
1641 }
1642 
update(PathRef File,ParseInputs Inputs,WantDiagnostics WantDiags)1643 bool TUScheduler::update(PathRef File, ParseInputs Inputs,
1644                          WantDiagnostics WantDiags) {
1645   std::unique_ptr<FileData> &FD = Files[File];
1646   bool NewFile = FD == nullptr;
1647   bool ContentChanged = false;
1648   if (!FD) {
1649     // Create a new worker to process the AST-related tasks.
1650     ASTWorkerHandle Worker =
1651         ASTWorker::create(File, CDB, *IdleASTs, *HeaderIncluders,
1652                           WorkerThreads ? WorkerThreads.getPointer() : nullptr,
1653                           Barrier, Opts, *Callbacks);
1654     FD = std::unique_ptr<FileData>(
1655         new FileData{Inputs.Contents, std::move(Worker)});
1656     ContentChanged = true;
1657   } else if (FD->Contents != Inputs.Contents) {
1658     ContentChanged = true;
1659     FD->Contents = Inputs.Contents;
1660   }
1661   FD->Worker->update(std::move(Inputs), WantDiags, ContentChanged);
1662   // There might be synthetic update requests, don't change the LastActiveFile
1663   // in such cases.
1664   if (ContentChanged)
1665     LastActiveFile = File.str();
1666   return NewFile;
1667 }
1668 
remove(PathRef File)1669 void TUScheduler::remove(PathRef File) {
1670   bool Removed = Files.erase(File);
1671   if (!Removed)
1672     elog("Trying to remove file from TUScheduler that is not tracked: {0}",
1673          File);
1674   // We don't call HeaderIncluders.remove(File) here.
1675   // If we did, we'd avoid potentially stale header/mainfile associations.
1676   // However, it would mean that closing a mainfile could invalidate the
1677   // preamble of several open headers.
1678 }
1679 
run(llvm::StringRef Name,llvm::StringRef Path,llvm::unique_function<void ()> Action)1680 void TUScheduler::run(llvm::StringRef Name, llvm::StringRef Path,
1681                       llvm::unique_function<void()> Action) {
1682   runWithSemaphore(Name, Path, std::move(Action), Barrier);
1683 }
1684 
runQuick(llvm::StringRef Name,llvm::StringRef Path,llvm::unique_function<void ()> Action)1685 void TUScheduler::runQuick(llvm::StringRef Name, llvm::StringRef Path,
1686                            llvm::unique_function<void()> Action) {
1687   // Use QuickRunBarrier to serialize quick tasks: we are ignoring
1688   // the parallelism level set by the user, don't abuse it
1689   runWithSemaphore(Name, Path, std::move(Action), QuickRunBarrier);
1690 }
1691 
runWithSemaphore(llvm::StringRef Name,llvm::StringRef Path,llvm::unique_function<void ()> Action,Semaphore & Sem)1692 void TUScheduler::runWithSemaphore(llvm::StringRef Name, llvm::StringRef Path,
1693                                    llvm::unique_function<void()> Action,
1694                                    Semaphore &Sem) {
1695   if (Path.empty())
1696     Path = LastActiveFile;
1697   else
1698     LastActiveFile = Path.str();
1699   if (!PreambleTasks) {
1700     WithContext WithProvidedContext(Opts.ContextProvider(Path));
1701     return Action();
1702   }
1703   PreambleTasks->runAsync(Name, [this, &Sem, Ctx = Context::current().clone(),
1704                                  Path(Path.str()),
1705                                  Action = std::move(Action)]() mutable {
1706     std::lock_guard<Semaphore> BarrierLock(Sem);
1707     WithContext WC(std::move(Ctx));
1708     WithContext WithProvidedContext(Opts.ContextProvider(Path));
1709     Action();
1710   });
1711 }
1712 
runWithAST(llvm::StringRef Name,PathRef File,llvm::unique_function<void (llvm::Expected<InputsAndAST>)> Action,TUScheduler::ASTActionInvalidation Invalidation)1713 void TUScheduler::runWithAST(
1714     llvm::StringRef Name, PathRef File,
1715     llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action,
1716     TUScheduler::ASTActionInvalidation Invalidation) {
1717   auto It = Files.find(File);
1718   if (It == Files.end()) {
1719     Action(llvm::make_error<LSPError>(
1720         "trying to get AST for non-added document", ErrorCode::InvalidParams));
1721     return;
1722   }
1723   LastActiveFile = File.str();
1724 
1725   It->second->Worker->runWithAST(Name, std::move(Action), Invalidation);
1726 }
1727 
runWithPreamble(llvm::StringRef Name,PathRef File,PreambleConsistency Consistency,Callback<InputsAndPreamble> Action)1728 void TUScheduler::runWithPreamble(llvm::StringRef Name, PathRef File,
1729                                   PreambleConsistency Consistency,
1730                                   Callback<InputsAndPreamble> Action) {
1731   auto It = Files.find(File);
1732   if (It == Files.end()) {
1733     Action(llvm::make_error<LSPError>(
1734         "trying to get preamble for non-added document",
1735         ErrorCode::InvalidParams));
1736     return;
1737   }
1738   LastActiveFile = File.str();
1739 
1740   if (!PreambleTasks) {
1741     trace::Span Tracer(Name);
1742     SPAN_ATTACH(Tracer, "file", File);
1743     std::shared_ptr<const ASTSignals> Signals;
1744     std::shared_ptr<const PreambleData> Preamble =
1745         It->second->Worker->getPossiblyStalePreamble(&Signals);
1746     WithContext WithProvidedContext(Opts.ContextProvider(File));
1747     Action(InputsAndPreamble{It->second->Contents,
1748                              It->second->Worker->getCurrentCompileCommand(),
1749                              Preamble.get(), Signals.get()});
1750     return;
1751   }
1752 
1753   std::shared_ptr<const ASTWorker> Worker = It->second->Worker.lock();
1754   auto Task = [Worker, Consistency, Name = Name.str(), File = File.str(),
1755                Contents = It->second->Contents,
1756                Command = Worker->getCurrentCompileCommand(),
1757                Ctx = Context::current().derive(FileBeingProcessed,
1758                                                std::string(File)),
1759                Action = std::move(Action), this]() mutable {
1760     ThreadCrashReporter ScopedReporter([&Name, &Contents, &Command]() {
1761       llvm::errs() << "Signalled during preamble action: " << Name << "\n";
1762       crashDumpCompileCommand(llvm::errs(), Command);
1763       crashDumpFileContents(llvm::errs(), Contents);
1764     });
1765     std::shared_ptr<const PreambleData> Preamble;
1766     if (Consistency == PreambleConsistency::Stale) {
1767       // Wait until the preamble is built for the first time, if preamble
1768       // is required. This avoids extra work of processing the preamble
1769       // headers in parallel multiple times.
1770       Worker->waitForFirstPreamble();
1771     }
1772     std::shared_ptr<const ASTSignals> Signals;
1773     Preamble = Worker->getPossiblyStalePreamble(&Signals);
1774 
1775     std::lock_guard<Semaphore> BarrierLock(Barrier);
1776     WithContext Guard(std::move(Ctx));
1777     trace::Span Tracer(Name);
1778     SPAN_ATTACH(Tracer, "file", File);
1779     WithContext WithProvidedContext(Opts.ContextProvider(File));
1780     Action(InputsAndPreamble{Contents, Command, Preamble.get(), Signals.get()});
1781   };
1782 
1783   PreambleTasks->runAsync("task:" + llvm::sys::path::filename(File),
1784                           std::move(Task));
1785 }
1786 
fileStats() const1787 llvm::StringMap<TUScheduler::FileStats> TUScheduler::fileStats() const {
1788   llvm::StringMap<TUScheduler::FileStats> Result;
1789   for (const auto &PathAndFile : Files)
1790     Result.try_emplace(PathAndFile.first(),
1791                        PathAndFile.second->Worker->stats());
1792   return Result;
1793 }
1794 
getFilesWithCachedAST() const1795 std::vector<Path> TUScheduler::getFilesWithCachedAST() const {
1796   std::vector<Path> Result;
1797   for (auto &&PathAndFile : Files) {
1798     if (!PathAndFile.second->Worker->isASTCached())
1799       continue;
1800     Result.push_back(std::string(PathAndFile.first()));
1801   }
1802   return Result;
1803 }
1804 
1805 DebouncePolicy::clock::duration
compute(llvm::ArrayRef<clock::duration> History) const1806 DebouncePolicy::compute(llvm::ArrayRef<clock::duration> History) const {
1807   assert(Min <= Max && "Invalid policy");
1808   if (History.empty())
1809     return Max; // Arbitrary.
1810 
1811   // Base the result on the median rebuild.
1812   // nth_element needs a mutable array, take the chance to bound the data size.
1813   History = History.take_back(15);
1814   llvm::SmallVector<clock::duration, 15> Recent(History.begin(), History.end());
1815   auto *Median = Recent.begin() + Recent.size() / 2;
1816   std::nth_element(Recent.begin(), Median, Recent.end());
1817 
1818   clock::duration Target =
1819       std::chrono::duration_cast<clock::duration>(RebuildRatio * *Median);
1820   if (Target > Max)
1821     return Max;
1822   if (Target < Min)
1823     return Min;
1824   return Target;
1825 }
1826 
fixed(clock::duration T)1827 DebouncePolicy DebouncePolicy::fixed(clock::duration T) {
1828   DebouncePolicy P;
1829   P.Min = P.Max = T;
1830   return P;
1831 }
1832 
profile(MemoryTree & MT) const1833 void TUScheduler::profile(MemoryTree &MT) const {
1834   for (const auto &Elem : fileStats()) {
1835     MT.detail(Elem.first())
1836         .child("preamble")
1837         .addUsage(Opts.StorePreamblesInMemory ? Elem.second.UsedBytesPreamble
1838                                               : 0);
1839     MT.detail(Elem.first()).child("ast").addUsage(Elem.second.UsedBytesAST);
1840     MT.child("header_includer_cache").addUsage(HeaderIncluders->getUsedBytes());
1841   }
1842 }
1843 } // namespace clangd
1844 } // namespace clang
1845