clang-tools  7.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 mantain a semaphore that
22 // 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 "Logger.h"
47 #include "Trace.h"
48 #include "clang/Frontend/CompilerInvocation.h"
49 #include "clang/Frontend/PCHContainerOperations.h"
50 #include "llvm/ADT/ScopeExit.h"
51 #include "llvm/Support/Errc.h"
52 #include "llvm/Support/Path.h"
53 #include <algorithm>
54 #include <memory>
55 #include <queue>
56 #include <thread>
57 
58 namespace clang {
59 namespace clangd {
60 using std::chrono::steady_clock;
61 
62 namespace {
63 class ASTWorker;
64 }
65 
66 /// An LRU cache of idle ASTs.
67 /// Because we want to limit the overall number of these we retain, the cache
68 /// owns ASTs (and may evict them) while their workers are idle.
69 /// Workers borrow ASTs when active, and return them when done.
71 public:
72  using Key = const ASTWorker *;
73 
74  ASTCache(unsigned MaxRetainedASTs) : MaxRetainedASTs(MaxRetainedASTs) {}
75 
76  /// Returns result of getUsedBytes() for the AST cached by \p K.
77  /// If no AST is cached, 0 is returned.
78  std::size_t getUsedBytes(Key K) {
79  std::lock_guard<std::mutex> Lock(Mut);
80  auto It = findByKey(K);
81  if (It == LRU.end() || !It->second)
82  return 0;
83  return It->second->getUsedBytes();
84  }
85 
86  /// Store the value in the pool, possibly removing the last used AST.
87  /// The value should not be in the pool when this function is called.
88  void put(Key K, std::unique_ptr<ParsedAST> V) {
89  std::unique_lock<std::mutex> Lock(Mut);
90  assert(findByKey(K) == LRU.end());
91 
92  LRU.insert(LRU.begin(), {K, std::move(V)});
93  if (LRU.size() <= MaxRetainedASTs)
94  return;
95  // We're past the limit, remove the last element.
96  std::unique_ptr<ParsedAST> ForCleanup = std::move(LRU.back().second);
97  LRU.pop_back();
98  // Run the expensive destructor outside the lock.
99  Lock.unlock();
100  ForCleanup.reset();
101  }
102 
103  /// Returns the cached value for \p K, or llvm::None if the value is not in
104  /// the cache anymore. If nullptr was cached for \p K, this function will
105  /// return a null unique_ptr wrapped into an optional.
106  llvm::Optional<std::unique_ptr<ParsedAST>> take(Key K) {
107  std::unique_lock<std::mutex> Lock(Mut);
108  auto Existing = findByKey(K);
109  if (Existing == LRU.end())
110  return llvm::None;
111  std::unique_ptr<ParsedAST> V = std::move(Existing->second);
112  LRU.erase(Existing);
113  // GCC 4.8 fails to compile `return V;`, as it tries to call the copy
114  // constructor of unique_ptr, so we call the move ctor explicitly to avoid
115  // this miscompile.
116  return llvm::Optional<std::unique_ptr<ParsedAST>>(std::move(V));
117  }
118 
119 private:
120  using KVPair = std::pair<Key, std::unique_ptr<ParsedAST>>;
121 
122  std::vector<KVPair>::iterator findByKey(Key K) {
123  return std::find_if(LRU.begin(), LRU.end(),
124  [K](const KVPair &P) { return P.first == K; });
125  }
126 
127  std::mutex Mut;
128  unsigned MaxRetainedASTs;
129  /// Items sorted in LRU order, i.e. first item is the most recently accessed
130  /// one.
131  std::vector<KVPair> LRU; /* GUARDED_BY(Mut) */
132 };
133 
134 namespace {
135 class ASTWorkerHandle;
136 
137 /// Owns one instance of the AST, schedules updates and reads of it.
138 /// Also responsible for building and providing access to the preamble.
139 /// Each ASTWorker processes the async requests sent to it on a separate
140 /// dedicated thread.
141 /// The ASTWorker that manages the AST is shared by both the processing thread
142 /// and the TUScheduler. The TUScheduler should discard an ASTWorker when
143 /// remove() is called, but its thread may be busy and we don't want to block.
144 /// So the workers are accessed via an ASTWorkerHandle. Destroying the handle
145 /// signals the worker to exit its run loop and gives up shared ownership of the
146 /// worker.
147 class ASTWorker {
148  friend class ASTWorkerHandle;
149  ASTWorker(PathRef FileName, TUScheduler::ASTCache &LRUCache,
150  Semaphore &Barrier, bool RunSync,
151  steady_clock::duration UpdateDebounce,
152  std::shared_ptr<PCHContainerOperations> PCHs,
153  bool StorePreamblesInMemory,
154  PreambleParsedCallback PreambleCallback);
155 
156 public:
157  /// Create a new ASTWorker and return a handle to it.
158  /// The processing thread is spawned using \p Tasks. However, when \p Tasks
159  /// is null, all requests will be processed on the calling thread
160  /// synchronously instead. \p Barrier is acquired when processing each
161  /// request, it is be used to limit the number of actively running threads.
162  static ASTWorkerHandle create(PathRef FileName,
163  TUScheduler::ASTCache &IdleASTs,
164  AsyncTaskRunner *Tasks, Semaphore &Barrier,
165  steady_clock::duration UpdateDebounce,
166  std::shared_ptr<PCHContainerOperations> PCHs,
167  bool StorePreamblesInMemory,
168  PreambleParsedCallback PreambleCallback);
169  ~ASTWorker();
170 
171  void update(ParseInputs Inputs, WantDiagnostics,
172  llvm::unique_function<void(std::vector<Diag>)> OnUpdated);
173  void
174  runWithAST(llvm::StringRef Name,
175  llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action);
176  bool blockUntilIdle(Deadline Timeout) const;
177 
178  std::shared_ptr<const PreambleData> getPossiblyStalePreamble() const;
179  /// Wait for the first build of preamble to finish. Preamble itself can be
180  /// accessed via getPossibleStalePreamble(). Note that this function will
181  /// return after an unsuccessful build of the preamble too, i.e. result of
182  /// getPossiblyStalePreamble() can be null even after this function returns.
183  void waitForFirstPreamble() const;
184 
185  std::size_t getUsedBytes() const;
186  bool isASTCached() const;
187 
188 private:
189  // Must be called exactly once on processing thread. Will return after
190  // stop() is called on a separate thread and all pending requests are
191  // processed.
192  void run();
193  /// Signal that run() should finish processing pending requests and exit.
194  void stop();
195  /// Adds a new task to the end of the request queue.
196  void startTask(llvm::StringRef Name, llvm::unique_function<void()> Task,
197  llvm::Optional<WantDiagnostics> UpdateType);
198  /// Determines the next action to perform.
199  /// All actions that should never run are disarded.
200  /// Returns a deadline for the next action. If it's expired, run now.
201  /// scheduleLocked() is called again at the deadline, or if requests arrive.
202  Deadline scheduleLocked();
203  /// Should the first task in the queue be skipped instead of run?
204  bool shouldSkipHeadLocked() const;
205 
206  struct Request {
207  llvm::unique_function<void()> Action;
208  std::string Name;
209  steady_clock::time_point AddTime;
210  Context Ctx;
211  llvm::Optional<WantDiagnostics> UpdateType;
212  };
213 
214  /// Handles retention of ASTs.
215  TUScheduler::ASTCache &IdleASTs;
216  const bool RunSync;
217  /// Time to wait after an update to see whether another update obsoletes it.
218  const steady_clock::duration UpdateDebounce;
219  /// File that ASTWorker is reponsible for.
220  const Path FileName;
221  /// Whether to keep the built preambles in memory or on disk.
222  const bool StorePreambleInMemory;
223  /// Callback, passed to the preamble builder.
224  const PreambleParsedCallback PreambleCallback;
225  /// Helper class required to build the ASTs.
226  const std::shared_ptr<PCHContainerOperations> PCHs;
227 
228  Semaphore &Barrier;
229  /// Inputs, corresponding to the current state of AST.
230  ParseInputs FileInputs;
231  /// Whether the diagnostics for the current FileInputs were reported to the
232  /// users before.
233  bool DiagsWereReported = false;
234  /// Size of the last AST
235  /// Guards members used by both TUScheduler and the worker thread.
236  mutable std::mutex Mutex;
237  std::shared_ptr<const PreambleData> LastBuiltPreamble; /* GUARDED_BY(Mutex) */
238  /// Becomes ready when the first preamble build finishes.
239  Notification PreambleWasBuilt;
240  /// Set to true to signal run() to finish processing.
241  bool Done; /* GUARDED_BY(Mutex) */
242  std::deque<Request> Requests; /* GUARDED_BY(Mutex) */
243  mutable std::condition_variable RequestsCV;
244 };
245 
246 /// A smart-pointer-like class that points to an active ASTWorker.
247 /// In destructor, signals to the underlying ASTWorker that no new requests will
248 /// be sent and the processing loop may exit (after running all pending
249 /// requests).
250 class ASTWorkerHandle {
251  friend class ASTWorker;
252  ASTWorkerHandle(std::shared_ptr<ASTWorker> Worker)
253  : Worker(std::move(Worker)) {
254  assert(this->Worker);
255  }
256 
257 public:
258  ASTWorkerHandle(const ASTWorkerHandle &) = delete;
259  ASTWorkerHandle &operator=(const ASTWorkerHandle &) = delete;
260  ASTWorkerHandle(ASTWorkerHandle &&) = default;
261  ASTWorkerHandle &operator=(ASTWorkerHandle &&) = default;
262 
263  ~ASTWorkerHandle() {
264  if (Worker)
265  Worker->stop();
266  }
267 
268  ASTWorker &operator*() {
269  assert(Worker && "Handle was moved from");
270  return *Worker;
271  }
272 
273  ASTWorker *operator->() {
274  assert(Worker && "Handle was moved from");
275  return Worker.get();
276  }
277 
278  /// Returns an owning reference to the underlying ASTWorker that can outlive
279  /// the ASTWorkerHandle. However, no new requests to an active ASTWorker can
280  /// be schedule via the returned reference, i.e. only reads of the preamble
281  /// are possible.
282  std::shared_ptr<const ASTWorker> lock() { return Worker; }
283 
284 private:
285  std::shared_ptr<ASTWorker> Worker;
286 };
287 
288 ASTWorkerHandle ASTWorker::create(PathRef FileName,
289  TUScheduler::ASTCache &IdleASTs,
290  AsyncTaskRunner *Tasks, Semaphore &Barrier,
291  steady_clock::duration UpdateDebounce,
292  std::shared_ptr<PCHContainerOperations> PCHs,
293  bool StorePreamblesInMemory,
294  PreambleParsedCallback PreambleCallback) {
295  std::shared_ptr<ASTWorker> Worker(new ASTWorker(
296  FileName, IdleASTs, Barrier, /*RunSync=*/!Tasks, UpdateDebounce,
297  std::move(PCHs), StorePreamblesInMemory, std::move(PreambleCallback)));
298  if (Tasks)
299  Tasks->runAsync("worker:" + llvm::sys::path::filename(FileName),
300  [Worker]() { Worker->run(); });
301 
302  return ASTWorkerHandle(std::move(Worker));
303 }
304 
305 ASTWorker::ASTWorker(PathRef FileName, TUScheduler::ASTCache &LRUCache,
306  Semaphore &Barrier, bool RunSync,
307  steady_clock::duration UpdateDebounce,
308  std::shared_ptr<PCHContainerOperations> PCHs,
309  bool StorePreamblesInMemory,
310  PreambleParsedCallback PreambleCallback)
311  : IdleASTs(LRUCache), RunSync(RunSync), UpdateDebounce(UpdateDebounce),
312  FileName(FileName), StorePreambleInMemory(StorePreamblesInMemory),
313  PreambleCallback(std::move(PreambleCallback)), PCHs(std::move(PCHs)),
314  Barrier(Barrier), Done(false) {}
315 
316 ASTWorker::~ASTWorker() {
317  // Make sure we remove the cached AST, if any.
318  IdleASTs.take(this);
319 #ifndef NDEBUG
320  std::lock_guard<std::mutex> Lock(Mutex);
321  assert(Done && "handle was not destroyed");
322  assert(Requests.empty() && "unprocessed requests when destroying ASTWorker");
323 #endif
324 }
325 
326 void ASTWorker::update(
327  ParseInputs Inputs, WantDiagnostics WantDiags,
328  llvm::unique_function<void(std::vector<Diag>)> OnUpdated) {
329  auto Task = [=](decltype(OnUpdated) OnUpdated) mutable {
330  // Will be used to check if we can avoid rebuilding the AST.
331  bool InputsAreTheSame =
332  std::tie(FileInputs.CompileCommand, FileInputs.Contents) ==
333  std::tie(Inputs.CompileCommand, Inputs.Contents);
334 
335  tooling::CompileCommand OldCommand = std::move(FileInputs.CompileCommand);
336  bool PrevDiagsWereReported = DiagsWereReported;
337  FileInputs = Inputs;
338  DiagsWereReported = false;
339 
340  log("Updating file {0} with command [{1}] {2}", FileName,
341  Inputs.CompileCommand.Directory,
342  llvm::join(Inputs.CompileCommand.CommandLine, " "));
343  // Rebuild the preamble and the AST.
344  std::unique_ptr<CompilerInvocation> Invocation =
345  buildCompilerInvocation(Inputs);
346  if (!Invocation) {
347  elog("Could not build CompilerInvocation for file {0}", FileName);
348  // Remove the old AST if it's still in cache.
349  IdleASTs.take(this);
350  // Make sure anyone waiting for the preamble gets notified it could not
351  // be built.
352  PreambleWasBuilt.notify();
353  return;
354  }
355 
356  std::shared_ptr<const PreambleData> OldPreamble =
357  getPossiblyStalePreamble();
358  std::shared_ptr<const PreambleData> NewPreamble =
359  buildPreamble(FileName, *Invocation, OldPreamble, OldCommand, Inputs,
360  PCHs, StorePreambleInMemory, PreambleCallback);
361 
362  bool CanReuseAST = InputsAreTheSame && (OldPreamble == NewPreamble);
363  {
364  std::lock_guard<std::mutex> Lock(Mutex);
365  if (NewPreamble)
366  LastBuiltPreamble = NewPreamble;
367  }
368  // Before doing the expensive AST reparse, we want to release our reference
369  // to the old preamble, so it can be freed if there are no other references
370  // to it.
371  OldPreamble.reset();
372  PreambleWasBuilt.notify();
373 
374  if (!CanReuseAST) {
375  IdleASTs.take(this); // Remove the old AST if it's still in cache.
376  } else {
377  // Since we don't need to rebuild the AST, we might've already reported
378  // the diagnostics for it.
379  if (PrevDiagsWereReported) {
380  DiagsWereReported = true;
381  // Take a shortcut and don't report the diagnostics, since they should
382  // not changed. All the clients should handle the lack of OnUpdated()
383  // call anyway to handle empty result from buildAST.
384  // FIXME(ibiryukov): the AST could actually change if non-preamble
385  // includes changed, but we choose to ignore it.
386  // FIXME(ibiryukov): should we refresh the cache in IdleASTs for the
387  // current file at this point?
388  log("Skipping rebuild of the AST for {0}, inputs are the same.",
389  FileName);
390  return;
391  }
392  }
393 
394  // We only need to build the AST if diagnostics were requested.
395  if (WantDiags == WantDiagnostics::No)
396  return;
397 
398  // Get the AST for diagnostics.
399  llvm::Optional<std::unique_ptr<ParsedAST>> AST = IdleASTs.take(this);
400  if (!AST) {
401  llvm::Optional<ParsedAST> NewAST =
402  buildAST(FileName, std::move(Invocation), Inputs, NewPreamble, PCHs);
403  AST = NewAST ? llvm::make_unique<ParsedAST>(std::move(*NewAST)) : nullptr;
404  }
405  // We want to report the diagnostics even if this update was cancelled.
406  // It seems more useful than making the clients wait indefinitely if they
407  // spam us with updates.
408  // Note *AST can be still be null if buildAST fails.
409  if (*AST) {
410  OnUpdated((*AST)->getDiagnostics());
411  DiagsWereReported = true;
412  }
413  // Stash the AST in the cache for further use.
414  IdleASTs.put(this, std::move(*AST));
415  };
416 
417  startTask("Update", Bind(Task, std::move(OnUpdated)), WantDiags);
418 }
419 
420 void ASTWorker::runWithAST(
421  llvm::StringRef Name,
422  llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action) {
423  auto Task = [=](decltype(Action) Action) {
424  llvm::Optional<std::unique_ptr<ParsedAST>> AST = IdleASTs.take(this);
425  if (!AST) {
426  std::unique_ptr<CompilerInvocation> Invocation =
427  buildCompilerInvocation(FileInputs);
428  // Try rebuilding the AST.
429  llvm::Optional<ParsedAST> NewAST =
430  Invocation
431  ? buildAST(FileName,
432  llvm::make_unique<CompilerInvocation>(*Invocation),
433  FileInputs, getPossiblyStalePreamble(), PCHs)
434  : llvm::None;
435  AST = NewAST ? llvm::make_unique<ParsedAST>(std::move(*NewAST)) : nullptr;
436  }
437  // Make sure we put the AST back into the LRU cache.
438  auto _ = llvm::make_scope_exit(
439  [&AST, this]() { IdleASTs.put(this, std::move(*AST)); });
440  // Run the user-provided action.
441  if (!*AST)
442  return Action(llvm::make_error<llvm::StringError>(
443  "invalid AST", llvm::errc::invalid_argument));
444  Action(InputsAndAST{FileInputs, **AST});
445  };
446  startTask(Name, Bind(Task, std::move(Action)),
447  /*UpdateType=*/llvm::None);
448 }
449 
450 std::shared_ptr<const PreambleData>
451 ASTWorker::getPossiblyStalePreamble() const {
452  std::lock_guard<std::mutex> Lock(Mutex);
453  return LastBuiltPreamble;
454 }
455 
456 void ASTWorker::waitForFirstPreamble() const {
457  PreambleWasBuilt.wait();
458 }
459 
460 std::size_t ASTWorker::getUsedBytes() const {
461  // Note that we don't report the size of ASTs currently used for processing
462  // the in-flight requests. We used this information for debugging purposes
463  // only, so this should be fine.
464  std::size_t Result = IdleASTs.getUsedBytes(this);
465  if (auto Preamble = getPossiblyStalePreamble())
466  Result += Preamble->Preamble.getSize();
467  return Result;
468 }
469 
470 bool ASTWorker::isASTCached() const { return IdleASTs.getUsedBytes(this) != 0; }
471 
472 void ASTWorker::stop() {
473  {
474  std::lock_guard<std::mutex> Lock(Mutex);
475  assert(!Done && "stop() called twice");
476  Done = true;
477  }
478  RequestsCV.notify_all();
479 }
480 
481 void ASTWorker::startTask(llvm::StringRef Name,
482  llvm::unique_function<void()> Task,
483  llvm::Optional<WantDiagnostics> UpdateType) {
484  if (RunSync) {
485  assert(!Done && "running a task after stop()");
486  trace::Span Tracer(Name + ":" + llvm::sys::path::filename(FileName));
487  Task();
488  return;
489  }
490 
491  {
492  std::lock_guard<std::mutex> Lock(Mutex);
493  assert(!Done && "running a task after stop()");
494  Requests.push_back({std::move(Task), Name, steady_clock::now(),
495  Context::current().clone(), UpdateType});
496  }
497  RequestsCV.notify_all();
498 }
499 
500 void ASTWorker::run() {
501  while (true) {
502  Request Req;
503  {
504  std::unique_lock<std::mutex> Lock(Mutex);
505  for (auto Wait = scheduleLocked(); !Wait.expired();
506  Wait = scheduleLocked()) {
507  if (Done) {
508  if (Requests.empty())
509  return;
510  else // Even though Done is set, finish pending requests.
511  break; // However, skip delays to shutdown fast.
512  }
513 
514  // Tracing: we have a next request, attribute this sleep to it.
515  Optional<WithContext> Ctx;
516  Optional<trace::Span> Tracer;
517  if (!Requests.empty()) {
518  Ctx.emplace(Requests.front().Ctx.clone());
519  Tracer.emplace("Debounce");
520  SPAN_ATTACH(*Tracer, "next_request", Requests.front().Name);
521  if (!(Wait == Deadline::infinity()))
522  SPAN_ATTACH(*Tracer, "sleep_ms",
523  std::chrono::duration_cast<std::chrono::milliseconds>(
524  Wait.time() - steady_clock::now())
525  .count());
526  }
527 
528  wait(Lock, RequestsCV, Wait);
529  }
530  Req = std::move(Requests.front());
531  // Leave it on the queue for now, so waiters don't see an empty queue.
532  } // unlock Mutex
533 
534  {
535  std::lock_guard<Semaphore> BarrierLock(Barrier);
536  WithContext Guard(std::move(Req.Ctx));
537  trace::Span Tracer(Req.Name);
538  Req.Action();
539  }
540 
541  {
542  std::lock_guard<std::mutex> Lock(Mutex);
543  Requests.pop_front();
544  }
545  RequestsCV.notify_all();
546  }
547 }
548 
549 Deadline ASTWorker::scheduleLocked() {
550  if (Requests.empty())
551  return Deadline::infinity(); // Wait for new requests.
552  while (shouldSkipHeadLocked())
553  Requests.pop_front();
554  assert(!Requests.empty() && "skipped the whole queue");
555  // Some updates aren't dead yet, but never end up being used.
556  // e.g. the first keystroke is live until obsoleted by the second.
557  // We debounce "maybe-unused" writes, sleeping 500ms in case they become dead.
558  // But don't delay reads (including updates where diagnostics are needed).
559  for (const auto &R : Requests)
560  if (R.UpdateType == None || R.UpdateType == WantDiagnostics::Yes)
561  return Deadline::zero();
562  // Front request needs to be debounced, so determine when we're ready.
563  Deadline D(Requests.front().AddTime + UpdateDebounce);
564  return D;
565 }
566 
567 // Returns true if Requests.front() is a dead update that can be skipped.
568 bool ASTWorker::shouldSkipHeadLocked() const {
569  assert(!Requests.empty());
570  auto Next = Requests.begin();
571  auto UpdateType = Next->UpdateType;
572  if (!UpdateType) // Only skip updates.
573  return false;
574  ++Next;
575  // An update is live if its AST might still be read.
576  // That is, if it's not immediately followed by another update.
577  if (Next == Requests.end() || !Next->UpdateType)
578  return false;
579  // The other way an update can be live is if its diagnostics might be used.
580  switch (*UpdateType) {
582  return false; // Always used.
583  case WantDiagnostics::No:
584  return true; // Always dead.
586  // Used unless followed by an update that generates diagnostics.
587  for (; Next != Requests.end(); ++Next)
588  if (Next->UpdateType == WantDiagnostics::Yes ||
589  Next->UpdateType == WantDiagnostics::Auto)
590  return true; // Prefer later diagnostics.
591  return false;
592  }
593  llvm_unreachable("Unknown WantDiagnostics");
594 }
595 
596 bool ASTWorker::blockUntilIdle(Deadline Timeout) const {
597  std::unique_lock<std::mutex> Lock(Mutex);
598  return wait(Lock, RequestsCV, Timeout, [&] { return Requests.empty(); });
599 }
600 
601 } // namespace
602 
604  unsigned HardwareConcurrency = std::thread::hardware_concurrency();
605  // C++ standard says that hardware_concurrency()
606  // may return 0, fallback to 1 worker thread in
607  // that case.
608  if (HardwareConcurrency == 0)
609  return 1;
610  return HardwareConcurrency;
611 }
612 
614  /// Latest inputs, passed to TUScheduler::update().
615  std::string Contents;
616  tooling::CompileCommand Command;
617  ASTWorkerHandle Worker;
618 };
619 
620 TUScheduler::TUScheduler(unsigned AsyncThreadsCount,
621  bool StorePreamblesInMemory,
622  PreambleParsedCallback PreambleCallback,
623  std::chrono::steady_clock::duration UpdateDebounce,
624  ASTRetentionPolicy RetentionPolicy)
625  : StorePreamblesInMemory(StorePreamblesInMemory),
626  PCHOps(std::make_shared<PCHContainerOperations>()),
627  PreambleCallback(std::move(PreambleCallback)), Barrier(AsyncThreadsCount),
628  IdleASTs(llvm::make_unique<ASTCache>(RetentionPolicy.MaxRetainedASTs)),
629  UpdateDebounce(UpdateDebounce) {
630  if (0 < AsyncThreadsCount) {
631  PreambleTasks.emplace();
632  WorkerThreads.emplace();
633  }
634 }
635 
637  // Notify all workers that they need to stop.
638  Files.clear();
639 
640  // Wait for all in-flight tasks to finish.
641  if (PreambleTasks)
642  PreambleTasks->wait();
643  if (WorkerThreads)
644  WorkerThreads->wait();
645 }
646 
648  for (auto &File : Files)
649  if (!File.getValue()->Worker->blockUntilIdle(D))
650  return false;
651  if (PreambleTasks)
652  if (!PreambleTasks->wait(D))
653  return false;
654  return true;
655 }
656 
658  PathRef File, ParseInputs Inputs, WantDiagnostics WantDiags,
659  llvm::unique_function<void(std::vector<Diag>)> OnUpdated) {
660  std::unique_ptr<FileData> &FD = Files[File];
661  if (!FD) {
662  // Create a new worker to process the AST-related tasks.
663  ASTWorkerHandle Worker = ASTWorker::create(
664  File, *IdleASTs, WorkerThreads ? WorkerThreads.getPointer() : nullptr,
665  Barrier, UpdateDebounce, PCHOps, StorePreamblesInMemory,
666  PreambleCallback);
667  FD = std::unique_ptr<FileData>(new FileData{
668  Inputs.Contents, Inputs.CompileCommand, std::move(Worker)});
669  } else {
670  FD->Contents = Inputs.Contents;
671  FD->Command = Inputs.CompileCommand;
672  }
673  FD->Worker->update(std::move(Inputs), WantDiags, std::move(OnUpdated));
674 }
675 
677  bool Removed = Files.erase(File);
678  if (!Removed)
679  elog("Trying to remove file from TUScheduler that is not tracked: {0}",
680  File);
681 }
682 
684  llvm::StringRef Name, PathRef File,
685  llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action) {
686  auto It = Files.find(File);
687  if (It == Files.end()) {
688  Action(llvm::make_error<llvm::StringError>(
689  "trying to get AST for non-added document",
690  llvm::errc::invalid_argument));
691  return;
692  }
693 
694  It->second->Worker->runWithAST(Name, std::move(Action));
695 }
696 
698  llvm::StringRef Name, PathRef File,
699  llvm::unique_function<void(llvm::Expected<InputsAndPreamble>)> Action) {
700  auto It = Files.find(File);
701  if (It == Files.end()) {
702  Action(llvm::make_error<llvm::StringError>(
703  "trying to get preamble for non-added document",
704  llvm::errc::invalid_argument));
705  return;
706  }
707 
708  if (!PreambleTasks) {
709  trace::Span Tracer(Name);
710  SPAN_ATTACH(Tracer, "file", File);
711  std::shared_ptr<const PreambleData> Preamble =
712  It->second->Worker->getPossiblyStalePreamble();
713  Action(InputsAndPreamble{It->second->Contents, It->second->Command,
714  Preamble.get()});
715  return;
716  }
717 
718  std::shared_ptr<const ASTWorker> Worker = It->second->Worker.lock();
719  auto Task = [Worker, this](std::string Name, std::string File,
720  std::string Contents,
721  tooling::CompileCommand Command, Context Ctx,
722  decltype(Action) Action) mutable {
723  // We don't want to be running preamble actions before the preamble was
724  // built for the first time. This avoids extra work of processing the
725  // preamble headers in parallel multiple times.
726  Worker->waitForFirstPreamble();
727 
728  std::lock_guard<Semaphore> BarrierLock(Barrier);
729  WithContext Guard(std::move(Ctx));
730  trace::Span Tracer(Name);
731  SPAN_ATTACH(Tracer, "file", File);
732  std::shared_ptr<const PreambleData> Preamble =
733  Worker->getPossiblyStalePreamble();
734  Action(InputsAndPreamble{Contents, Command, Preamble.get()});
735  };
736 
737  PreambleTasks->runAsync("task:" + llvm::sys::path::filename(File),
738  Bind(Task, std::string(Name), std::string(File),
739  It->second->Contents, It->second->Command,
740  Context::current().clone(), std::move(Action)));
741 }
742 
743 std::vector<std::pair<Path, std::size_t>>
745  std::vector<std::pair<Path, std::size_t>> Result;
746  Result.reserve(Files.size());
747  for (auto &&PathAndFile : Files)
748  Result.push_back(
749  {PathAndFile.first(), PathAndFile.second->Worker->getUsedBytes()});
750  return Result;
751 }
752 
753 std::vector<Path> TUScheduler::getFilesWithCachedAST() const {
754  std::vector<Path> Result;
755  for (auto &&PathAndFile : Files) {
756  if (!PathAndFile.second->Worker->isASTCached())
757  continue;
758  Result.push_back(PathAndFile.first());
759  }
760  return Result;
761 }
762 
763 } // namespace clangd
764 } // namespace clang
const tooling::CompileCommand & Command
WantDiagnostics
Determines whether diagnostics should be generated for a file snapshot.
Definition: TUScheduler.h:38
Some operations such as code completion produce a set of candidates.
Diagnostics must be generated for this snapshot.
std::function< void(PathRef Path, ASTContext &, std::shared_ptr< clang::Preprocessor >)> PreambleParsedCallback
Definition: ClangdUnit.h:131
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:357
void remove(PathRef File)
Remove File from the list of tracked files and schedule removal of its resources. ...
llvm::StringRef PathRef
A typedef to represent a ref to file path.
Definition: Path.h:24
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
void elog(const char *Fmt, Ts &&... Vals)
Definition: Logger.h:56
StringRef Contents
Configuration of the AST retention policy.
Definition: TUScheduler.h:48
Context Ctx
Context clone() const
Clone this context object.
Definition: Context.cpp:21
std::unique_ptr< Iterator > create(PostingListRef Documents)
Returns a document iterator over given PostingList.
Definition: Iterator.cpp:228
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:61
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.
Definition: TUScheduler.cpp:88
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:267
tooling::CompileCommand CompileCommand
Definition: ClangdUnit.h:60
std::vector< std::pair< Path, std::size_t > > getUsedBytesPerFile() const
Returns estimated memory usage for each of the currently open files.
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:294
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:90
Runs tasks on separate (detached) threads and wait for all tasks to finish.
Definition: Threading.h:103
PrecompiledPreamble const * Preamble
A context is an immutable container for per-request data that must be propagated through layers that ...
Definition: Context.h:70
std::string Name
void update(PathRef File, ParseInputs Inputs, WantDiagnostics WD, llvm::unique_function< void(std::vector< Diag >)> OnUpdated)
Schedule an update for File.
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:59
ASTCache(unsigned MaxRetainedASTs)
Definition: TUScheduler.cpp:74
void runWithPreamble(llvm::StringRef Name, PathRef File, Callback< InputsAndPreamble > Action)
Schedule an async read of the Preamble.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static Deadline zero()
Definition: Threading.h:60
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
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:56
static std::string join(ArrayRef< SpecialMemberFunctionsCheck::SpecialMemberFunctionKind > SMFS, llvm::StringRef AndOr)
An LRU cache of idle ASTs.
Definition: TUScheduler.cpp:70
Records an event whose duration is the lifetime of the Span object.
Definition: Trace.h:83
TUScheduler(unsigned AsyncThreadsCount, bool StorePreamblesInMemory, PreambleParsedCallback PreambleCallback, std::chrono::steady_clock::duration UpdateDebounce, ASTRetentionPolicy RetentionPolicy)
#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.
std::size_t getUsedBytes(Key K)
Returns result of getUsedBytes() for the AST cached by K.
Definition: TUScheduler.cpp:78