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