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