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