clang-tools 10.0.0

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 // For each file, managed by TUScheduler, we create a single ASTWorker that
9 // manages an AST for that file. All operations that modify or read the AST are
10 // run on a separate dedicated thread asynchronously in FIFO order.
11 //
12 // We start processing each update immediately after we receive it. If two or
13 // more updates come subsequently without reads in-between, we attempt to drop
14 // an older one to not waste time building the ASTs we don't need.
15 //
16 // The processing thread of the ASTWorker is also responsible for building the
17 // preamble. However, unlike AST, the same preamble can be read concurrently, so
18 // we run each of async preamble reads on its own thread.
19 //
20 // To limit the concurrent load that clangd produces we maintain a semaphore
21 // that keeps more than a fixed number of threads from running concurrently.
22 //
23 // Rationale for cancelling updates.
24 // LSP clients can send updates to clangd on each keystroke. Some files take
25 // significant time to parse (e.g. a few seconds) and clangd can get starved by
26 // the updates to those files. Therefore we try to process only the last update,
27 // if possible.
28 // Our current strategy to do that is the following:
29 // - For each update we immediately schedule rebuild of the AST.
30 // - Rebuild of the AST checks if it was cancelled before doing any actual work.
31 // If it was, it does not do an actual rebuild, only reports llvm::None to the
32 // callback
33 // - When adding an update, we cancel the last update in the queue if it didn't
34 // have any reads.
35 // There is probably a optimal ways to do that. One approach we might take is
36 // the following:
37 // - For each update we remember the pending inputs, but delay rebuild of the
38 // AST for some timeout.
39 // - If subsequent updates come before rebuild was started, we replace the
40 // pending inputs and reset the timer.
41 // - If any reads of the AST are scheduled, we start building the AST
42 // immediately.
43
44 #include "TUScheduler.h"
45 #include "Cancellation.h"
46 #include "Compiler.h"
47 #include "Context.h"
48 #include "Diagnostics.h"
49 #include "GlobalCompilationDatabase.h"
50 #include "Logger.h"
51 #include "ParsedAST.h"
52 #include "Preamble.h"
53 #include "Trace.h"
54 #include "index/CanonicalIncludes.h"
55 #include "clang/Frontend/CompilerInvocation.h"
56 #include "clang/Tooling/CompilationDatabase.h"
57 #include "llvm/ADT/Optional.h"
58 #include "llvm/ADT/ScopeExit.h"
59 #include "llvm/Support/Errc.h"
60 #include "llvm/Support/Path.h"
61 #include "llvm/Support/Threading.h"
62 #include <algorithm>
63 #include <memory>
64 #include <queue>
65 #include <thread>
66
67 namespace clang {
68 namespace clangd {
69 using std::chrono::steady_clock;
70
71 namespace {
72 class ASTWorker;
73 } // namespace
74
75 static clang::clangd::Key<std::string> kFileBeingProcessed;
76
77 llvm::Optional<llvm::StringRef> TUScheduler::getFileBeingProcessedInContext() {
78 if (auto *File = Context::current().get(kFileBeingProcessed))
79 return llvm::StringRef(*File);
80 return None;
81 }
82
83 /// An LRU cache of idle ASTs.
84 /// Because we want to limit the overall number of these we retain, the cache
85 /// owns ASTs (and may evict them) while their workers are idle.
86 /// Workers borrow ASTs when active, and return them when done.
87 class TUScheduler::ASTCache {
88 public:
89 using Key = const ASTWorker *;
90
91 ASTCache(unsigned MaxRetainedASTs) : MaxRetainedASTs(MaxRetainedASTs) {}
92
93 /// Returns result of getUsedBytes() for the AST cached by \p K.
94 /// If no AST is cached, 0 is returned.
95 std::size_t getUsedBytes(Key K) {
96 std::lock_guard<std::mutex> Lock(Mut);
97 auto It = findByKey(K);
98 if (It == LRU.end() || !It->second)
99 return 0;
100 return It->second->getUsedBytes();
101 }
102
103 /// Store the value in the pool, possibly removing the last used AST.
104 /// The value should not be in the pool when this function is called.
105 void put(Key K, std::unique_ptr<ParsedAST> V) {
106 std::unique_lock<std::mutex> Lock(Mut);
107 assert(findByKey(K) == LRU.end());
108
109 LRU.insert(LRU.begin(), {K, std::move(V)});
110 if (LRU.size() <= MaxRetainedASTs)
111 return;
112 // We're past the limit, remove the last element.
113 std::unique_ptr<ParsedAST> ForCleanup = std::move(LRU.back().second);
114 LRU.pop_back();
115 // Run the expensive destructor outside the lock.
116 Lock.unlock();
117 ForCleanup.reset();
118 }
119
120 /// Returns the cached value for \p K, or llvm::None if the value is not in
121 /// the cache anymore. If nullptr was cached for \p K, this function will
122 /// return a null unique_ptr wrapped into an optional.
123 llvm::Optional<std::unique_ptr<ParsedAST>> take(Key K) {
124 std::unique_lock<std::mutex> Lock(Mut);
125 auto Existing = findByKey(K);
126 if (Existing == LRU.end())
127 return None;
128 std::unique_ptr<ParsedAST> V = std::move(Existing->second);
129 LRU.erase(Existing);
130 // GCC 4.8 fails to compile `return V;`, as it tries to call the copy
131 // constructor of unique_ptr, so we call the move ctor explicitly to avoid
132 // this miscompile.
133 return llvm::Optional<std::unique_ptr<ParsedAST>>(std::move(V));
134 }
135
136 private:
137 using KVPair = std::pair<Key, std::unique_ptr<ParsedAST>>;
138
139 std::vector<KVPair>::iterator findByKey(Key K) {
140 return llvm::find_if(LRU, [K](const KVPair &P) { return P.first == K; });
141 }
142
143 std::mutex Mut;
144 unsigned MaxRetainedASTs;
145 /// Items sorted in LRU order, i.e. first item is the most recently accessed
146 /// one.
147 std::vector<KVPair> LRU; /* GUARDED_BY(Mut) */
148 };
149
150 namespace {
151 class ASTWorkerHandle;
152
153 /// Owns one instance of the AST, schedules updates and reads of it.
154 /// Also responsible for building and providing access to the preamble.
155 /// Each ASTWorker processes the async requests sent to it on a separate
156 /// dedicated thread.
157 /// The ASTWorker that manages the AST is shared by both the processing thread
158 /// and the TUScheduler. The TUScheduler should discard an ASTWorker when
159 /// remove() is called, but its thread may be busy and we don't want to block.
160 /// So the workers are accessed via an ASTWorkerHandle. Destroying the handle
161 /// signals the worker to exit its run loop and gives up shared ownership of the
162 /// worker.
163 class ASTWorker {
164 friend class ASTWorkerHandle;
165 ASTWorker(PathRef FileName, const GlobalCompilationDatabase &CDB,
166 TUScheduler::ASTCache &LRUCache, Semaphore &Barrier, bool RunSync,
167 steady_clock::duration UpdateDebounce, bool StorePreamblesInMemory,
168 ParsingCallbacks &Callbacks);
169
170 public:
171 /// Create a new ASTWorker and return a handle to it.
172 /// The processing thread is spawned using \p Tasks. However, when \p Tasks
173 /// is null, all requests will be processed on the calling thread
174 /// synchronously instead. \p Barrier is acquired when processing each
175 /// request, it is used to limit the number of actively running threads.
176 static ASTWorkerHandle
177 create(PathRef FileName, const GlobalCompilationDatabase &CDB,
178 TUScheduler::ASTCache &IdleASTs, AsyncTaskRunner *Tasks,
179 Semaphore &Barrier, steady_clock::duration UpdateDebounce,
180 bool StorePreamblesInMemory, ParsingCallbacks &Callbacks);
181 ~ASTWorker();
182
183 void update(ParseInputs Inputs, WantDiagnostics);
184 void
185 runWithAST(llvm::StringRef Name,
186 llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action);
187 bool blockUntilIdle(Deadline Timeout) const;
188
189 std::shared_ptr<const PreambleData> getPossiblyStalePreamble() const;
190
191 /// Obtain a preamble reflecting all updates so far. Threadsafe.
192 /// It may be delivered immediately, or later on the worker thread.
193 void getCurrentPreamble(
194 llvm::unique_function<void(std::shared_ptr<const PreambleData>)>);
195 /// Returns compile command from the current file inputs.
196 tooling::CompileCommand getCurrentCompileCommand() const;
197
198 /// Wait for the first build of preamble to finish. Preamble itself can be
199 /// accessed via getPossiblyStalePreamble(). Note that this function will
200 /// return after an unsuccessful build of the preamble too, i.e. result of
201 /// getPossiblyStalePreamble() can be null even after this function returns.
202 void waitForFirstPreamble() const;
203
204 std::size_t getUsedBytes() const;
205 bool isASTCached() const;
206
207 private:
208 // Must be called exactly once on processing thread. Will return after
209 // stop() is called on a separate thread and all pending requests are
210 // processed.
211 void run();
212 /// Signal that run() should finish processing pending requests and exit.
213 void stop();
214 /// Adds a new task to the end of the request queue.
215 void startTask(llvm::StringRef Name, llvm::unique_function<void()> Task,
216 llvm::Optional<WantDiagnostics> UpdateType);
217 /// Updates the TUStatus and emits it. Only called in the worker thread.
218 void emitTUStatus(TUAction FAction,
219 const TUStatus::BuildDetails *Detail = nullptr);
220
221 /// Determines the next action to perform.
222 /// All actions that should never run are discarded.
223 /// Returns a deadline for the next action. If it's expired, run now.
224 /// scheduleLocked() is called again at the deadline, or if requests arrive.
225 Deadline scheduleLocked();
226 /// Should the first task in the queue be skipped instead of run?
227 bool shouldSkipHeadLocked() const;
228 /// This is private because `FileInputs.FS` is not thread-safe and thus not
229 /// safe to share. Callers should make sure not to expose `FS` via a public
230 /// interface.
231 std::shared_ptr<const ParseInputs> getCurrentFileInputs() const;
232
233 struct Request {
234 llvm::unique_function<void()> Action;
235 std::string Name;
236 steady_clock::time_point AddTime;
237 Context Ctx;
238 llvm::Optional<WantDiagnostics> UpdateType;
239 };
240
241 /// Handles retention of ASTs.
242 TUScheduler::ASTCache &IdleASTs;
243 const bool RunSync;
244 /// Time to wait after an update to see whether another update obsoletes it.
245 const steady_clock::duration UpdateDebounce;
246 /// File that ASTWorker is responsible for.
247 const Path FileName;
248 const GlobalCompilationDatabase &CDB;
249 /// Whether to keep the built preambles in memory or on disk.
250 const bool StorePreambleInMemory;
251 /// Callback invoked when preamble or main file AST is built.
252 ParsingCallbacks &Callbacks;
253 /// Only accessed by the worker thread.
254 TUStatus Status;
255
256 Semaphore &Barrier;
257 /// Whether the 'onMainAST' callback ran for the current FileInputs.
258 bool RanASTCallback = false;
259 /// Guards members used by both TUScheduler and the worker thread.
260 mutable std::mutex Mutex;
261 /// File inputs, currently being used by the worker.
262 /// Inputs are written and read by the worker thread, compile command can also
263 /// be consumed by clients of ASTWorker.
264 std::shared_ptr<const ParseInputs> FileInputs; /* GUARDED_BY(Mutex) */
265 std::shared_ptr<const PreambleData> LastBuiltPreamble; /* GUARDED_BY(Mutex) */
266 /// Becomes ready when the first preamble build finishes.
267 Notification PreambleWasBuilt;
268 /// Set to true to signal run() to finish processing.
269 bool Done; /* GUARDED_BY(Mutex) */
270 std::deque<Request> Requests; /* GUARDED_BY(Mutex) */
271 mutable std::condition_variable RequestsCV;
272 /// Guards the callback that publishes results of AST-related computations
273 /// (diagnostics, highlightings) and file statuses.
274 std::mutex PublishMu;
275 // Used to prevent remove document + add document races that lead to
276 // out-of-order callbacks for publishing results of onMainAST callback.
277 //
278 // The lifetime of the old/new ASTWorkers will overlap, but their handles
279 // don't. When the old handle is destroyed, the old worker will stop reporting
280 // any results to the user.
281 bool CanPublishResults = true; /* GUARDED_BY(PublishMu) */
282 };
283
284 /// A smart-pointer-like class that points to an active ASTWorker.
285 /// In destructor, signals to the underlying ASTWorker that no new requests will
286 /// be sent and the processing loop may exit (after running all pending
287 /// requests).
288 class ASTWorkerHandle {
289 friend class ASTWorker;
290 ASTWorkerHandle(std::shared_ptr<ASTWorker> Worker)
291 : Worker(std::move(Worker)) {
292 assert(this->Worker);
293 }
294
295 public:
296 ASTWorkerHandle(const ASTWorkerHandle &) = delete;
297 ASTWorkerHandle &operator=(const ASTWorkerHandle &) = delete;
298 ASTWorkerHandle(ASTWorkerHandle &&) = default;
299 ASTWorkerHandle &operator=(ASTWorkerHandle &&) = default;
300
301 ~ASTWorkerHandle() {
302 if (Worker)
303 Worker->stop();
304 }
305
306 ASTWorker &operator*() {
307 assert(Worker && "Handle was moved from");
308 return *Worker;
309 }
310
311 ASTWorker *operator->() {
312 assert(Worker && "Handle was moved from");
313 return Worker.get();
314 }
315
316 /// Returns an owning reference to the underlying ASTWorker that can outlive
317 /// the ASTWorkerHandle. However, no new requests to an active ASTWorker can
318 /// be schedule via the returned reference, i.e. only reads of the preamble
319 /// are possible.
320 std::shared_ptr<const ASTWorker> lock() { return Worker; }
321
322 private:
323 std::shared_ptr<ASTWorker> Worker;
324 };
325
326 ASTWorkerHandle
327 ASTWorker::create(PathRef FileName, const GlobalCompilationDatabase &CDB,
328 TUScheduler::ASTCache &IdleASTs, AsyncTaskRunner *Tasks,
329 Semaphore &Barrier, steady_clock::duration UpdateDebounce,
330 bool StorePreamblesInMemory, ParsingCallbacks &Callbacks) {
331 std::shared_ptr<ASTWorker> Worker(
332 new ASTWorker(FileName, CDB, IdleASTs, Barrier, /*RunSync=*/!Tasks,
333 UpdateDebounce, StorePreamblesInMemory, Callbacks));
334 if (Tasks)
335 Tasks->runAsync("worker:" + llvm::sys::path::filename(FileName),
336 [Worker]() { Worker->run(); });
337
338 return ASTWorkerHandle(std::move(Worker));
339 }
340
341 ASTWorker::ASTWorker(PathRef FileName, const GlobalCompilationDatabase &CDB,
342 TUScheduler::ASTCache &LRUCache, Semaphore &Barrier,
343 bool RunSync, steady_clock::duration UpdateDebounce,
344 bool StorePreamblesInMemory, ParsingCallbacks &Callbacks)
345 : IdleASTs(LRUCache), RunSync(RunSync), UpdateDebounce(UpdateDebounce),
346 FileName(FileName), CDB(CDB),
347 StorePreambleInMemory(StorePreamblesInMemory),
348 Callbacks(Callbacks), Status{TUAction(TUAction::Idle, ""),
349 TUStatus::BuildDetails()},
350 Barrier(Barrier), Done(false) {
351 auto Inputs = std::make_shared<ParseInputs>();
352 // Set a fallback command because compile command can be accessed before
353 // `Inputs` is initialized. Other fields are only used after initialization
354 // from client inputs.
355 Inputs->CompileCommand = CDB.getFallbackCommand(FileName);
356 FileInputs = std::move(Inputs);
357 }
358
359 ASTWorker::~ASTWorker() {
360 // Make sure we remove the cached AST, if any.
361 IdleASTs.take(this);
362 #ifndef NDEBUG
363 std::lock_guard<std::mutex> Lock(Mutex);
364 assert(Done && "handle was not destroyed");
365 assert(Requests.empty() && "unprocessed requests when destroying ASTWorker");
366 #endif
367 }
368
369 void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags) {
370 llvm::StringRef TaskName = "Update";
371 auto Task = [=]() mutable {
372 auto RunPublish = [&](llvm::function_ref<void()> Publish) {
373 // Ensure we only publish results from the worker if the file was not
374 // removed, making sure there are not race conditions.
375 std::lock_guard<std::mutex> Lock(PublishMu);
376 if (CanPublishResults)
377 Publish();
378 };
379
380 // Get the actual command as `Inputs` does not have a command.
381 // FIXME: some build systems like Bazel will take time to preparing
382 // environment to build the file, it would be nice if we could emit a
383 // "PreparingBuild" status to inform users, it is non-trivial given the
384 // current implementation.
385 if (auto Cmd = CDB.getCompileCommand(FileName))
386 Inputs.CompileCommand = *Cmd;
387 else
388 // FIXME: consider using old command if it's not a fallback one.
389 Inputs.CompileCommand = CDB.getFallbackCommand(FileName);
390 auto PrevInputs = getCurrentFileInputs();
391 // Will be used to check if we can avoid rebuilding the AST.
392 bool InputsAreTheSame =
393 std::tie(PrevInputs->CompileCommand, PrevInputs->Contents) ==
394 std::tie(Inputs.CompileCommand, Inputs.Contents);
395
396 tooling::CompileCommand OldCommand = PrevInputs->CompileCommand;
397 bool RanCallbackForPrevInputs = RanASTCallback;
398 {
399 std::lock_guard<std::mutex> Lock(Mutex);
400 FileInputs = std::make_shared<ParseInputs>(Inputs);
401 }
402 RanASTCallback = false;
403 emitTUStatus({TUAction::BuildingPreamble, TaskName});
404 log("Updating file {0} with command {1}\n[{2}]\n{3}", FileName,
405 Inputs.CompileCommand.Heuristic,
406 Inputs.CompileCommand.Directory,
407 llvm::join(Inputs.CompileCommand.CommandLine, " "));
408 // Rebuild the preamble and the AST.
409 StoreDiags CompilerInvocationDiagConsumer;
410 std::vector<std::string> CC1Args;
411 std::unique_ptr<CompilerInvocation> Invocation = buildCompilerInvocation(
412 Inputs, CompilerInvocationDiagConsumer, &CC1Args);
413 // Log cc1 args even (especially!) if creating invocation failed.
414 if (!CC1Args.empty())
415 vlog("Driver produced command: cc1 {0}", llvm::join(CC1Args, " "));
416 std::vector<Diag> CompilerInvocationDiags =
417 CompilerInvocationDiagConsumer.take();
418 if (!Invocation) {
419 elog("Could not build CompilerInvocation for file {0}", FileName);
420 // Remove the old AST if it's still in cache.
421 IdleASTs.take(this);
422 TUStatus::BuildDetails Details;
423 Details.BuildFailed = true;
424 emitTUStatus({TUAction::BuildingPreamble, TaskName}, &Details);
425 // Report the diagnostics we collected when parsing the command line.
426 Callbacks.onFailedAST(FileName, std::move(CompilerInvocationDiags),
427 RunPublish);
428 // Make sure anyone waiting for the preamble gets notified it could not
429 // be built.
430 PreambleWasBuilt.notify();
431 return;
432 }
433
434 std::shared_ptr<const PreambleData> OldPreamble =
435 getPossiblyStalePreamble();
436 std::shared_ptr<const PreambleData> NewPreamble = buildPreamble(
437 FileName, *Invocation, OldPreamble, OldCommand, Inputs,
438 StorePreambleInMemory,
439 [this](ASTContext &Ctx, std::shared_ptr<clang::Preprocessor> PP,
440 const CanonicalIncludes &CanonIncludes) {
441 Callbacks.onPreambleAST(FileName, Ctx, std::move(PP), CanonIncludes);
442 });
443
444 bool CanReuseAST = InputsAreTheSame && (OldPreamble == NewPreamble);
445 {
446 std::lock_guard<std::mutex> Lock(Mutex);
447 LastBuiltPreamble = NewPreamble;
448 }
449 // Before doing the expensive AST reparse, we want to release our reference
450 // to the old preamble, so it can be freed if there are no other references
451 // to it.
452 OldPreamble.reset();
453 PreambleWasBuilt.notify();
454 emitTUStatus({TUAction::BuildingFile, TaskName});
455 if (!CanReuseAST) {
456 IdleASTs.take(this); // Remove the old AST if it's still in cache.
457 } else {
458 // We don't need to rebuild the AST, check if we need to run the callback.
459 if (RanCallbackForPrevInputs) {
460 RanASTCallback = true;
461 // Take a shortcut and don't report the diagnostics, since they should
462 // not changed. All the clients should handle the lack of OnUpdated()
463 // call anyway to handle empty result from buildAST.
464 // FIXME(ibiryukov): the AST could actually change if non-preamble
465 // includes changed, but we choose to ignore it.
466 // FIXME(ibiryukov): should we refresh the cache in IdleASTs for the
467 // current file at this point?
468 log("Skipping rebuild of the AST for {0}, inputs are the same.",
469 FileName);
470 TUStatus::BuildDetails Details;
471 Details.ReuseAST = true;
472 emitTUStatus({TUAction::BuildingFile, TaskName}, &Details);
473 return;
474 }
475 }
476
477 // We only need to build the AST if diagnostics were requested.
478 if (WantDiags == WantDiagnostics::No)
479 return;
480
481 {
482 std::lock_guard<std::mutex> Lock(PublishMu);
483 // No need to rebuild the AST if we won't send the diagnostics. However,
484 // note that we don't prevent preamble rebuilds.
485 if (!CanPublishResults)
486 return;
487 }
488
489 // Get the AST for diagnostics.
490 llvm::Optional<std::unique_ptr<ParsedAST>> AST = IdleASTs.take(this);
491 if (!AST) {
492 llvm::Optional<ParsedAST> NewAST =
493 buildAST(FileName, std::move(Invocation), CompilerInvocationDiags,
494 Inputs, NewPreamble);
495 AST = NewAST ? std::make_unique<ParsedAST>(std::move(*NewAST)) : nullptr;
496 if (!(*AST)) { // buildAST fails.
497 TUStatus::BuildDetails Details;
498 Details.BuildFailed = true;
499 emitTUStatus({TUAction::BuildingFile, TaskName}, &Details);
500 }
501 } else {
502 // We are reusing the AST.
503 TUStatus::BuildDetails Details;
504 Details.ReuseAST = true;
505 emitTUStatus({TUAction::BuildingFile, TaskName}, &Details);
506 }
507
508 // We want to report the diagnostics even if this update was cancelled.
509 // It seems more useful than making the clients wait indefinitely if they
510 // spam us with updates.
511 // Note *AST can still be null if buildAST fails.
512 if (*AST) {
513 trace::Span Span("Running main AST callback");
514
515 Callbacks.onMainAST(FileName, **AST, RunPublish);
516 RanASTCallback = true;
517 } else {
518 // Failed to build the AST, at least report diagnostics from the command
519 // line if there were any.
520 // FIXME: we might have got more errors while trying to build the AST,
521 // surface them too.
522 Callbacks.onFailedAST(FileName, CompilerInvocationDiags, RunPublish);
523 }
524 // Stash the AST in the cache for further use.
525 IdleASTs.put(this, std::move(*AST));
526 };
527 startTask(TaskName, std::move(Task), WantDiags);
528 }
529
530 void ASTWorker::runWithAST(
531 llvm::StringRef Name,
532 llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action) {
533 auto Task = [=, Action = std::move(Action)]() mutable {
534 if (isCancelled())
535 return Action(llvm::make_error<CancelledError>());
536 llvm::Optional<std::unique_ptr<ParsedAST>> AST = IdleASTs.take(this);
537 auto CurrentInputs = getCurrentFileInputs();
538 if (!AST) {
539 StoreDiags CompilerInvocationDiagConsumer;
540 std::unique_ptr<CompilerInvocation> Invocation = buildCompilerInvocation(
541 *CurrentInputs, CompilerInvocationDiagConsumer);
542 // Try rebuilding the AST.
543 llvm::Optional<ParsedAST> NewAST =
544 Invocation
545 ? buildAST(FileName,
546 std::make_unique<CompilerInvocation>(*Invocation),
547 CompilerInvocationDiagConsumer.take(), *CurrentInputs,
548 getPossiblyStalePreamble())
549 : None;
550 AST = NewAST ? std::make_unique<ParsedAST>(std::move(*NewAST)) : nullptr;
551 }
552 // Make sure we put the AST back into the LRU cache.
553 auto _ = llvm::make_scope_exit(
554 [&AST, this]() { IdleASTs.put(this, std::move(*AST)); });
555 // Run the user-provided action.
556 if (!*AST)
557 return Action(llvm::make_error<llvm::StringError>(
558 "invalid AST", llvm::errc::invalid_argument));
559 Action(InputsAndAST{*CurrentInputs, **AST});
560 };
561 startTask(Name, std::move(Task), /*UpdateType=*/None);
562 }
563
564 std::shared_ptr<const PreambleData>
565 ASTWorker::getPossiblyStalePreamble() const {
566 std::lock_guard<std::mutex> Lock(Mutex);
567 return LastBuiltPreamble;
568 }
569
570 void ASTWorker::getCurrentPreamble(
571 llvm::unique_function<void(std::shared_ptr<const PreambleData>)> Callback) {
572 // We could just call startTask() to throw the read on the queue, knowing
573 // it will run after any updates. But we know this task is cheap, so to
574 // improve latency we cheat: insert it on the queue after the last update.
575 std::unique_lock<std::mutex> Lock(Mutex);
576 auto LastUpdate =
577 std::find_if(Requests.rbegin(), Requests.rend(),
578 [](const Request &R) { return R.UpdateType.hasValue(); });
579 // If there were no writes in the queue, the preamble is ready now.
580 if (LastUpdate == Requests.rend()) {
581 Lock.unlock();
582 return Callback(getPossiblyStalePreamble());
583 }
584 assert(!RunSync && "Running synchronously, but queue is non-empty!");
585 Requests.insert(LastUpdate.base(),
586 Request{[Callback = std::move(Callback), this]() mutable {
587 Callback(getPossiblyStalePreamble());
588 },
589 "GetPreamble", steady_clock::now(),
590 Context::current().clone(),
591 /*UpdateType=*/None});
592 Lock.unlock();
593 RequestsCV.notify_all();
594 }
595
596 void ASTWorker::waitForFirstPreamble() const { PreambleWasBuilt.wait(); }
597
598 std::shared_ptr<const ParseInputs> ASTWorker::getCurrentFileInputs() const {
599 std::unique_lock<std::mutex> Lock(Mutex);
600 return FileInputs;
601 }
602
603 tooling::CompileCommand ASTWorker::getCurrentCompileCommand() const {
604 std::unique_lock<std::mutex> Lock(Mutex);
605 return FileInputs->CompileCommand;
606 }
607
608 std::size_t ASTWorker::getUsedBytes() const {
609 // Note that we don't report the size of ASTs currently used for processing
610 // the in-flight requests. We used this information for debugging purposes
611 // only, so this should be fine.
612 std::size_t Result = IdleASTs.getUsedBytes(this);
613 if (auto Preamble = getPossiblyStalePreamble())
614 Result += Preamble->Preamble.getSize();
615 return Result;
616 }
617
618 bool ASTWorker::isASTCached() const { return IdleASTs.getUsedBytes(this) != 0; }
619
620 void ASTWorker::stop() {
621 {
622 std::lock_guard<std::mutex> Lock(PublishMu);
623 CanPublishResults = false;
624 }
625 {
626 std::lock_guard<std::mutex> Lock(Mutex);
627 assert(!Done && "stop() called twice");
628 Done = true;
629 }
630 RequestsCV.notify_all();
631 }
632
633 void ASTWorker::startTask(llvm::StringRef Name,
634 llvm::unique_function<void()> Task,
635 llvm::Optional<WantDiagnostics> UpdateType) {
636 if (RunSync) {
637 assert(!Done && "running a task after stop()");
638 trace::Span Tracer(Name + ":" + llvm::sys::path::filename(FileName));
639 Task();
640 return;
641 }
642
643 {
644 std::lock_guard<std::mutex> Lock(Mutex);
645 assert(!Done && "running a task after stop()");
646 Requests.push_back(
647 {std::move(Task), Name, steady_clock::now(),
648 Context::current().derive(kFileBeingProcessed, FileName), UpdateType});
649 }
650 RequestsCV.notify_all();
651 }
652
653 void ASTWorker::emitTUStatus(TUAction Action,
654 const TUStatus::BuildDetails *Details) {
655 Status.Action = std::move(Action);
656 if (Details)
657 Status.Details = *Details;
658 std::lock_guard<std::mutex> Lock(PublishMu);
659 // Do not emit TU statuses when the ASTWorker is shutting down.
660 if (CanPublishResults) {
661 Callbacks.onFileUpdated(FileName, Status);
662 }
663 }
664
665 void ASTWorker::run() {
666 while (true) {
667 Request Req;
668 {
669 std::unique_lock<std::mutex> Lock(Mutex);
670 for (auto Wait = scheduleLocked(); !Wait.expired();
671 Wait = scheduleLocked()) {
672 if (Done) {
673 if (Requests.empty())
674 return;
675 else // Even though Done is set, finish pending requests.
676 break; // However, skip delays to shutdown fast.
677 }
678
679 // Tracing: we have a next request, attribute this sleep to it.
680 llvm::Optional<WithContext> Ctx;
681 llvm::Optional<trace::Span> Tracer;
682 if (!Requests.empty()) {
683 Ctx.emplace(Requests.front().Ctx.clone());
684 Tracer.emplace("Debounce");
685 SPAN_ATTACH(*Tracer, "next_request", Requests.front().Name);
686 if (!(Wait == Deadline::infinity())) {
687 emitTUStatus({TUAction::Queued, Req.Name});
688 SPAN_ATTACH(*Tracer, "sleep_ms",
689 std::chrono::duration_cast<std::chrono::milliseconds>(
690 Wait.time() - steady_clock::now())
691 .count());
692 }
693 }
694
695 wait(Lock, RequestsCV, Wait);
696 }
697 Req = std::move(Requests.front());
698 // Leave it on the queue for now, so waiters don't see an empty queue.
699 } // unlock Mutex
700
701 {
702 std::unique_lock<Semaphore> Lock(Barrier, std::try_to_lock);
703 if (!Lock.owns_lock()) {
704 emitTUStatus({TUAction::Queued, Req.Name});
705 Lock.lock();
706 }
707 WithContext Guard(std::move(Req.Ctx));
708 trace::Span Tracer(Req.Name);
709 emitTUStatus({TUAction::RunningAction, Req.Name});
710 Req.Action();
711 }
712
713 bool IsEmpty = false;
714 {
715 std::lock_guard<std::mutex> Lock(Mutex);
716 Requests.pop_front();
717 IsEmpty = Requests.empty();
718 }
719 if (IsEmpty)
720 emitTUStatus({TUAction::Idle, /*Name*/ ""});
721 RequestsCV.notify_all();
722 }
723 }
724
725 Deadline ASTWorker::scheduleLocked() {
726 if (Requests.empty())
727 return Deadline::infinity(); // Wait for new requests.
728 // Handle cancelled requests first so the rest of the scheduler doesn't.
729 for (auto I = Requests.begin(), E = Requests.end(); I != E; ++I) {
730 if (!isCancelled(I->Ctx)) {
731 // Cancellations after the first read don't affect current scheduling.
732 if (I->UpdateType == None)
733 break;
734 continue;
735 }
736 // Cancelled reads are moved to the front of the queue and run immediately.
737 if (I->UpdateType == None) {
738 Request R = std::move(*I);
739 Requests.erase(I);
740 Requests.push_front(std::move(R));
741 return Deadline::zero();
742 }
743 // Cancelled updates are downgraded to auto-diagnostics, and may be elided.
744 if (I->UpdateType == WantDiagnostics::Yes)
745 I->UpdateType = WantDiagnostics::Auto;
746 }
747
748 while (shouldSkipHeadLocked())
749 Requests.pop_front();
750 assert(!Requests.empty() && "skipped the whole queue");
751 // Some updates aren't dead yet, but never end up being used.
752 // e.g. the first keystroke is live until obsoleted by the second.
753 // We debounce "maybe-unused" writes, sleeping 500ms in case they become dead.
754 // But don't delay reads (including updates where diagnostics are needed).
755 for (const auto &R : Requests)
756 if (R.UpdateType == None || R.UpdateType == WantDiagnostics::Yes)
757 return Deadline::zero();
758 // Front request needs to be debounced, so determine when we're ready.
759 Deadline D(Requests.front().AddTime + UpdateDebounce);
760 return D;
761 }
762
763 // Returns true if Requests.front() is a dead update that can be skipped.
764 bool ASTWorker::shouldSkipHeadLocked() const {
765 assert(!Requests.empty());
766 auto Next = Requests.begin();
767 auto UpdateType = Next->UpdateType;
768 if (!UpdateType) // Only skip updates.
769 return false;
770 ++Next;
771 // An update is live if its AST might still be read.
772 // That is, if it's not immediately followed by another update.
773 if (Next == Requests.end() || !Next->UpdateType)
774 return false;
775 // The other way an update can be live is if its diagnostics might be used.
776 switch (*UpdateType) {
777 case WantDiagnostics::Yes:
778 return false; // Always used.
779 case WantDiagnostics::No:
780 return true; // Always dead.
781 case WantDiagnostics::Auto:
782 // Used unless followed by an update that generates diagnostics.
783 for (; Next != Requests.end(); ++Next)
784 if (Next->UpdateType == WantDiagnostics::Yes ||
785 Next->UpdateType == WantDiagnostics::Auto)
786 return true; // Prefer later diagnostics.
787 return false;
788 }
789 llvm_unreachable("Unknown WantDiagnostics");
790 }
791
792 bool ASTWorker::blockUntilIdle(Deadline Timeout) const {
793 std::unique_lock<std::mutex> Lock(Mutex);
794 return wait(Lock, RequestsCV, Timeout, [&] { return Requests.empty(); });
795 }
796
797 // Render a TUAction to a user-facing string representation.
798 // TUAction represents clangd-internal states, we don't intend to expose them
799 // to users (say C++ programmers) directly to avoid confusion, we use terms that
800 // are familiar by C++ programmers.
801 std::string renderTUAction(const TUAction &Action) {
802 std::string Result;
803 llvm::raw_string_ostream OS(Result);
804 switch (Action.S) {
805 case TUAction::Queued:
806 OS << "file is queued";
807 break;
808 case TUAction::RunningAction:
809 OS << "running " << Action.Name;
810 break;
811 case TUAction::BuildingPreamble:
812 OS << "parsing includes";
813 break;
814 case TUAction::BuildingFile:
815 OS << "parsing main file";
816 break;
817 case TUAction::Idle:
818 OS << "idle";
819 break;
820 }
821 return OS.str();
822 }
823
824 } // namespace
825
826 unsigned getDefaultAsyncThreadsCount() {
827 unsigned HardwareConcurrency = llvm::heavyweight_hardware_concurrency();
828 // heavyweight_hardware_concurrency may fall back to hardware_concurrency.
829 // C++ standard says that hardware_concurrency() may return 0; fallback to 1
830 // worker thread in that case.
831 if (HardwareConcurrency == 0)
832 return 1;
833 return HardwareConcurrency;
834 }
835
836 FileStatus TUStatus::render(PathRef File) const {
837 FileStatus FStatus;
838 FStatus.uri = URIForFile::canonicalize(File, /*TUPath=*/File);
839 FStatus.state = renderTUAction(Action);
840 return FStatus;
841 }
842
843 struct TUScheduler::FileData {
844 /// Latest inputs, passed to TUScheduler::update().
845 std::string Contents;
846 ASTWorkerHandle Worker;
847 };
848
849 TUScheduler::TUScheduler(const GlobalCompilationDatabase &CDB,
850 unsigned AsyncThreadsCount,
851 bool StorePreamblesInMemory,
852 std::unique_ptr<ParsingCallbacks> Callbacks,
853 std::chrono::steady_clock::duration UpdateDebounce,
854 ASTRetentionPolicy RetentionPolicy)
855 : CDB(CDB), StorePreamblesInMemory(StorePreamblesInMemory),
856 Callbacks(Callbacks ? move(Callbacks)
857 : std::make_unique<ParsingCallbacks>()),
858 Barrier(AsyncThreadsCount),
859 IdleASTs(std::make_unique<ASTCache>(RetentionPolicy.MaxRetainedASTs)),
860 UpdateDebounce(UpdateDebounce) {
861 if (0 < AsyncThreadsCount) {
862 PreambleTasks.emplace();
863 WorkerThreads.emplace();
864 }
865 }
866
867 TUScheduler::~TUScheduler() {
868 // Notify all workers that they need to stop.
869 Files.clear();
870
871 // Wait for all in-flight tasks to finish.
872 if (PreambleTasks)
873 PreambleTasks->wait();
874 if (WorkerThreads)
875 WorkerThreads->wait();
876 }
877
878 bool TUScheduler::blockUntilIdle(Deadline D) const {
879 for (auto &File : Files)
880 if (!File.getValue()->Worker->blockUntilIdle(D))
881 return false;
882 if (PreambleTasks)
883 if (!PreambleTasks->wait(D))
884 return false;
885 return true;
886 }
887
888 bool TUScheduler::update(PathRef File, ParseInputs Inputs,
889 WantDiagnostics WantDiags) {
890 std::unique_ptr<FileData> &FD = Files[File];
891 bool NewFile = FD == nullptr;
892 if (!FD) {
893 // Create a new worker to process the AST-related tasks.
894 ASTWorkerHandle Worker = ASTWorker::create(
895 File, CDB, *IdleASTs,
896 WorkerThreads ? WorkerThreads.getPointer() : nullptr, Barrier,
897 UpdateDebounce, StorePreamblesInMemory, *Callbacks);
898 FD = std::unique_ptr<FileData>(
899 new FileData{Inputs.Contents, std::move(Worker)});
900 } else {
901 FD->Contents = Inputs.Contents;
902 }
903 FD->Worker->update(std::move(Inputs), WantDiags);
904 return NewFile;
905 }
906
907 void TUScheduler::remove(PathRef File) {
908 bool Removed = Files.erase(File);
909 if (!Removed)
910 elog("Trying to remove file from TUScheduler that is not tracked: {0}",
911 File);
912 }
913
914 llvm::StringRef TUScheduler::getContents(PathRef File) const {
915 auto It = Files.find(File);
916 if (It == Files.end()) {
917 elog("getContents() for untracked file: {0}", File);
918 return "";
919 }
920 return It->second->Contents;
921 }
922
923 llvm::StringMap<std::string> TUScheduler::getAllFileContents() const {
924 llvm::StringMap<std::string> Results;
925 for (auto &It : Files)
926 Results.try_emplace(It.getKey(), It.getValue()->Contents);
927 return Results;
928 }
929
930 void TUScheduler::run(llvm::StringRef Name,
931 llvm::unique_function<void()> Action) {
932 if (!PreambleTasks)
933 return Action();
934 PreambleTasks->runAsync(Name, [Ctx = Context::current().clone(),
935 Action = std::move(Action)]() mutable {
936 WithContext WC(std::move(Ctx));
937 Action();
938 });
939 }
940
941 void TUScheduler::runWithAST(
942 llvm::StringRef Name, PathRef File,
943 llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action) {
944 auto It = Files.find(File);
945 if (It == Files.end()) {
946 Action(llvm::make_error<LSPError>(
947 "trying to get AST for non-added document", ErrorCode::InvalidParams));
948 return;
949 }
950
951 It->second->Worker->runWithAST(Name, std::move(Action));
952 }
953
954 void TUScheduler::runWithPreamble(llvm::StringRef Name, PathRef File,
955 PreambleConsistency Consistency,
956 Callback<InputsAndPreamble> Action) {
957 auto It = Files.find(File);
958 if (It == Files.end()) {
959 Action(llvm::make_error<LSPError>(
960 "trying to get preamble for non-added document",
961 ErrorCode::InvalidParams));
962 return;
963 }
964
965 if (!PreambleTasks) {
966 trace::Span Tracer(Name);
967 SPAN_ATTACH(Tracer, "file", File);
968 std::shared_ptr<const PreambleData> Preamble =
969 It->second->Worker->getPossiblyStalePreamble();
970 Action(InputsAndPreamble{It->second->Contents,
971 It->second->Worker->getCurrentCompileCommand(),
972 Preamble.get()});
973 return;
974 }
975
976 // Future is populated if the task needs a specific preamble.
977 std::future<std::shared_ptr<const PreambleData>> ConsistentPreamble;
978 if (Consistency == Consistent) {
979 std::promise<std::shared_ptr<const PreambleData>> Promise;
980 ConsistentPreamble = Promise.get_future();
981 It->second->Worker->getCurrentPreamble(
982 [Promise = std::move(Promise)](
983 std::shared_ptr<const PreambleData> Preamble) mutable {
984 Promise.set_value(std::move(Preamble));
985 });
986 }
987
988 std::shared_ptr<const ASTWorker> Worker = It->second->Worker.lock();
989 auto Task = [Worker, Consistency, Name = Name.str(), File = File.str(),
990 Contents = It->second->Contents,
991 Command = Worker->getCurrentCompileCommand(),
992 Ctx = Context::current().derive(kFileBeingProcessed, File),
993 ConsistentPreamble = std::move(ConsistentPreamble),
994 Action = std::move(Action), this]() mutable {
995 std::shared_ptr<const PreambleData> Preamble;
996 if (ConsistentPreamble.valid()) {
997 Preamble = ConsistentPreamble.get();
998 } else {
999 if (Consistency != PreambleConsistency::StaleOrAbsent) {
1000 // Wait until the preamble is built for the first time, if preamble is
1001 // required. This avoids extra work of processing the preamble headers
1002 // in parallel multiple times.
1003 Worker->waitForFirstPreamble();
1004 }
1005 Preamble = Worker->getPossiblyStalePreamble();
1006 }
1007
1008 std::lock_guard<Semaphore> BarrierLock(Barrier);
1009 WithContext Guard(std::move(Ctx));
1010 trace::Span Tracer(Name);
1011 SPAN_ATTACH(Tracer, "file", File);
1012 Action(InputsAndPreamble{Contents, Command, Preamble.get()});
1013 };
1014
1015 PreambleTasks->runAsync("task:" + llvm::sys::path::filename(File),
1016 std::move(Task));
1017 }
1018
1019 std::vector<std::pair<Path, std::size_t>>
1020 TUScheduler::getUsedBytesPerFile() const {
1021 std::vector<std::pair<Path, std::size_t>> Result;
1022 Result.reserve(Files.size());
1023 for (auto &&PathAndFile : Files)
1024 Result.push_back(
1025 {PathAndFile.first(), PathAndFile.second->Worker->getUsedBytes()});
1026 return Result;
1027 }
1028
1029 std::vector<Path> TUScheduler::getFilesWithCachedAST() const {
1030 std::vector<Path> Result;
1031 for (auto &&PathAndFile : Files) {
1032 if (!PathAndFile.second->Worker->isASTCached())
1033 continue;
1034 Result.push_back(PathAndFile.first());
1035 }
1036 return Result;
1037 }
1038
1039 } // namespace clangd
1040 } // namespace clang
clang::clangd::TUScheduler::PreambleConsistency
PreambleConsistency
Controls whether preamble reads wait for the preamble to be up-to-date.
Definition: TUScheduler.h:201
Command
const tooling::CompileCommand & Command
Definition: CodeComplete.cpp:1019
clang::clangd::TUScheduler::~TUScheduler
~TUScheduler()
Definition: TUScheduler.cpp:867
clang::clangd::WantDiagnostics
WantDiagnostics
Determines whether diagnostics should be generated for a file snapshot.
Definition: TUScheduler.h:47
Trace.h
Contents
llvm::StringRef Contents
Definition: CodeComplete.cpp:1021
clang::clangd::WantDiagnostics::No
Diagnostics must be generated for this snapshot.
clang::clangd::buildAST
llvm::Optional< ParsedAST > buildAST(PathRef FileName, std::unique_ptr< CompilerInvocation > Invocation, llvm::ArrayRef< Diag > CompilerInvocationDiags, const ParseInputs &Inputs, std::shared_ptr< const PreambleData > Preamble)
Build an AST from provided user inputs.
Definition: ParsedAST.cpp:505
clang::clangd::TUStatus::render
FileStatus render(PathRef File) const
Serialize this to an LSP file status item.
Definition: TUScheduler.cpp:836
clang::clangd::TUScheduler::getFileBeingProcessedInContext
static llvm::Optional< llvm::StringRef > getFileBeingProcessedInContext()
Definition: TUScheduler.cpp:77
clang::clangd::TUScheduler::blockUntilIdle
bool blockUntilIdle(Deadline D) const
Wait until there are no scheduled or running tasks.
Definition: TUScheduler.cpp:878
clang::clangd::TUScheduler::remove
void remove(PathRef File)
Remove File from the list of tracked files and schedule removal of its resources. ...
Definition: TUScheduler.cpp:907
clang::clangd::TUAction::Idle
Definition: TUScheduler.h:70
clang::clangd::TUScheduler::TUScheduler
TUScheduler(const GlobalCompilationDatabase &CDB, unsigned AsyncThreadsCount, bool StorePreamblesInMemory, std::unique_ptr< ParsingCallbacks > ASTCallbacks, std::chrono::steady_clock::duration UpdateDebounce, ASTRetentionPolicy RetentionPolicy)
Definition: TUScheduler.cpp:849
clang::clangd::TUAction::Queued
Definition: TUScheduler.h:65
clang::clangd::FileStatus::state
std::string state
The human-readable string presents the current state of the file, can be shown in the UI (e...
Definition: Protocol.h:1207
clang::clangd::PathRef
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition: Path.h:23
clang::clangd::TUAction::RunningAction
Definition: TUScheduler.h:66
Results
std::vector< CodeCompletionResult > Results
Definition: CodeComplete.cpp:689
clang::clangd::Key
Values in a Context are indexed by typed keys.
Definition: Context.h:40
clang::clangd::Callback
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition: Function.h:28
clang::clangd::TextDocumentSyncKind::None
Documents should not be synced at all.
Context.h
clang::clangd::Semaphore
Limits the number of threads that can acquire the lock at the same time.
Definition: Threading.h:41
clang::clangd::FileStatus::uri
URIForFile uri
The text document&#39;s URI.
Definition: Protocol.h:1204
clang::clangd::vlog
void vlog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:67
clang::clangd::TUScheduler::update
bool update(PathRef File, ParseInputs Inputs, WantDiagnostics WD)
Schedule an update for File.
Definition: TUScheduler.cpp:888
clang::clangd::TUAction::BuildingFile
Definition: TUScheduler.h:68
clang::clangd::elog
void elog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:56
clang::clangd::ParseInputs::Contents
std::string Contents
Definition: Compiler.h:47
GlobalCompilationDatabase.h
CanonicalIncludes.h
clang::clangd::ASTRetentionPolicy
Configuration of the AST retention policy.
Definition: TUScheduler.h:57
clang::clangd::isCancelled
bool isCancelled(const Context &Ctx)
True if the current context is within a cancelable task which was cancelled.
Definition: Cancellation.cpp:26
Cancellation.h
clang::clangd::buildPreamble
std::shared_ptr< const PreambleData > buildPreamble(PathRef FileName, CompilerInvocation &CI, std::shared_ptr< const PreambleData > OldPreamble, const tooling::CompileCommand &OldCompileCommand, const ParseInputs &Inputs, bool StoreInMemory, PreambleParsedCallback PreambleCallback)
Build a preamble for the new inputs unless an old one can be reused.
Definition: Preamble.cpp:89
clang::clangd::WantDiagnostics::Yes
clang::clangd::GlobalCompilationDatabase
Provides compilation arguments used for parsing C and C++ files.
Definition: GlobalCompilationDatabase.h:35
Ctx
Context Ctx
Definition: TUScheduler.cpp:237
clang::clangd::SymbolOrigin::AST
Preamble.h
clang::clangd::Context::clone
Context clone() const
Clone this context object.
Definition: Context.cpp:20
Compiler.h
UpdateType
llvm::Optional< WantDiagnostics > UpdateType
Definition: TUScheduler.cpp:238
clang::clangd::Deadline::infinity
static Deadline infinity()
Definition: Threading.h:63
Action
llvm::unique_function< void()> Action
Definition: TUScheduler.cpp:234
Diagnostics.h
clang::clangd::log
void log(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:62
clang::clangd::TUScheduler::ASTCache::put
void put(Key K, std::unique_ptr< ParsedAST > V)
Store the value in the pool, possibly removing the last used AST.
Definition: TUScheduler.cpp:105
clang::clangd::Path
std::string Path
A typedef to represent a file path.
Definition: Path.h:20
clang::clangd::Context::current
static const Context & current()
Returns the context for the current thread, creating it if needed.
Definition: Context.cpp:27
clang::clangd::URIForFile::canonicalize
static URIForFile canonicalize(llvm::StringRef AbsPath, llvm::StringRef TUPath)
Canonicalizes AbsPath via URI.
Definition: Protocol.cpp:32
clang::clangd::TUScheduler::getUsedBytesPerFile
std::vector< std::pair< Path, std::size_t > > getUsedBytesPerFile() const
Returns estimated memory usage for each of the currently open files.
Definition: TUScheduler.cpp:1020
clang::clangd::TUScheduler::runWithPreamble
void runWithPreamble(llvm::StringRef Name, PathRef File, PreambleConsistency Consistency, Callback< InputsAndPreamble > Action)
Schedule an async read of the preamble.
Definition: TUScheduler.cpp:954
clang::clangd::TUScheduler::getFilesWithCachedAST
std::vector< Path > getFilesWithCachedAST() const
Returns a list of files with ASTs currently stored in memory.
Definition: TUScheduler.cpp:1029
FileName
PathRef FileName
Definition: CodeComplete.cpp:1018
clang::clangd::wait
void wait(std::unique_lock< std::mutex > &Lock, std::condition_variable &CV, Deadline D)
Wait once on CV for the specified duration.
Definition: Threading.cpp:107
clang::clangd::ErrorCode::InvalidParams
clang::clangd::AsyncTaskRunner
Runs tasks on separate (detached) threads and wait for all tasks to finish.
Definition: Threading.h:105
Name
std::string Name
Definition: TUScheduler.cpp:235
clang::clangd::TUScheduler::ASTCache::Key
const ASTWorker * Key
Definition: TUScheduler.cpp:89
clang::clangd::TUStatus::BuildDetails
Definition: TUScheduler.h:82
clang::clangd::getDefaultAsyncThreadsCount
unsigned getDefaultAsyncThreadsCount()
Returns a number of a default async threads to use for TUScheduler.
Definition: TUScheduler.cpp:826
clang::clangd::WithContext
WithContext replaces Context::current() with a provided scope.
Definition: Context.h:189
clang::clangd::TUAction
Definition: TUScheduler.h:63
clang::clangd::ParsingCallbacks
Definition: TUScheduler.h:95
clang::clangd::TUScheduler::FileData::Contents
std::string Contents
Latest inputs, passed to TUScheduler::update().
Definition: TUScheduler.cpp:845
Logger.h
clang::clangd::ParseInputs
Information required to run clang, e.g. to parse AST or do code completion.
Definition: Compiler.h:44
clang::clangd::TUScheduler::FileData
Definition: TUScheduler.cpp:843
clang::clangd::TUScheduler::ASTCache::ASTCache
ASTCache(unsigned MaxRetainedASTs)
Definition: TUScheduler.cpp:91
Preamble
const PreambleData * Preamble
Definition: CodeComplete.cpp:1020
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
clang::clangd::Deadline::zero
static Deadline zero()
Definition: Threading.h:62
ParsedAST.h
clang::clangd::Context::derive
Context derive(const Key< Type > &Key, typename std::decay< Type >::type Value) const &
Derives a child context It is safe to move or destroy a parent context after calling derive()...
Definition: Context.h:121
clang::clangd::TUScheduler::ASTCache::take
llvm::Optional< std::unique_ptr< ParsedAST > > take(Key K)
Returns the cached value for K, or llvm::None if the value is not in the cache anymore.
Definition: TUScheduler.cpp:123
clang::tidy::bugprone::PP
static Preprocessor * PP
Definition: BadSignalToKillThreadCheck.cpp:28
AddTime
steady_clock::time_point AddTime
Definition: TUScheduler.cpp:236
clang::clangd::buildCompilerInvocation
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:44
clang::clangd::kFileBeingProcessed
static clang::clangd::Key< std::string > kFileBeingProcessed
Definition: TUScheduler.cpp:75
clang::clangd::TUScheduler::runWithAST
void runWithAST(llvm::StringRef Name, PathRef File, Callback< InputsAndAST > Action)
Schedule an async read of the AST.
Definition: TUScheduler.cpp:941
clang::clangd::Deadline
A point in time we can wait for.
Definition: Threading.h:58
E
const Expr * E
Definition: AvoidBindCheck.cpp:82
clang::clangd::FileStatus
Clangd extension: indicates the current state of the file in clangd, sent from server via the textDoc...
Definition: Protocol.h:1202
clang::clangd::TUAction::BuildingPreamble
Definition: TUScheduler.h:67
clang::clangd::InputsAndPreamble
Definition: TUScheduler.h:39
clang::tidy::cppcoreguidelines::join
static std::string join(ArrayRef< SpecialMemberFunctionsCheck::SpecialMemberFunctionKind > SMFS, llvm::StringRef AndOr)
Definition: SpecialMemberFunctionsCheck.cpp:81
clang::clangd::TUScheduler::ASTCache
An LRU cache of idle ASTs.
Definition: TUScheduler.cpp:87
clang::clangd::TUScheduler::getContents
llvm::StringRef getContents(PathRef File) const
Returns the current contents of the buffer for File, per last update().
Definition: TUScheduler.cpp:914
clang::clangd::trace::Span
Records an event whose duration is the lifetime of the Span object.
Definition: Trace.h:81
clang::clangd::CompletionItemKind::File
clang::clangd::InputsAndPreamble::Contents
llvm::StringRef Contents
Definition: TUScheduler.h:40
SPAN_ATTACH
#define SPAN_ATTACH(S, Name, Expr)
Attach a key-value pair to a Span event.
Definition: Trace.h:97
clang::clangd::WantDiagnostics::Auto
Diagnostics must not be generated for this snapshot.
clang::clangd::TUScheduler::FileData::Worker
ASTWorkerHandle Worker
Definition: TUScheduler.cpp:846
TUScheduler.h
clang::clangd::TUScheduler::Consistent
The preamble is generated from the current version of the file.
Definition: TUScheduler.h:206
clang::clangd::TUScheduler::getAllFileContents
llvm::StringMap< std::string > getAllFileContents() const
Returns a snapshot of all file buffer contents, per last update().
Definition: TUScheduler.cpp:923
clang::clangd::TUScheduler::ASTCache::getUsedBytes
std::size_t getUsedBytes(Key K)
Returns result of getUsedBytes() for the AST cached by K.
Definition: TUScheduler.cpp:95
clang::clangd::TUScheduler::run
void run(llvm::StringRef Name, llvm::unique_function< void()> Action)
Schedule an async task with no dependencies.
Definition: TUScheduler.cpp:930