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