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