Mercurial > hg > CbC > CbC_llvm
comparison clang-tools-extra/clangd/TUScheduler.cpp @ 221:79ff65ed7e25
LLVM12 Original
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Tue, 15 Jun 2021 19:15:29 +0900 |
parents | 0572611fdcc8 |
children | 5f17cb93ff66 |
comparison
equal
deleted
inserted
replaced
220:42394fc6a535 | 221:79ff65ed7e25 |
---|---|
54 #include "Preamble.h" | 54 #include "Preamble.h" |
55 #include "index/CanonicalIncludes.h" | 55 #include "index/CanonicalIncludes.h" |
56 #include "support/Cancellation.h" | 56 #include "support/Cancellation.h" |
57 #include "support/Context.h" | 57 #include "support/Context.h" |
58 #include "support/Logger.h" | 58 #include "support/Logger.h" |
59 #include "support/MemoryTree.h" | |
59 #include "support/Path.h" | 60 #include "support/Path.h" |
60 #include "support/Threading.h" | 61 #include "support/Threading.h" |
61 #include "support/Trace.h" | 62 #include "support/Trace.h" |
62 #include "clang/Frontend/CompilerInvocation.h" | 63 #include "clang/Frontend/CompilerInvocation.h" |
63 #include "clang/Tooling/CompilationDatabase.h" | 64 #include "clang/Tooling/CompilationDatabase.h" |
67 #include "llvm/ADT/STLExtras.h" | 68 #include "llvm/ADT/STLExtras.h" |
68 #include "llvm/ADT/ScopeExit.h" | 69 #include "llvm/ADT/ScopeExit.h" |
69 #include "llvm/ADT/SmallVector.h" | 70 #include "llvm/ADT/SmallVector.h" |
70 #include "llvm/ADT/StringExtras.h" | 71 #include "llvm/ADT/StringExtras.h" |
71 #include "llvm/ADT/StringRef.h" | 72 #include "llvm/ADT/StringRef.h" |
73 #include "llvm/Support/Allocator.h" | |
72 #include "llvm/Support/Errc.h" | 74 #include "llvm/Support/Errc.h" |
73 #include "llvm/Support/ErrorHandling.h" | 75 #include "llvm/Support/ErrorHandling.h" |
74 #include "llvm/Support/FormatVariadic.h" | 76 #include "llvm/Support/FormatVariadic.h" |
75 #include "llvm/Support/Path.h" | 77 #include "llvm/Support/Path.h" |
76 #include "llvm/Support/Threading.h" | 78 #include "llvm/Support/Threading.h" |
77 #include <algorithm> | 79 #include <algorithm> |
80 #include <atomic> | |
78 #include <chrono> | 81 #include <chrono> |
82 #include <condition_variable> | |
79 #include <functional> | 83 #include <functional> |
80 #include <memory> | 84 #include <memory> |
81 #include <mutex> | 85 #include <mutex> |
82 #include <queue> | 86 #include <queue> |
83 #include <string> | 87 #include <string> |
175 /// Items sorted in LRU order, i.e. first item is the most recently accessed | 179 /// Items sorted in LRU order, i.e. first item is the most recently accessed |
176 /// one. | 180 /// one. |
177 std::vector<KVPair> LRU; /* GUARDED_BY(Mut) */ | 181 std::vector<KVPair> LRU; /* GUARDED_BY(Mut) */ |
178 }; | 182 }; |
179 | 183 |
184 /// A map from header files to an opened "proxy" file that includes them. | |
185 /// If you open the header, the compile command from the proxy file is used. | |
186 /// | |
187 /// This inclusion information could also naturally live in the index, but there | |
188 /// are advantages to using open files instead: | |
189 /// - it's easier to achieve a *stable* choice of proxy, which is important | |
190 /// to avoid invalidating the preamble | |
191 /// - context-sensitive flags for libraries with multiple configurations | |
192 /// (e.g. C++ stdlib sensitivity to -std version) | |
193 /// - predictable behavior, e.g. guarantees that go-to-def landing on a header | |
194 /// will have a suitable command available | |
195 /// - fewer scaling problems to solve (project include graphs are big!) | |
196 /// | |
197 /// Implementation details: | |
198 /// - We only record this for mainfiles where the command was trustworthy | |
199 /// (i.e. not inferred). This avoids a bad inference "infecting" other files. | |
200 /// - Once we've picked a proxy file for a header, we stick with it until the | |
201 /// proxy file is invalidated *and* a new candidate proxy file is built. | |
202 /// Switching proxies is expensive, as the compile flags will (probably) | |
203 /// change and therefore we'll end up rebuilding the header's preamble. | |
204 /// - We don't capture the actual compile command, but just the filename we | |
205 /// should query to get it. This avoids getting out of sync with the CDB. | |
206 /// | |
207 /// All methods are threadsafe. In practice, update() comes from preamble | |
208 /// threads, remove()s mostly from the main thread, and get() from ASTWorker. | |
209 /// Writes are rare and reads are cheap, so we don't expect much contention. | |
210 class TUScheduler::HeaderIncluderCache { | |
211 // We should be be a little careful how we store the include graph of open | |
212 // files, as each can have a large number of transitive headers. | |
213 // This representation is O(unique transitive source files). | |
214 llvm::BumpPtrAllocator Arena; | |
215 struct Association { | |
216 llvm::StringRef MainFile; | |
217 // Circular-linked-list of associations with the same mainFile. | |
218 // Null indicates that the mainfile was removed. | |
219 Association *Next; | |
220 }; | |
221 llvm::StringMap<Association, llvm::BumpPtrAllocator &> HeaderToMain; | |
222 llvm::StringMap<Association *, llvm::BumpPtrAllocator &> MainToFirst; | |
223 std::atomic<size_t> UsedBytes; // Updated after writes. | |
224 mutable std::mutex Mu; | |
225 | |
226 void invalidate(Association *First) { | |
227 Association *Current = First; | |
228 do { | |
229 Association *Next = Current->Next; | |
230 Current->Next = nullptr; | |
231 Current = Next; | |
232 } while (Current != First); | |
233 } | |
234 | |
235 // Create the circular list and return the head of it. | |
236 Association *associate(llvm::StringRef MainFile, | |
237 llvm::ArrayRef<std::string> Headers) { | |
238 Association *First = nullptr, *Prev = nullptr; | |
239 for (const std::string &Header : Headers) { | |
240 auto &Assoc = HeaderToMain[Header]; | |
241 if (Assoc.Next) | |
242 continue; // Already has a valid association. | |
243 | |
244 Assoc.MainFile = MainFile; | |
245 Assoc.Next = Prev; | |
246 Prev = &Assoc; | |
247 if (!First) | |
248 First = &Assoc; | |
249 } | |
250 if (First) | |
251 First->Next = Prev; | |
252 return First; | |
253 } | |
254 | |
255 void updateMemoryUsage() { | |
256 auto StringMapHeap = [](const auto &Map) { | |
257 // StringMap stores the hashtable on the heap. | |
258 // It contains pointers to the entries, and a hashcode for each. | |
259 return Map.getNumBuckets() * (sizeof(void *) + sizeof(unsigned)); | |
260 }; | |
261 size_t Usage = Arena.getTotalMemory() + StringMapHeap(MainToFirst) + | |
262 StringMapHeap(HeaderToMain) + sizeof(*this); | |
263 UsedBytes.store(Usage, std::memory_order_release); | |
264 } | |
265 | |
266 public: | |
267 HeaderIncluderCache() : HeaderToMain(Arena), MainToFirst(Arena) { | |
268 updateMemoryUsage(); | |
269 } | |
270 | |
271 // Associate each header with MainFile (unless already associated). | |
272 // Headers not in the list will have their associations removed. | |
273 void update(PathRef MainFile, llvm::ArrayRef<std::string> Headers) { | |
274 std::lock_guard<std::mutex> Lock(Mu); | |
275 auto It = MainToFirst.try_emplace(MainFile, nullptr); | |
276 Association *&First = It.first->second; | |
277 if (First) | |
278 invalidate(First); | |
279 First = associate(It.first->first(), Headers); | |
280 updateMemoryUsage(); | |
281 } | |
282 | |
283 // Mark MainFile as gone. | |
284 // This will *not* disassociate headers with MainFile immediately, but they | |
285 // will be eligible for association with other files that get update()d. | |
286 void remove(PathRef MainFile) { | |
287 std::lock_guard<std::mutex> Lock(Mu); | |
288 Association *&First = MainToFirst[MainFile]; | |
289 if (First) | |
290 invalidate(First); | |
291 } | |
292 | |
293 /// Get the mainfile associated with Header, or the empty string if none. | |
294 std::string get(PathRef Header) const { | |
295 std::lock_guard<std::mutex> Lock(Mu); | |
296 return HeaderToMain.lookup(Header).MainFile.str(); | |
297 } | |
298 | |
299 size_t getUsedBytes() const { | |
300 return UsedBytes.load(std::memory_order_acquire); | |
301 } | |
302 }; | |
303 | |
180 namespace { | 304 namespace { |
305 | |
306 bool isReliable(const tooling::CompileCommand &Cmd) { | |
307 return Cmd.Heuristic.empty(); | |
308 } | |
309 | |
181 /// Threadsafe manager for updating a TUStatus and emitting it after each | 310 /// Threadsafe manager for updating a TUStatus and emitting it after each |
182 /// update. | 311 /// update. |
183 class SynchronizedTUStatus { | 312 class SynchronizedTUStatus { |
184 public: | 313 public: |
185 SynchronizedTUStatus(PathRef FileName, ParsingCallbacks &Callbacks) | 314 SynchronizedTUStatus(PathRef FileName, ParsingCallbacks &Callbacks) |
217 /// instead. | 346 /// instead. |
218 class PreambleThread { | 347 class PreambleThread { |
219 public: | 348 public: |
220 PreambleThread(llvm::StringRef FileName, ParsingCallbacks &Callbacks, | 349 PreambleThread(llvm::StringRef FileName, ParsingCallbacks &Callbacks, |
221 bool StorePreambleInMemory, bool RunSync, | 350 bool StorePreambleInMemory, bool RunSync, |
222 SynchronizedTUStatus &Status, ASTWorker &AW) | 351 SynchronizedTUStatus &Status, |
352 TUScheduler::HeaderIncluderCache &HeaderIncluders, | |
353 ASTWorker &AW) | |
223 : FileName(FileName), Callbacks(Callbacks), | 354 : FileName(FileName), Callbacks(Callbacks), |
224 StoreInMemory(StorePreambleInMemory), RunSync(RunSync), Status(Status), | 355 StoreInMemory(StorePreambleInMemory), RunSync(RunSync), Status(Status), |
225 ASTPeer(AW) {} | 356 ASTPeer(AW), HeaderIncluders(HeaderIncluders) {} |
226 | 357 |
227 /// It isn't guaranteed that each requested version will be built. If there | 358 /// It isn't guaranteed that each requested version will be built. If there |
228 /// are multiple update requests while building a preamble, only the last one | 359 /// are multiple update requests while building a preamble, only the last one |
229 /// will be built. | 360 /// will be built. |
230 void update(std::unique_ptr<CompilerInvocation> CI, ParseInputs PI, | 361 void update(std::unique_ptr<CompilerInvocation> CI, ParseInputs PI, |
237 Status.PreambleActivity = PreambleAction::Idle; | 368 Status.PreambleActivity = PreambleAction::Idle; |
238 }); | 369 }); |
239 return; | 370 return; |
240 } | 371 } |
241 { | 372 { |
242 std::lock_guard<std::mutex> Lock(Mutex); | 373 std::unique_lock<std::mutex> Lock(Mutex); |
243 // If shutdown is issued, don't bother building. | 374 // If NextReq was requested with WantDiagnostics::Yes we cannot just drop |
244 if (Done) | 375 // that on the floor. Block until we start building it. This won't |
245 return; | 376 // dead-lock as we are blocking the caller thread, while builds continue |
377 // on preamble thread. | |
378 ReqCV.wait(Lock, [this] { | |
379 return !NextReq || NextReq->WantDiags != WantDiagnostics::Yes; | |
380 }); | |
246 NextReq = std::move(Req); | 381 NextReq = std::move(Req); |
247 } | 382 } |
248 // Let the worker thread know there's a request, notify_one is safe as there | 383 // Let the worker thread know there's a request, notify_one is safe as there |
249 // should be a single worker thread waiting on it. | 384 // should be a single worker thread waiting on it. |
250 ReqCV.notify_all(); | 385 ReqCV.notify_all(); |
263 NextReq.reset(); | 398 NextReq.reset(); |
264 } | 399 } |
265 | 400 |
266 { | 401 { |
267 WithContext Guard(std::move(CurrentReq->Ctx)); | 402 WithContext Guard(std::move(CurrentReq->Ctx)); |
403 // Note that we don't make use of the ContextProvider here. | |
404 // Preamble tasks are always scheduled by ASTWorker tasks, and we | |
405 // reuse the context/config that was created at that level. | |
406 | |
268 // Build the preamble and let the waiters know about it. | 407 // Build the preamble and let the waiters know about it. |
269 build(std::move(*CurrentReq)); | 408 build(std::move(*CurrentReq)); |
270 } | 409 } |
271 bool IsEmpty = false; | 410 bool IsEmpty = false; |
272 { | 411 { |
339 const bool StoreInMemory; | 478 const bool StoreInMemory; |
340 const bool RunSync; | 479 const bool RunSync; |
341 | 480 |
342 SynchronizedTUStatus &Status; | 481 SynchronizedTUStatus &Status; |
343 ASTWorker &ASTPeer; | 482 ASTWorker &ASTPeer; |
483 TUScheduler::HeaderIncluderCache &HeaderIncluders; | |
344 }; | 484 }; |
345 | 485 |
346 class ASTWorkerHandle; | 486 class ASTWorkerHandle; |
347 | 487 |
348 /// Owns one instance of the AST, schedules updates and reads of it. | 488 /// Owns one instance of the AST, schedules updates and reads of it. |
356 /// signals the worker to exit its run loop and gives up shared ownership of the | 496 /// signals the worker to exit its run loop and gives up shared ownership of the |
357 /// worker. | 497 /// worker. |
358 class ASTWorker { | 498 class ASTWorker { |
359 friend class ASTWorkerHandle; | 499 friend class ASTWorkerHandle; |
360 ASTWorker(PathRef FileName, const GlobalCompilationDatabase &CDB, | 500 ASTWorker(PathRef FileName, const GlobalCompilationDatabase &CDB, |
361 TUScheduler::ASTCache &LRUCache, Semaphore &Barrier, bool RunSync, | 501 TUScheduler::ASTCache &LRUCache, |
362 DebouncePolicy UpdateDebounce, bool StorePreamblesInMemory, | 502 TUScheduler::HeaderIncluderCache &HeaderIncluders, |
503 Semaphore &Barrier, bool RunSync, const TUScheduler::Options &Opts, | |
363 ParsingCallbacks &Callbacks); | 504 ParsingCallbacks &Callbacks); |
364 | 505 |
365 public: | 506 public: |
366 /// Create a new ASTWorker and return a handle to it. | 507 /// Create a new ASTWorker and return a handle to it. |
367 /// The processing thread is spawned using \p Tasks. However, when \p Tasks | 508 /// The processing thread is spawned using \p Tasks. However, when \p Tasks |
368 /// is null, all requests will be processed on the calling thread | 509 /// is null, all requests will be processed on the calling thread |
369 /// synchronously instead. \p Barrier is acquired when processing each | 510 /// synchronously instead. \p Barrier is acquired when processing each |
370 /// request, it is used to limit the number of actively running threads. | 511 /// request, it is used to limit the number of actively running threads. |
371 static ASTWorkerHandle | 512 static ASTWorkerHandle |
372 create(PathRef FileName, const GlobalCompilationDatabase &CDB, | 513 create(PathRef FileName, const GlobalCompilationDatabase &CDB, |
373 TUScheduler::ASTCache &IdleASTs, AsyncTaskRunner *Tasks, | 514 TUScheduler::ASTCache &IdleASTs, |
374 Semaphore &Barrier, DebouncePolicy UpdateDebounce, | 515 TUScheduler::HeaderIncluderCache &HeaderIncluders, |
375 bool StorePreamblesInMemory, ParsingCallbacks &Callbacks); | 516 AsyncTaskRunner *Tasks, Semaphore &Barrier, |
517 const TUScheduler::Options &Opts, ParsingCallbacks &Callbacks); | |
376 ~ASTWorker(); | 518 ~ASTWorker(); |
377 | 519 |
378 void update(ParseInputs Inputs, WantDiagnostics); | 520 void update(ParseInputs Inputs, WantDiagnostics, bool ContentChanged); |
379 void | 521 void |
380 runWithAST(llvm::StringRef Name, | 522 runWithAST(llvm::StringRef Name, |
381 llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action, | 523 llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action, |
382 TUScheduler::ASTActionInvalidation); | 524 TUScheduler::ASTActionInvalidation); |
383 bool blockUntilIdle(Deadline Timeout) const; | 525 bool blockUntilIdle(Deadline Timeout) const; |
384 | 526 |
385 std::shared_ptr<const PreambleData> getPossiblyStalePreamble() const; | 527 std::shared_ptr<const PreambleData> getPossiblyStalePreamble( |
528 std::shared_ptr<const ASTSignals> *ASTSignals = nullptr) const; | |
386 | 529 |
387 /// Used to inform ASTWorker about a new preamble build by PreambleThread. | 530 /// Used to inform ASTWorker about a new preamble build by PreambleThread. |
388 /// Diagnostics are only published through this callback. This ensures they | 531 /// Diagnostics are only published through this callback. This ensures they |
389 /// are always for newer versions of the file, as the callback gets called in | 532 /// are always for newer versions of the file, as the callback gets called in |
390 /// the same order as update requests. | 533 /// the same order as update requests. |
407 | 550 |
408 TUScheduler::FileStats stats() const; | 551 TUScheduler::FileStats stats() const; |
409 bool isASTCached() const; | 552 bool isASTCached() const; |
410 | 553 |
411 private: | 554 private: |
555 // Details of an update request that are relevant to scheduling. | |
556 struct UpdateType { | |
557 // Do we want diagnostics from this version? | |
558 // If Yes, we must always build this version. | |
559 // If No, we only need to build this version if it's read. | |
560 // If Auto, we build if it's read or if the debounce expires. | |
561 WantDiagnostics Diagnostics; | |
562 // Did the main-file content of the document change? | |
563 // If so, we're allowed to cancel certain invalidated preceding reads. | |
564 bool ContentChanged; | |
565 }; | |
566 | |
412 /// Publishes diagnostics for \p Inputs. It will build an AST or reuse the | 567 /// Publishes diagnostics for \p Inputs. It will build an AST or reuse the |
413 /// cached one if applicable. Assumes LatestPreamble is compatible for \p | 568 /// cached one if applicable. Assumes LatestPreamble is compatible for \p |
414 /// Inputs. | 569 /// Inputs. |
415 void generateDiagnostics(std::unique_ptr<CompilerInvocation> Invocation, | 570 void generateDiagnostics(std::unique_ptr<CompilerInvocation> Invocation, |
416 ParseInputs Inputs, std::vector<Diag> CIDiags); | 571 ParseInputs Inputs, std::vector<Diag> CIDiags); |
572 | |
573 void updateASTSignals(ParsedAST &AST); | |
417 | 574 |
418 // Must be called exactly once on processing thread. Will return after | 575 // Must be called exactly once on processing thread. Will return after |
419 // stop() is called on a separate thread and all pending requests are | 576 // stop() is called on a separate thread and all pending requests are |
420 // processed. | 577 // processed. |
421 void run(); | 578 void run(); |
422 /// Signal that run() should finish processing pending requests and exit. | 579 /// Signal that run() should finish processing pending requests and exit. |
423 void stop(); | 580 void stop(); |
581 | |
424 /// Adds a new task to the end of the request queue. | 582 /// Adds a new task to the end of the request queue. |
425 void startTask(llvm::StringRef Name, llvm::unique_function<void()> Task, | 583 void startTask(llvm::StringRef Name, llvm::unique_function<void()> Task, |
426 llvm::Optional<WantDiagnostics> UpdateType, | 584 llvm::Optional<UpdateType> Update, |
427 TUScheduler::ASTActionInvalidation); | 585 TUScheduler::ASTActionInvalidation); |
428 | 586 |
429 /// Determines the next action to perform. | 587 /// Determines the next action to perform. |
430 /// All actions that should never run are discarded. | 588 /// All actions that should never run are discarded. |
431 /// Returns a deadline for the next action. If it's expired, run now. | 589 /// Returns a deadline for the next action. If it's expired, run now. |
437 struct Request { | 595 struct Request { |
438 llvm::unique_function<void()> Action; | 596 llvm::unique_function<void()> Action; |
439 std::string Name; | 597 std::string Name; |
440 steady_clock::time_point AddTime; | 598 steady_clock::time_point AddTime; |
441 Context Ctx; | 599 Context Ctx; |
442 llvm::Optional<WantDiagnostics> UpdateType; | 600 llvm::Optional<Context> QueueCtx; |
601 llvm::Optional<UpdateType> Update; | |
443 TUScheduler::ASTActionInvalidation InvalidationPolicy; | 602 TUScheduler::ASTActionInvalidation InvalidationPolicy; |
444 Canceler Invalidate; | 603 Canceler Invalidate; |
445 }; | 604 }; |
446 | 605 |
447 /// Handles retention of ASTs. | 606 /// Handles retention of ASTs. |
448 TUScheduler::ASTCache &IdleASTs; | 607 TUScheduler::ASTCache &IdleASTs; |
608 TUScheduler::HeaderIncluderCache &HeaderIncluders; | |
449 const bool RunSync; | 609 const bool RunSync; |
450 /// Time to wait after an update to see whether another update obsoletes it. | 610 /// Time to wait after an update to see whether another update obsoletes it. |
451 const DebouncePolicy UpdateDebounce; | 611 const DebouncePolicy UpdateDebounce; |
452 /// File that ASTWorker is responsible for. | 612 /// File that ASTWorker is responsible for. |
453 const Path FileName; | 613 const Path FileName; |
614 /// Callback to create processing contexts for tasks. | |
615 const std::function<Context(llvm::StringRef)> ContextProvider; | |
454 const GlobalCompilationDatabase &CDB; | 616 const GlobalCompilationDatabase &CDB; |
455 /// Callback invoked when preamble or main file AST is built. | 617 /// Callback invoked when preamble or main file AST is built. |
456 ParsingCallbacks &Callbacks; | 618 ParsingCallbacks &Callbacks; |
457 /// Latest build preamble for current TU. | |
458 std::shared_ptr<const PreambleData> LatestPreamble; | |
459 Notification BuiltFirstPreamble; | |
460 | 619 |
461 Semaphore &Barrier; | 620 Semaphore &Barrier; |
462 /// Whether the 'onMainAST' callback ran for the current FileInputs. | 621 /// Whether the 'onMainAST' callback ran for the current FileInputs. |
463 bool RanASTCallback = false; | 622 bool RanASTCallback = false; |
464 /// Guards members used by both TUScheduler and the worker thread. | 623 /// Guards members used by both TUScheduler and the worker thread. |
466 /// File inputs, currently being used by the worker. | 625 /// File inputs, currently being used by the worker. |
467 /// Writes and reads from unknown threads are locked. Reads from the worker | 626 /// Writes and reads from unknown threads are locked. Reads from the worker |
468 /// thread are not locked, as it's the only writer. | 627 /// thread are not locked, as it's the only writer. |
469 ParseInputs FileInputs; /* GUARDED_BY(Mutex) */ | 628 ParseInputs FileInputs; /* GUARDED_BY(Mutex) */ |
470 /// Times of recent AST rebuilds, used for UpdateDebounce computation. | 629 /// Times of recent AST rebuilds, used for UpdateDebounce computation. |
471 llvm::SmallVector<DebouncePolicy::clock::duration, 8> | 630 llvm::SmallVector<DebouncePolicy::clock::duration> |
472 RebuildTimes; /* GUARDED_BY(Mutex) */ | 631 RebuildTimes; /* GUARDED_BY(Mutex) */ |
473 /// Set to true to signal run() to finish processing. | 632 /// Set to true to signal run() to finish processing. |
474 bool Done; /* GUARDED_BY(Mutex) */ | 633 bool Done; /* GUARDED_BY(Mutex) */ |
475 std::deque<Request> Requests; /* GUARDED_BY(Mutex) */ | 634 std::deque<Request> Requests; /* GUARDED_BY(Mutex) */ |
476 std::queue<Request> PreambleRequests; /* GUARDED_BY(Mutex) */ | |
477 llvm::Optional<Request> CurrentRequest; /* GUARDED_BY(Mutex) */ | 635 llvm::Optional<Request> CurrentRequest; /* GUARDED_BY(Mutex) */ |
636 /// Signalled whenever a new request has been scheduled or processing of a | |
637 /// request has completed. | |
478 mutable std::condition_variable RequestsCV; | 638 mutable std::condition_variable RequestsCV; |
639 std::shared_ptr<const ASTSignals> LatestASTSignals; /* GUARDED_BY(Mutex) */ | |
640 /// Latest build preamble for current TU. | |
641 /// None means no builds yet, null means there was an error while building. | |
642 /// Only written by ASTWorker's thread. | |
643 llvm::Optional<std::shared_ptr<const PreambleData>> LatestPreamble; | |
644 std::deque<Request> PreambleRequests; /* GUARDED_BY(Mutex) */ | |
645 /// Signaled whenever LatestPreamble changes state or there's a new | |
646 /// PreambleRequest. | |
647 mutable std::condition_variable PreambleCV; | |
479 /// Guards the callback that publishes results of AST-related computations | 648 /// Guards the callback that publishes results of AST-related computations |
480 /// (diagnostics, highlightings) and file statuses. | 649 /// (diagnostics) and file statuses. |
481 std::mutex PublishMu; | 650 std::mutex PublishMu; |
482 // Used to prevent remove document + add document races that lead to | 651 // Used to prevent remove document + add document races that lead to |
483 // out-of-order callbacks for publishing results of onMainAST callback. | 652 // out-of-order callbacks for publishing results of onMainAST callback. |
484 // | 653 // |
485 // The lifetime of the old/new ASTWorkers will overlap, but their handles | 654 // The lifetime of the old/new ASTWorkers will overlap, but their handles |
535 std::shared_ptr<ASTWorker> Worker; | 704 std::shared_ptr<ASTWorker> Worker; |
536 }; | 705 }; |
537 | 706 |
538 ASTWorkerHandle | 707 ASTWorkerHandle |
539 ASTWorker::create(PathRef FileName, const GlobalCompilationDatabase &CDB, | 708 ASTWorker::create(PathRef FileName, const GlobalCompilationDatabase &CDB, |
540 TUScheduler::ASTCache &IdleASTs, AsyncTaskRunner *Tasks, | 709 TUScheduler::ASTCache &IdleASTs, |
541 Semaphore &Barrier, DebouncePolicy UpdateDebounce, | 710 TUScheduler::HeaderIncluderCache &HeaderIncluders, |
542 bool StorePreamblesInMemory, ParsingCallbacks &Callbacks) { | 711 AsyncTaskRunner *Tasks, Semaphore &Barrier, |
712 const TUScheduler::Options &Opts, | |
713 ParsingCallbacks &Callbacks) { | |
543 std::shared_ptr<ASTWorker> Worker( | 714 std::shared_ptr<ASTWorker> Worker( |
544 new ASTWorker(FileName, CDB, IdleASTs, Barrier, /*RunSync=*/!Tasks, | 715 new ASTWorker(FileName, CDB, IdleASTs, HeaderIncluders, Barrier, |
545 UpdateDebounce, StorePreamblesInMemory, Callbacks)); | 716 /*RunSync=*/!Tasks, Opts, Callbacks)); |
546 if (Tasks) { | 717 if (Tasks) { |
547 Tasks->runAsync("ASTWorker:" + llvm::sys::path::filename(FileName), | 718 Tasks->runAsync("ASTWorker:" + llvm::sys::path::filename(FileName), |
548 [Worker]() { Worker->run(); }); | 719 [Worker]() { Worker->run(); }); |
549 Tasks->runAsync("PreambleWorker:" + llvm::sys::path::filename(FileName), | 720 Tasks->runAsync("PreambleWorker:" + llvm::sys::path::filename(FileName), |
550 [Worker]() { Worker->PreamblePeer.run(); }); | 721 [Worker]() { Worker->PreamblePeer.run(); }); |
552 | 723 |
553 return ASTWorkerHandle(std::move(Worker)); | 724 return ASTWorkerHandle(std::move(Worker)); |
554 } | 725 } |
555 | 726 |
556 ASTWorker::ASTWorker(PathRef FileName, const GlobalCompilationDatabase &CDB, | 727 ASTWorker::ASTWorker(PathRef FileName, const GlobalCompilationDatabase &CDB, |
557 TUScheduler::ASTCache &LRUCache, Semaphore &Barrier, | 728 TUScheduler::ASTCache &LRUCache, |
558 bool RunSync, DebouncePolicy UpdateDebounce, | 729 TUScheduler::HeaderIncluderCache &HeaderIncluders, |
559 bool StorePreamblesInMemory, ParsingCallbacks &Callbacks) | 730 Semaphore &Barrier, bool RunSync, |
560 : IdleASTs(LRUCache), RunSync(RunSync), UpdateDebounce(UpdateDebounce), | 731 const TUScheduler::Options &Opts, |
561 FileName(FileName), CDB(CDB), Callbacks(Callbacks), Barrier(Barrier), | 732 ParsingCallbacks &Callbacks) |
562 Done(false), Status(FileName, Callbacks), | 733 : IdleASTs(LRUCache), HeaderIncluders(HeaderIncluders), RunSync(RunSync), |
563 PreamblePeer(FileName, Callbacks, StorePreamblesInMemory, | 734 UpdateDebounce(Opts.UpdateDebounce), FileName(FileName), |
564 // FIXME: Run PreamblePeer asynchronously once ast patching | 735 ContextProvider(Opts.ContextProvider), CDB(CDB), Callbacks(Callbacks), |
565 // is available. | 736 Barrier(Barrier), Done(false), Status(FileName, Callbacks), |
566 /*RunSync=*/true, Status, *this) { | 737 PreamblePeer(FileName, Callbacks, Opts.StorePreamblesInMemory, RunSync, |
738 Status, HeaderIncluders, *this) { | |
567 // Set a fallback command because compile command can be accessed before | 739 // Set a fallback command because compile command can be accessed before |
568 // `Inputs` is initialized. Other fields are only used after initialization | 740 // `Inputs` is initialized. Other fields are only used after initialization |
569 // from client inputs. | 741 // from client inputs. |
570 FileInputs.CompileCommand = CDB.getFallbackCommand(FileName); | 742 FileInputs.CompileCommand = CDB.getFallbackCommand(FileName); |
571 } | 743 } |
579 assert(Requests.empty() && !CurrentRequest && | 751 assert(Requests.empty() && !CurrentRequest && |
580 "unprocessed requests when destroying ASTWorker"); | 752 "unprocessed requests when destroying ASTWorker"); |
581 #endif | 753 #endif |
582 } | 754 } |
583 | 755 |
584 void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags) { | 756 void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags, |
757 bool ContentChanged) { | |
585 std::string TaskName = llvm::formatv("Update ({0})", Inputs.Version); | 758 std::string TaskName = llvm::formatv("Update ({0})", Inputs.Version); |
586 auto Task = [=]() mutable { | 759 auto Task = [=]() mutable { |
587 // Get the actual command as `Inputs` does not have a command. | 760 // Get the actual command as `Inputs` does not have a command. |
588 // FIXME: some build systems like Bazel will take time to preparing | 761 // FIXME: some build systems like Bazel will take time to preparing |
589 // environment to build the file, it would be nice if we could emit a | 762 // environment to build the file, it would be nice if we could emit a |
590 // "PreparingBuild" status to inform users, it is non-trivial given the | 763 // "PreparingBuild" status to inform users, it is non-trivial given the |
591 // current implementation. | 764 // current implementation. |
592 if (auto Cmd = CDB.getCompileCommand(FileName)) | 765 auto Cmd = CDB.getCompileCommand(FileName); |
593 Inputs.CompileCommand = *Cmd; | 766 // If we don't have a reliable command for this file, it may be a header. |
767 // Try to find a file that includes it, to borrow its command. | |
768 if (!Cmd || !isReliable(*Cmd)) { | |
769 std::string ProxyFile = HeaderIncluders.get(FileName); | |
770 if (!ProxyFile.empty()) { | |
771 auto ProxyCmd = CDB.getCompileCommand(ProxyFile); | |
772 if (!ProxyCmd || !isReliable(*ProxyCmd)) { | |
773 // This command is supposed to be reliable! It's probably gone. | |
774 HeaderIncluders.remove(ProxyFile); | |
775 } else { | |
776 // We have a reliable command for an including file, use it. | |
777 Cmd = tooling::transferCompileCommand(std::move(*ProxyCmd), FileName); | |
778 } | |
779 } | |
780 } | |
781 if (Cmd) | |
782 Inputs.CompileCommand = std::move(*Cmd); | |
594 else | 783 else |
595 // FIXME: consider using old command if it's not a fallback one. | |
596 Inputs.CompileCommand = CDB.getFallbackCommand(FileName); | 784 Inputs.CompileCommand = CDB.getFallbackCommand(FileName); |
597 | 785 |
598 bool InputsAreTheSame = | 786 bool InputsAreTheSame = |
599 std::tie(FileInputs.CompileCommand, FileInputs.Contents) == | 787 std::tie(FileInputs.CompileCommand, FileInputs.Contents) == |
600 std::tie(Inputs.CompileCommand, Inputs.Contents); | 788 std::tie(Inputs.CompileCommand, Inputs.Contents); |
611 } | 799 } |
612 | 800 |
613 log("ASTWorker building file {0} version {1} with command {2}\n[{3}]\n{4}", | 801 log("ASTWorker building file {0} version {1} with command {2}\n[{3}]\n{4}", |
614 FileName, Inputs.Version, Inputs.CompileCommand.Heuristic, | 802 FileName, Inputs.Version, Inputs.CompileCommand.Heuristic, |
615 Inputs.CompileCommand.Directory, | 803 Inputs.CompileCommand.Directory, |
616 llvm::join(Inputs.CompileCommand.CommandLine, " ")); | 804 printArgv(Inputs.CompileCommand.CommandLine)); |
617 | 805 |
618 StoreDiags CompilerInvocationDiagConsumer; | 806 StoreDiags CompilerInvocationDiagConsumer; |
619 std::vector<std::string> CC1Args; | 807 std::vector<std::string> CC1Args; |
620 std::unique_ptr<CompilerInvocation> Invocation = buildCompilerInvocation( | 808 std::unique_ptr<CompilerInvocation> Invocation = buildCompilerInvocation( |
621 Inputs, CompilerInvocationDiagConsumer, &CC1Args); | 809 Inputs, CompilerInvocationDiagConsumer, &CC1Args); |
622 // Log cc1 args even (especially!) if creating invocation failed. | 810 // Log cc1 args even (especially!) if creating invocation failed. |
623 if (!CC1Args.empty()) | 811 if (!CC1Args.empty()) |
624 vlog("Driver produced command: cc1 {0}", llvm::join(CC1Args, " ")); | 812 vlog("Driver produced command: cc1 {0}", printArgv(CC1Args)); |
625 std::vector<Diag> CompilerInvocationDiags = | 813 std::vector<Diag> CompilerInvocationDiags = |
626 CompilerInvocationDiagConsumer.take(); | 814 CompilerInvocationDiagConsumer.take(); |
627 if (!Invocation) { | 815 if (!Invocation) { |
628 elog("Could not build CompilerInvocation for file {0}", FileName); | 816 elog("Could not build CompilerInvocation for file {0}", FileName); |
629 // Remove the old AST if it's still in cache. | 817 // Remove the old AST if it's still in cache. |
638 // are not race conditions. | 826 // are not race conditions. |
639 std::lock_guard<std::mutex> Lock(PublishMu); | 827 std::lock_guard<std::mutex> Lock(PublishMu); |
640 if (CanPublishResults) | 828 if (CanPublishResults) |
641 Publish(); | 829 Publish(); |
642 }); | 830 }); |
831 // Note that this might throw away a stale preamble that might still be | |
832 // useful, but this is how we communicate a build error. | |
833 LatestPreamble.emplace(); | |
643 // Make sure anyone waiting for the preamble gets notified it could not be | 834 // Make sure anyone waiting for the preamble gets notified it could not be |
644 // built. | 835 // built. |
645 BuiltFirstPreamble.notify(); | 836 PreambleCV.notify_all(); |
646 return; | 837 return; |
647 } | 838 } |
648 | 839 |
649 PreamblePeer.update(std::move(Invocation), std::move(Inputs), | 840 PreamblePeer.update(std::move(Invocation), std::move(Inputs), |
650 std::move(CompilerInvocationDiags), WantDiags); | 841 std::move(CompilerInvocationDiags), WantDiags); |
842 std::unique_lock<std::mutex> Lock(Mutex); | |
843 PreambleCV.wait(Lock, [this] { | |
844 // Block until we reiceve a preamble request, unless a preamble already | |
845 // exists, as patching an empty preamble would imply rebuilding it from | |
846 // scratch. | |
847 // We block here instead of the consumer to prevent any deadlocks. Since | |
848 // LatestPreamble is only populated by ASTWorker thread. | |
849 return LatestPreamble || !PreambleRequests.empty() || Done; | |
850 }); | |
651 return; | 851 return; |
652 }; | 852 }; |
653 startTask(TaskName, std::move(Task), WantDiags, TUScheduler::NoInvalidation); | 853 startTask(TaskName, std::move(Task), UpdateType{WantDiags, ContentChanged}, |
854 TUScheduler::NoInvalidation); | |
654 } | 855 } |
655 | 856 |
656 void ASTWorker::runWithAST( | 857 void ASTWorker::runWithAST( |
657 llvm::StringRef Name, | 858 llvm::StringRef Name, |
658 llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action, | 859 llvm::unique_function<void(llvm::Expected<InputsAndAST>)> Action, |
687 // Make sure we put the AST back into the LRU cache. | 888 // Make sure we put the AST back into the LRU cache. |
688 auto _ = llvm::make_scope_exit( | 889 auto _ = llvm::make_scope_exit( |
689 [&AST, this]() { IdleASTs.put(this, std::move(*AST)); }); | 890 [&AST, this]() { IdleASTs.put(this, std::move(*AST)); }); |
690 // Run the user-provided action. | 891 // Run the user-provided action. |
691 if (!*AST) | 892 if (!*AST) |
692 return Action(llvm::make_error<llvm::StringError>( | 893 return Action(error(llvm::errc::invalid_argument, "invalid AST")); |
693 "invalid AST", llvm::errc::invalid_argument)); | |
694 vlog("ASTWorker running {0} on version {2} of {1}", Name, FileName, | 894 vlog("ASTWorker running {0} on version {2} of {1}", Name, FileName, |
695 FileInputs.Version); | 895 FileInputs.Version); |
696 Action(InputsAndAST{FileInputs, **AST}); | 896 Action(InputsAndAST{FileInputs, **AST}); |
697 }; | 897 }; |
698 startTask(Name, std::move(Task), /*UpdateType=*/None, Invalidation); | 898 startTask(Name, std::move(Task), /*Update=*/None, Invalidation); |
699 } | 899 } |
700 | 900 |
701 void PreambleThread::build(Request Req) { | 901 void PreambleThread::build(Request Req) { |
702 assert(Req.CI && "Got preamble request with null compiler invocation"); | 902 assert(Req.CI && "Got preamble request with null compiler invocation"); |
703 const ParseInputs &Inputs = Req.Inputs; | 903 const ParseInputs &Inputs = Req.Inputs; |
707 }); | 907 }); |
708 auto _ = llvm::make_scope_exit([this, &Req] { | 908 auto _ = llvm::make_scope_exit([this, &Req] { |
709 ASTPeer.updatePreamble(std::move(Req.CI), std::move(Req.Inputs), | 909 ASTPeer.updatePreamble(std::move(Req.CI), std::move(Req.Inputs), |
710 LatestBuild, std::move(Req.CIDiags), | 910 LatestBuild, std::move(Req.CIDiags), |
711 std::move(Req.WantDiags)); | 911 std::move(Req.WantDiags)); |
912 Callbacks.onPreamblePublished(FileName); | |
712 }); | 913 }); |
713 | 914 |
714 if (!LatestBuild || Inputs.ForceRebuild) { | 915 if (!LatestBuild || Inputs.ForceRebuild) { |
715 vlog("Building first preamble for {0} version {1}", FileName, | 916 vlog("Building first preamble for {0} version {1}", FileName, |
716 Inputs.Version); | 917 Inputs.Version); |
730 std::shared_ptr<clang::Preprocessor> PP, | 931 std::shared_ptr<clang::Preprocessor> PP, |
731 const CanonicalIncludes &CanonIncludes) { | 932 const CanonicalIncludes &CanonIncludes) { |
732 Callbacks.onPreambleAST(FileName, Version, Ctx, std::move(PP), | 933 Callbacks.onPreambleAST(FileName, Version, Ctx, std::move(PP), |
733 CanonIncludes); | 934 CanonIncludes); |
734 }); | 935 }); |
936 if (LatestBuild && isReliable(LatestBuild->CompileCommand)) | |
937 HeaderIncluders.update(FileName, LatestBuild->Includes.allHeaders()); | |
735 } | 938 } |
736 | 939 |
737 void ASTWorker::updatePreamble(std::unique_ptr<CompilerInvocation> CI, | 940 void ASTWorker::updatePreamble(std::unique_ptr<CompilerInvocation> CI, |
738 ParseInputs PI, | 941 ParseInputs PI, |
739 std::shared_ptr<const PreambleData> Preamble, | 942 std::shared_ptr<const PreambleData> Preamble, |
745 PI = std::move(PI), CIDiags = std::move(CIDiags), | 948 PI = std::move(PI), CIDiags = std::move(CIDiags), |
746 WantDiags = std::move(WantDiags)]() mutable { | 949 WantDiags = std::move(WantDiags)]() mutable { |
747 // Update the preamble inside ASTWorker queue to ensure atomicity. As a task | 950 // Update the preamble inside ASTWorker queue to ensure atomicity. As a task |
748 // running inside ASTWorker assumes internals won't change until it | 951 // running inside ASTWorker assumes internals won't change until it |
749 // finishes. | 952 // finishes. |
750 if (Preamble != LatestPreamble) { | 953 if (!LatestPreamble || Preamble != *LatestPreamble) { |
751 ++PreambleBuildCount; | 954 ++PreambleBuildCount; |
752 // Cached AST is no longer valid. | 955 // Cached AST is no longer valid. |
753 IdleASTs.take(this); | 956 IdleASTs.take(this); |
754 RanASTCallback = false; | 957 RanASTCallback = false; |
755 std::lock_guard<std::mutex> Lock(Mutex); | 958 std::lock_guard<std::mutex> Lock(Mutex); |
756 // LatestPreamble might be the last reference to old preamble, do not | 959 // LatestPreamble might be the last reference to old preamble, do not |
757 // trigger destructor while holding the lock. | 960 // trigger destructor while holding the lock. |
758 std::swap(LatestPreamble, Preamble); | 961 if (LatestPreamble) |
759 } | 962 std::swap(*LatestPreamble, Preamble); |
963 else | |
964 LatestPreamble = std::move(Preamble); | |
965 } | |
966 // Notify anyone waiting for a preamble. | |
967 PreambleCV.notify_all(); | |
760 // Give up our ownership to old preamble before starting expensive AST | 968 // Give up our ownership to old preamble before starting expensive AST |
761 // build. | 969 // build. |
762 Preamble.reset(); | 970 Preamble.reset(); |
763 BuiltFirstPreamble.notify(); | |
764 // We only need to build the AST if diagnostics were requested. | 971 // We only need to build the AST if diagnostics were requested. |
765 if (WantDiags == WantDiagnostics::No) | 972 if (WantDiags == WantDiagnostics::No) |
766 return; | 973 return; |
767 // Report diagnostics with the new preamble to ensure progress. Otherwise | 974 // Report diagnostics with the new preamble to ensure progress. Otherwise |
768 // diagnostics might get stale indefinitely if user keeps invalidating the | 975 // diagnostics might get stale indefinitely if user keeps invalidating the |
773 Task(); | 980 Task(); |
774 return; | 981 return; |
775 } | 982 } |
776 { | 983 { |
777 std::lock_guard<std::mutex> Lock(Mutex); | 984 std::lock_guard<std::mutex> Lock(Mutex); |
778 PreambleRequests.push({std::move(Task), std::move(TaskName), | 985 PreambleRequests.push_back({std::move(Task), std::move(TaskName), |
779 steady_clock::now(), Context::current().clone(), | 986 steady_clock::now(), Context::current().clone(), |
780 llvm::None, TUScheduler::NoInvalidation, nullptr}); | 987 llvm::None, llvm::None, |
781 } | 988 TUScheduler::NoInvalidation, nullptr}); |
989 } | |
990 PreambleCV.notify_all(); | |
782 RequestsCV.notify_all(); | 991 RequestsCV.notify_all(); |
992 } | |
993 | |
994 void ASTWorker::updateASTSignals(ParsedAST &AST) { | |
995 auto Signals = std::make_shared<const ASTSignals>(ASTSignals::derive(AST)); | |
996 // Existing readers of ASTSignals will have their copy preserved until the | |
997 // read is completed. The last reader deletes the old ASTSignals. | |
998 { | |
999 std::lock_guard<std::mutex> Lock(Mutex); | |
1000 std::swap(LatestASTSignals, Signals); | |
1001 } | |
783 } | 1002 } |
784 | 1003 |
785 void ASTWorker::generateDiagnostics( | 1004 void ASTWorker::generateDiagnostics( |
786 std::unique_ptr<CompilerInvocation> Invocation, ParseInputs Inputs, | 1005 std::unique_ptr<CompilerInvocation> Invocation, ParseInputs Inputs, |
787 std::vector<Diag> CIDiags) { | 1006 std::vector<Diag> CIDiags) { |
788 // Tracks ast cache accesses for publishing diags. | 1007 // Tracks ast cache accesses for publishing diags. |
789 static constexpr trace::Metric ASTAccessForDiag( | 1008 static constexpr trace::Metric ASTAccessForDiag( |
790 "ast_access_diag", trace::Metric::Counter, "result"); | 1009 "ast_access_diag", trace::Metric::Counter, "result"); |
791 assert(Invocation); | 1010 assert(Invocation); |
1011 assert(LatestPreamble); | |
792 // No need to rebuild the AST if we won't send the diagnostics. | 1012 // No need to rebuild the AST if we won't send the diagnostics. |
793 { | 1013 { |
794 std::lock_guard<std::mutex> Lock(PublishMu); | 1014 std::lock_guard<std::mutex> Lock(PublishMu); |
795 if (!CanPublishResults) | 1015 if (!CanPublishResults) |
796 return; | 1016 return; |
819 llvm::Optional<std::unique_ptr<ParsedAST>> AST = | 1039 llvm::Optional<std::unique_ptr<ParsedAST>> AST = |
820 IdleASTs.take(this, &ASTAccessForDiag); | 1040 IdleASTs.take(this, &ASTAccessForDiag); |
821 if (!AST || !InputsAreLatest) { | 1041 if (!AST || !InputsAreLatest) { |
822 auto RebuildStartTime = DebouncePolicy::clock::now(); | 1042 auto RebuildStartTime = DebouncePolicy::clock::now(); |
823 llvm::Optional<ParsedAST> NewAST = ParsedAST::build( | 1043 llvm::Optional<ParsedAST> NewAST = ParsedAST::build( |
824 FileName, Inputs, std::move(Invocation), CIDiags, LatestPreamble); | 1044 FileName, Inputs, std::move(Invocation), CIDiags, *LatestPreamble); |
825 auto RebuildDuration = DebouncePolicy::clock::now() - RebuildStartTime; | 1045 auto RebuildDuration = DebouncePolicy::clock::now() - RebuildStartTime; |
826 ++ASTBuildCount; | 1046 ++ASTBuildCount; |
827 // Try to record the AST-build time, to inform future update debouncing. | 1047 // Try to record the AST-build time, to inform future update debouncing. |
828 // This is best-effort only: if the lock is held, don't bother. | 1048 // This is best-effort only: if the lock is held, don't bother. |
829 std::unique_lock<std::mutex> Lock(Mutex, std::try_to_lock); | 1049 std::unique_lock<std::mutex> Lock(Mutex, std::try_to_lock); |
857 Publish(); | 1077 Publish(); |
858 }; | 1078 }; |
859 if (*AST) { | 1079 if (*AST) { |
860 trace::Span Span("Running main AST callback"); | 1080 trace::Span Span("Running main AST callback"); |
861 Callbacks.onMainAST(FileName, **AST, RunPublish); | 1081 Callbacks.onMainAST(FileName, **AST, RunPublish); |
1082 updateASTSignals(**AST); | |
862 } else { | 1083 } else { |
863 // Failed to build the AST, at least report diagnostics from the | 1084 // Failed to build the AST, at least report diagnostics from the |
864 // command line if there were any. | 1085 // command line if there were any. |
865 // FIXME: we might have got more errors while trying to build the | 1086 // FIXME: we might have got more errors while trying to build the |
866 // AST, surface them too. | 1087 // AST, surface them too. |
874 RanASTCallback = *AST != nullptr; | 1095 RanASTCallback = *AST != nullptr; |
875 IdleASTs.put(this, std::move(*AST)); | 1096 IdleASTs.put(this, std::move(*AST)); |
876 } | 1097 } |
877 } | 1098 } |
878 | 1099 |
879 std::shared_ptr<const PreambleData> | 1100 std::shared_ptr<const PreambleData> ASTWorker::getPossiblyStalePreamble( |
880 ASTWorker::getPossiblyStalePreamble() const { | 1101 std::shared_ptr<const ASTSignals> *ASTSignals) const { |
881 std::lock_guard<std::mutex> Lock(Mutex); | 1102 std::lock_guard<std::mutex> Lock(Mutex); |
882 return LatestPreamble; | 1103 if (ASTSignals) |
883 } | 1104 *ASTSignals = LatestASTSignals; |
884 | 1105 return LatestPreamble ? *LatestPreamble : nullptr; |
885 void ASTWorker::waitForFirstPreamble() const { BuiltFirstPreamble.wait(); } | 1106 } |
1107 | |
1108 void ASTWorker::waitForFirstPreamble() const { | |
1109 std::unique_lock<std::mutex> Lock(Mutex); | |
1110 PreambleCV.wait(Lock, [this] { return LatestPreamble.hasValue() || Done; }); | |
1111 } | |
886 | 1112 |
887 tooling::CompileCommand ASTWorker::getCurrentCompileCommand() const { | 1113 tooling::CompileCommand ASTWorker::getCurrentCompileCommand() const { |
888 std::unique_lock<std::mutex> Lock(Mutex); | 1114 std::unique_lock<std::mutex> Lock(Mutex); |
889 return FileInputs.CompileCommand; | 1115 return FileInputs.CompileCommand; |
890 } | 1116 } |
894 Result.ASTBuilds = ASTBuildCount; | 1120 Result.ASTBuilds = ASTBuildCount; |
895 Result.PreambleBuilds = PreambleBuildCount; | 1121 Result.PreambleBuilds = PreambleBuildCount; |
896 // Note that we don't report the size of ASTs currently used for processing | 1122 // Note that we don't report the size of ASTs currently used for processing |
897 // the in-flight requests. We used this information for debugging purposes | 1123 // the in-flight requests. We used this information for debugging purposes |
898 // only, so this should be fine. | 1124 // only, so this should be fine. |
899 Result.UsedBytes = IdleASTs.getUsedBytes(this); | 1125 Result.UsedBytesAST = IdleASTs.getUsedBytes(this); |
900 if (auto Preamble = getPossiblyStalePreamble()) | 1126 if (auto Preamble = getPossiblyStalePreamble()) |
901 Result.UsedBytes += Preamble->Preamble.getSize(); | 1127 Result.UsedBytesPreamble = Preamble->Preamble.getSize(); |
902 return Result; | 1128 return Result; |
903 } | 1129 } |
904 | 1130 |
905 bool ASTWorker::isASTCached() const { return IdleASTs.getUsedBytes(this) != 0; } | 1131 bool ASTWorker::isASTCached() const { return IdleASTs.getUsedBytes(this) != 0; } |
906 | 1132 |
912 { | 1138 { |
913 std::lock_guard<std::mutex> Lock(Mutex); | 1139 std::lock_guard<std::mutex> Lock(Mutex); |
914 assert(!Done && "stop() called twice"); | 1140 assert(!Done && "stop() called twice"); |
915 Done = true; | 1141 Done = true; |
916 } | 1142 } |
1143 PreamblePeer.stop(); | |
917 // We are no longer going to build any preambles, let the waiters know that. | 1144 // We are no longer going to build any preambles, let the waiters know that. |
918 BuiltFirstPreamble.notify(); | 1145 PreambleCV.notify_all(); |
919 PreamblePeer.stop(); | |
920 Status.stop(); | 1146 Status.stop(); |
921 RequestsCV.notify_all(); | 1147 RequestsCV.notify_all(); |
922 } | 1148 } |
923 | 1149 |
924 void ASTWorker::startTask(llvm::StringRef Name, | 1150 void ASTWorker::startTask(llvm::StringRef Name, |
925 llvm::unique_function<void()> Task, | 1151 llvm::unique_function<void()> Task, |
926 llvm::Optional<WantDiagnostics> UpdateType, | 1152 llvm::Optional<UpdateType> Update, |
927 TUScheduler::ASTActionInvalidation Invalidation) { | 1153 TUScheduler::ASTActionInvalidation Invalidation) { |
928 if (RunSync) { | 1154 if (RunSync) { |
929 assert(!Done && "running a task after stop()"); | 1155 assert(!Done && "running a task after stop()"); |
930 trace::Span Tracer(Name + ":" + llvm::sys::path::filename(FileName)); | 1156 trace::Span Tracer(Name + ":" + llvm::sys::path::filename(FileName)); |
1157 WithContext WithProvidedContext(ContextProvider(FileName)); | |
931 Task(); | 1158 Task(); |
932 return; | 1159 return; |
933 } | 1160 } |
934 | 1161 |
935 { | 1162 { |
936 std::lock_guard<std::mutex> Lock(Mutex); | 1163 std::lock_guard<std::mutex> Lock(Mutex); |
937 assert(!Done && "running a task after stop()"); | 1164 assert(!Done && "running a task after stop()"); |
938 // Cancel any requests invalidated by this request. | 1165 // Cancel any requests invalidated by this request. |
939 if (UpdateType) { | 1166 if (Update && Update->ContentChanged) { |
940 for (auto &R : llvm::reverse(Requests)) { | 1167 for (auto &R : llvm::reverse(Requests)) { |
941 if (R.InvalidationPolicy == TUScheduler::InvalidateOnUpdate) | 1168 if (R.InvalidationPolicy == TUScheduler::InvalidateOnUpdate) |
942 R.Invalidate(); | 1169 R.Invalidate(); |
943 if (R.UpdateType) | 1170 if (R.Update && R.Update->ContentChanged) |
944 break; // Older requests were already invalidated by the older update. | 1171 break; // Older requests were already invalidated by the older update. |
945 } | 1172 } |
946 } | 1173 } |
947 | 1174 |
948 // Allow this request to be cancelled if invalidated. | 1175 // Allow this request to be cancelled if invalidated. |
951 if (Invalidation) { | 1178 if (Invalidation) { |
952 WithContext WC(std::move(Ctx)); | 1179 WithContext WC(std::move(Ctx)); |
953 std::tie(Ctx, Invalidate) = cancelableTask( | 1180 std::tie(Ctx, Invalidate) = cancelableTask( |
954 /*Reason=*/static_cast<int>(ErrorCode::ContentModified)); | 1181 /*Reason=*/static_cast<int>(ErrorCode::ContentModified)); |
955 } | 1182 } |
1183 // Trace the time the request spends in the queue, and the requests that | |
1184 // it's going to wait for. | |
1185 llvm::Optional<Context> QueueCtx; | |
1186 if (trace::enabled()) { | |
1187 // Tracers that follow threads and need strict nesting will see a tiny | |
1188 // instantaneous event "we're enqueueing", and sometime later it runs. | |
1189 WithContext WC(Ctx.clone()); | |
1190 trace::Span Tracer("Queued:" + Name); | |
1191 if (Tracer.Args) { | |
1192 if (CurrentRequest) | |
1193 SPAN_ATTACH(Tracer, "CurrentRequest", CurrentRequest->Name); | |
1194 llvm::json::Array PreambleRequestsNames; | |
1195 for (const auto &Req : PreambleRequests) | |
1196 PreambleRequestsNames.push_back(Req.Name); | |
1197 SPAN_ATTACH(Tracer, "PreambleRequestsNames", | |
1198 std::move(PreambleRequestsNames)); | |
1199 llvm::json::Array RequestsNames; | |
1200 for (const auto &Req : Requests) | |
1201 RequestsNames.push_back(Req.Name); | |
1202 SPAN_ATTACH(Tracer, "RequestsNames", std::move(RequestsNames)); | |
1203 } | |
1204 // For tracers that follow contexts, keep the trace span's context alive | |
1205 // until we dequeue the request, so they see the full duration. | |
1206 QueueCtx = Context::current().clone(); | |
1207 } | |
956 Requests.push_back({std::move(Task), std::string(Name), steady_clock::now(), | 1208 Requests.push_back({std::move(Task), std::string(Name), steady_clock::now(), |
957 std::move(Ctx), UpdateType, Invalidation, | 1209 std::move(Ctx), std::move(QueueCtx), Update, |
958 std::move(Invalidate)}); | 1210 Invalidation, std::move(Invalidate)}); |
959 } | 1211 } |
960 RequestsCV.notify_all(); | 1212 RequestsCV.notify_all(); |
961 } | 1213 } |
962 | 1214 |
963 void ASTWorker::run() { | 1215 void ASTWorker::run() { |
999 } | 1251 } |
1000 // Any request in ReceivedPreambles is at least as old as the | 1252 // Any request in ReceivedPreambles is at least as old as the |
1001 // Requests.front(), so prefer them first to preserve LSP order. | 1253 // Requests.front(), so prefer them first to preserve LSP order. |
1002 if (!PreambleRequests.empty()) { | 1254 if (!PreambleRequests.empty()) { |
1003 CurrentRequest = std::move(PreambleRequests.front()); | 1255 CurrentRequest = std::move(PreambleRequests.front()); |
1004 PreambleRequests.pop(); | 1256 PreambleRequests.pop_front(); |
1005 } else { | 1257 } else { |
1006 CurrentRequest = std::move(Requests.front()); | 1258 CurrentRequest = std::move(Requests.front()); |
1007 Requests.pop_front(); | 1259 Requests.pop_front(); |
1008 } | 1260 } |
1009 } // unlock Mutex | 1261 } // unlock Mutex |
1262 | |
1263 // Inform tracing that the request was dequeued. | |
1264 CurrentRequest->QueueCtx.reset(); | |
1010 | 1265 |
1011 // It is safe to perform reads to CurrentRequest without holding the lock as | 1266 // It is safe to perform reads to CurrentRequest without holding the lock as |
1012 // only writer is also this thread. | 1267 // only writer is also this thread. |
1013 { | 1268 { |
1014 std::unique_lock<Semaphore> Lock(Barrier, std::try_to_lock); | 1269 std::unique_lock<Semaphore> Lock(Barrier, std::try_to_lock); |
1023 trace::Span Tracer(CurrentRequest->Name); | 1278 trace::Span Tracer(CurrentRequest->Name); |
1024 Status.update([&](TUStatus &Status) { | 1279 Status.update([&](TUStatus &Status) { |
1025 Status.ASTActivity.K = ASTAction::RunningAction; | 1280 Status.ASTActivity.K = ASTAction::RunningAction; |
1026 Status.ASTActivity.Name = CurrentRequest->Name; | 1281 Status.ASTActivity.Name = CurrentRequest->Name; |
1027 }); | 1282 }); |
1283 WithContext WithProvidedContext(ContextProvider(FileName)); | |
1028 CurrentRequest->Action(); | 1284 CurrentRequest->Action(); |
1029 } | 1285 } |
1030 | 1286 |
1031 bool IsEmpty = false; | 1287 bool IsEmpty = false; |
1032 { | 1288 { |
1052 return Deadline::infinity(); // Wait for new requests. | 1308 return Deadline::infinity(); // Wait for new requests. |
1053 // Handle cancelled requests first so the rest of the scheduler doesn't. | 1309 // Handle cancelled requests first so the rest of the scheduler doesn't. |
1054 for (auto I = Requests.begin(), E = Requests.end(); I != E; ++I) { | 1310 for (auto I = Requests.begin(), E = Requests.end(); I != E; ++I) { |
1055 if (!isCancelled(I->Ctx)) { | 1311 if (!isCancelled(I->Ctx)) { |
1056 // Cancellations after the first read don't affect current scheduling. | 1312 // Cancellations after the first read don't affect current scheduling. |
1057 if (I->UpdateType == None) | 1313 if (I->Update == None) |
1058 break; | 1314 break; |
1059 continue; | 1315 continue; |
1060 } | 1316 } |
1061 // Cancelled reads are moved to the front of the queue and run immediately. | 1317 // Cancelled reads are moved to the front of the queue and run immediately. |
1062 if (I->UpdateType == None) { | 1318 if (I->Update == None) { |
1063 Request R = std::move(*I); | 1319 Request R = std::move(*I); |
1064 Requests.erase(I); | 1320 Requests.erase(I); |
1065 Requests.push_front(std::move(R)); | 1321 Requests.push_front(std::move(R)); |
1066 return Deadline::zero(); | 1322 return Deadline::zero(); |
1067 } | 1323 } |
1068 // Cancelled updates are downgraded to auto-diagnostics, and may be elided. | 1324 // Cancelled updates are downgraded to auto-diagnostics, and may be elided. |
1069 if (I->UpdateType == WantDiagnostics::Yes) | 1325 if (I->Update->Diagnostics == WantDiagnostics::Yes) |
1070 I->UpdateType = WantDiagnostics::Auto; | 1326 I->Update->Diagnostics = WantDiagnostics::Auto; |
1071 } | 1327 } |
1072 | 1328 |
1073 while (shouldSkipHeadLocked()) { | 1329 while (shouldSkipHeadLocked()) { |
1074 vlog("ASTWorker skipping {0} for {1}", Requests.front().Name, FileName); | 1330 vlog("ASTWorker skipping {0} for {1}", Requests.front().Name, FileName); |
1075 Requests.pop_front(); | 1331 Requests.pop_front(); |
1078 // Some updates aren't dead yet, but never end up being used. | 1334 // Some updates aren't dead yet, but never end up being used. |
1079 // e.g. the first keystroke is live until obsoleted by the second. | 1335 // e.g. the first keystroke is live until obsoleted by the second. |
1080 // We debounce "maybe-unused" writes, sleeping in case they become dead. | 1336 // We debounce "maybe-unused" writes, sleeping in case they become dead. |
1081 // But don't delay reads (including updates where diagnostics are needed). | 1337 // But don't delay reads (including updates where diagnostics are needed). |
1082 for (const auto &R : Requests) | 1338 for (const auto &R : Requests) |
1083 if (R.UpdateType == None || R.UpdateType == WantDiagnostics::Yes) | 1339 if (R.Update == None || R.Update->Diagnostics == WantDiagnostics::Yes) |
1084 return Deadline::zero(); | 1340 return Deadline::zero(); |
1085 // Front request needs to be debounced, so determine when we're ready. | 1341 // Front request needs to be debounced, so determine when we're ready. |
1086 Deadline D(Requests.front().AddTime + UpdateDebounce.compute(RebuildTimes)); | 1342 Deadline D(Requests.front().AddTime + UpdateDebounce.compute(RebuildTimes)); |
1087 return D; | 1343 return D; |
1088 } | 1344 } |
1089 | 1345 |
1090 // Returns true if Requests.front() is a dead update that can be skipped. | 1346 // Returns true if Requests.front() is a dead update that can be skipped. |
1091 bool ASTWorker::shouldSkipHeadLocked() const { | 1347 bool ASTWorker::shouldSkipHeadLocked() const { |
1092 assert(!Requests.empty()); | 1348 assert(!Requests.empty()); |
1093 auto Next = Requests.begin(); | 1349 auto Next = Requests.begin(); |
1094 auto UpdateType = Next->UpdateType; | 1350 auto Update = Next->Update; |
1095 if (!UpdateType) // Only skip updates. | 1351 if (!Update) // Only skip updates. |
1096 return false; | 1352 return false; |
1097 ++Next; | 1353 ++Next; |
1098 // An update is live if its AST might still be read. | 1354 // An update is live if its AST might still be read. |
1099 // That is, if it's not immediately followed by another update. | 1355 // That is, if it's not immediately followed by another update. |
1100 if (Next == Requests.end() || !Next->UpdateType) | 1356 if (Next == Requests.end() || !Next->Update) |
1101 return false; | 1357 return false; |
1102 // The other way an update can be live is if its diagnostics might be used. | 1358 // The other way an update can be live is if its diagnostics might be used. |
1103 switch (*UpdateType) { | 1359 switch (Update->Diagnostics) { |
1104 case WantDiagnostics::Yes: | 1360 case WantDiagnostics::Yes: |
1105 return false; // Always used. | 1361 return false; // Always used. |
1106 case WantDiagnostics::No: | 1362 case WantDiagnostics::No: |
1107 return true; // Always dead. | 1363 return true; // Always dead. |
1108 case WantDiagnostics::Auto: | 1364 case WantDiagnostics::Auto: |
1109 // Used unless followed by an update that generates diagnostics. | 1365 // Used unless followed by an update that generates diagnostics. |
1110 for (; Next != Requests.end(); ++Next) | 1366 for (; Next != Requests.end(); ++Next) |
1111 if (Next->UpdateType == WantDiagnostics::Yes || | 1367 if (Next->Update && Next->Update->Diagnostics != WantDiagnostics::No) |
1112 Next->UpdateType == WantDiagnostics::Auto) | |
1113 return true; // Prefer later diagnostics. | 1368 return true; // Prefer later diagnostics. |
1114 return false; | 1369 return false; |
1115 } | 1370 } |
1116 llvm_unreachable("Unknown WantDiagnostics"); | 1371 llvm_unreachable("Unknown WantDiagnostics"); |
1117 } | 1372 } |
1118 | 1373 |
1119 bool ASTWorker::blockUntilIdle(Deadline Timeout) const { | 1374 bool ASTWorker::blockUntilIdle(Deadline Timeout) const { |
1120 std::unique_lock<std::mutex> Lock(Mutex); | 1375 auto WaitUntilASTWorkerIsIdle = [&] { |
1121 return wait(Lock, RequestsCV, Timeout, [&] { | 1376 std::unique_lock<std::mutex> Lock(Mutex); |
1122 return PreambleRequests.empty() && Requests.empty() && !CurrentRequest; | 1377 return wait(Lock, RequestsCV, Timeout, [&] { |
1123 }); | 1378 return PreambleRequests.empty() && Requests.empty() && !CurrentRequest; |
1379 }); | |
1380 }; | |
1381 // Make sure ASTWorker has processed all requests, which might issue new | |
1382 // updates to PreamblePeer. | |
1383 WaitUntilASTWorkerIsIdle(); | |
1384 // Now that ASTWorker processed all requests, ensure PreamblePeer has served | |
1385 // all update requests. This might create new PreambleRequests for the | |
1386 // ASTWorker. | |
1387 PreamblePeer.blockUntilIdle(Timeout); | |
1388 assert(Requests.empty() && | |
1389 "No new normal tasks can be scheduled concurrently with " | |
1390 "blockUntilIdle(): ASTWorker isn't threadsafe"); | |
1391 // Finally make sure ASTWorker has processed all of the preamble updates. | |
1392 return WaitUntilASTWorkerIsIdle(); | |
1124 } | 1393 } |
1125 | 1394 |
1126 // Render a TUAction to a user-facing string representation. | 1395 // Render a TUAction to a user-facing string representation. |
1127 // TUAction represents clangd-internal states, we don't intend to expose them | 1396 // TUAction represents clangd-internal states, we don't intend to expose them |
1128 // to users (say C++ programmers) directly to avoid confusion, we use terms that | 1397 // to users (say C++ programmers) directly to avoid confusion, we use terms that |
1151 // We handle idle specially below. | 1420 // We handle idle specially below. |
1152 break; | 1421 break; |
1153 } | 1422 } |
1154 if (Result.empty()) | 1423 if (Result.empty()) |
1155 return "idle"; | 1424 return "idle"; |
1156 return llvm::join(Result, ","); | 1425 return llvm::join(Result, ", "); |
1157 } | 1426 } |
1158 | 1427 |
1159 } // namespace | 1428 } // namespace |
1160 | 1429 |
1161 unsigned getDefaultAsyncThreadsCount() { | 1430 unsigned getDefaultAsyncThreadsCount() { |
1176 }; | 1445 }; |
1177 | 1446 |
1178 TUScheduler::TUScheduler(const GlobalCompilationDatabase &CDB, | 1447 TUScheduler::TUScheduler(const GlobalCompilationDatabase &CDB, |
1179 const Options &Opts, | 1448 const Options &Opts, |
1180 std::unique_ptr<ParsingCallbacks> Callbacks) | 1449 std::unique_ptr<ParsingCallbacks> Callbacks) |
1181 : CDB(CDB), StorePreamblesInMemory(Opts.StorePreamblesInMemory), | 1450 : CDB(CDB), Opts(Opts), |
1182 Callbacks(Callbacks ? move(Callbacks) | 1451 Callbacks(Callbacks ? move(Callbacks) |
1183 : std::make_unique<ParsingCallbacks>()), | 1452 : std::make_unique<ParsingCallbacks>()), |
1184 Barrier(Opts.AsyncThreadsCount), | 1453 Barrier(Opts.AsyncThreadsCount), QuickRunBarrier(Opts.AsyncThreadsCount), |
1185 IdleASTs( | 1454 IdleASTs( |
1186 std::make_unique<ASTCache>(Opts.RetentionPolicy.MaxRetainedASTs)), | 1455 std::make_unique<ASTCache>(Opts.RetentionPolicy.MaxRetainedASTs)), |
1187 UpdateDebounce(Opts.UpdateDebounce) { | 1456 HeaderIncluders(std::make_unique<HeaderIncluderCache>()) { |
1457 // Avoid null checks everywhere. | |
1458 if (!Opts.ContextProvider) { | |
1459 this->Opts.ContextProvider = [](llvm::StringRef) { | |
1460 return Context::current().clone(); | |
1461 }; | |
1462 } | |
1188 if (0 < Opts.AsyncThreadsCount) { | 1463 if (0 < Opts.AsyncThreadsCount) { |
1189 PreambleTasks.emplace(); | 1464 PreambleTasks.emplace(); |
1190 WorkerThreads.emplace(); | 1465 WorkerThreads.emplace(); |
1191 } | 1466 } |
1192 } | 1467 } |
1214 | 1489 |
1215 bool TUScheduler::update(PathRef File, ParseInputs Inputs, | 1490 bool TUScheduler::update(PathRef File, ParseInputs Inputs, |
1216 WantDiagnostics WantDiags) { | 1491 WantDiagnostics WantDiags) { |
1217 std::unique_ptr<FileData> &FD = Files[File]; | 1492 std::unique_ptr<FileData> &FD = Files[File]; |
1218 bool NewFile = FD == nullptr; | 1493 bool NewFile = FD == nullptr; |
1494 bool ContentChanged = false; | |
1219 if (!FD) { | 1495 if (!FD) { |
1220 // Create a new worker to process the AST-related tasks. | 1496 // Create a new worker to process the AST-related tasks. |
1221 ASTWorkerHandle Worker = ASTWorker::create( | 1497 ASTWorkerHandle Worker = |
1222 File, CDB, *IdleASTs, | 1498 ASTWorker::create(File, CDB, *IdleASTs, *HeaderIncluders, |
1223 WorkerThreads ? WorkerThreads.getPointer() : nullptr, Barrier, | 1499 WorkerThreads ? WorkerThreads.getPointer() : nullptr, |
1224 UpdateDebounce, StorePreamblesInMemory, *Callbacks); | 1500 Barrier, Opts, *Callbacks); |
1225 FD = std::unique_ptr<FileData>( | 1501 FD = std::unique_ptr<FileData>( |
1226 new FileData{Inputs.Contents, std::move(Worker)}); | 1502 new FileData{Inputs.Contents, std::move(Worker)}); |
1227 } else { | 1503 ContentChanged = true; |
1504 } else if (FD->Contents != Inputs.Contents) { | |
1505 ContentChanged = true; | |
1228 FD->Contents = Inputs.Contents; | 1506 FD->Contents = Inputs.Contents; |
1229 } | 1507 } |
1230 FD->Worker->update(std::move(Inputs), WantDiags); | 1508 FD->Worker->update(std::move(Inputs), WantDiags, ContentChanged); |
1509 // There might be synthetic update requests, don't change the LastActiveFile | |
1510 // in such cases. | |
1511 if (ContentChanged) | |
1512 LastActiveFile = File.str(); | |
1231 return NewFile; | 1513 return NewFile; |
1232 } | 1514 } |
1233 | 1515 |
1234 void TUScheduler::remove(PathRef File) { | 1516 void TUScheduler::remove(PathRef File) { |
1235 bool Removed = Files.erase(File); | 1517 bool Removed = Files.erase(File); |
1236 if (!Removed) | 1518 if (!Removed) |
1237 elog("Trying to remove file from TUScheduler that is not tracked: {0}", | 1519 elog("Trying to remove file from TUScheduler that is not tracked: {0}", |
1238 File); | 1520 File); |
1239 } | 1521 // We don't call HeaderIncluders.remove(File) here. |
1240 | 1522 // If we did, we'd avoid potentially stale header/mainfile associations. |
1241 llvm::StringMap<std::string> TUScheduler::getAllFileContents() const { | 1523 // However, it would mean that closing a mainfile could invalidate the |
1242 llvm::StringMap<std::string> Results; | 1524 // preamble of several open headers. |
1243 for (auto &It : Files) | 1525 } |
1244 Results.try_emplace(It.getKey(), It.getValue()->Contents); | 1526 |
1245 return Results; | 1527 void TUScheduler::run(llvm::StringRef Name, llvm::StringRef Path, |
1246 } | |
1247 | |
1248 void TUScheduler::run(llvm::StringRef Name, | |
1249 llvm::unique_function<void()> Action) { | 1528 llvm::unique_function<void()> Action) { |
1250 if (!PreambleTasks) | 1529 runWithSemaphore(Name, Path, std::move(Action), Barrier); |
1530 } | |
1531 | |
1532 void TUScheduler::runQuick(llvm::StringRef Name, llvm::StringRef Path, | |
1533 llvm::unique_function<void()> Action) { | |
1534 // Use QuickRunBarrier to serialize quick tasks: we are ignoring | |
1535 // the parallelism level set by the user, don't abuse it | |
1536 runWithSemaphore(Name, Path, std::move(Action), QuickRunBarrier); | |
1537 } | |
1538 | |
1539 void TUScheduler::runWithSemaphore(llvm::StringRef Name, llvm::StringRef Path, | |
1540 llvm::unique_function<void()> Action, | |
1541 Semaphore &Sem) { | |
1542 if (Path.empty()) | |
1543 Path = LastActiveFile; | |
1544 else | |
1545 LastActiveFile = Path.str(); | |
1546 if (!PreambleTasks) { | |
1547 WithContext WithProvidedContext(Opts.ContextProvider(Path)); | |
1251 return Action(); | 1548 return Action(); |
1252 PreambleTasks->runAsync(Name, [this, Ctx = Context::current().clone(), | 1549 } |
1550 PreambleTasks->runAsync(Name, [this, &Sem, Ctx = Context::current().clone(), | |
1551 Path(Path.str()), | |
1253 Action = std::move(Action)]() mutable { | 1552 Action = std::move(Action)]() mutable { |
1254 std::lock_guard<Semaphore> BarrierLock(Barrier); | 1553 std::lock_guard<Semaphore> BarrierLock(Sem); |
1255 WithContext WC(std::move(Ctx)); | 1554 WithContext WC(std::move(Ctx)); |
1555 WithContext WithProvidedContext(Opts.ContextProvider(Path)); | |
1256 Action(); | 1556 Action(); |
1257 }); | 1557 }); |
1258 } | 1558 } |
1259 | 1559 |
1260 void TUScheduler::runWithAST( | 1560 void TUScheduler::runWithAST( |
1265 if (It == Files.end()) { | 1565 if (It == Files.end()) { |
1266 Action(llvm::make_error<LSPError>( | 1566 Action(llvm::make_error<LSPError>( |
1267 "trying to get AST for non-added document", ErrorCode::InvalidParams)); | 1567 "trying to get AST for non-added document", ErrorCode::InvalidParams)); |
1268 return; | 1568 return; |
1269 } | 1569 } |
1570 LastActiveFile = File.str(); | |
1270 | 1571 |
1271 It->second->Worker->runWithAST(Name, std::move(Action), Invalidation); | 1572 It->second->Worker->runWithAST(Name, std::move(Action), Invalidation); |
1272 } | 1573 } |
1273 | 1574 |
1274 void TUScheduler::runWithPreamble(llvm::StringRef Name, PathRef File, | 1575 void TUScheduler::runWithPreamble(llvm::StringRef Name, PathRef File, |
1279 Action(llvm::make_error<LSPError>( | 1580 Action(llvm::make_error<LSPError>( |
1280 "trying to get preamble for non-added document", | 1581 "trying to get preamble for non-added document", |
1281 ErrorCode::InvalidParams)); | 1582 ErrorCode::InvalidParams)); |
1282 return; | 1583 return; |
1283 } | 1584 } |
1585 LastActiveFile = File.str(); | |
1284 | 1586 |
1285 if (!PreambleTasks) { | 1587 if (!PreambleTasks) { |
1286 trace::Span Tracer(Name); | 1588 trace::Span Tracer(Name); |
1287 SPAN_ATTACH(Tracer, "file", File); | 1589 SPAN_ATTACH(Tracer, "file", File); |
1590 std::shared_ptr<const ASTSignals> Signals; | |
1288 std::shared_ptr<const PreambleData> Preamble = | 1591 std::shared_ptr<const PreambleData> Preamble = |
1289 It->second->Worker->getPossiblyStalePreamble(); | 1592 It->second->Worker->getPossiblyStalePreamble(&Signals); |
1593 WithContext WithProvidedContext(Opts.ContextProvider(File)); | |
1290 Action(InputsAndPreamble{It->second->Contents, | 1594 Action(InputsAndPreamble{It->second->Contents, |
1291 It->second->Worker->getCurrentCompileCommand(), | 1595 It->second->Worker->getCurrentCompileCommand(), |
1292 Preamble.get()}); | 1596 Preamble.get(), Signals.get()}); |
1293 return; | 1597 return; |
1294 } | 1598 } |
1295 | 1599 |
1296 std::shared_ptr<const ASTWorker> Worker = It->second->Worker.lock(); | 1600 std::shared_ptr<const ASTWorker> Worker = It->second->Worker.lock(); |
1297 auto Task = | 1601 auto Task = [Worker, Consistency, Name = Name.str(), File = File.str(), |
1298 [Worker, Consistency, Name = Name.str(), File = File.str(), | 1602 Contents = It->second->Contents, |
1299 Contents = It->second->Contents, | 1603 Command = Worker->getCurrentCompileCommand(), |
1300 Command = Worker->getCurrentCompileCommand(), | 1604 Ctx = Context::current().derive(kFileBeingProcessed, |
1301 Ctx = Context::current().derive(kFileBeingProcessed, std::string(File)), | 1605 std::string(File)), |
1302 Action = std::move(Action), this]() mutable { | 1606 Action = std::move(Action), this]() mutable { |
1303 std::shared_ptr<const PreambleData> Preamble; | 1607 std::shared_ptr<const PreambleData> Preamble; |
1304 if (Consistency == PreambleConsistency::Stale) { | 1608 if (Consistency == PreambleConsistency::Stale) { |
1305 // Wait until the preamble is built for the first time, if preamble | 1609 // Wait until the preamble is built for the first time, if preamble |
1306 // is required. This avoids extra work of processing the preamble | 1610 // is required. This avoids extra work of processing the preamble |
1307 // headers in parallel multiple times. | 1611 // headers in parallel multiple times. |
1308 Worker->waitForFirstPreamble(); | 1612 Worker->waitForFirstPreamble(); |
1309 } | 1613 } |
1310 Preamble = Worker->getPossiblyStalePreamble(); | 1614 std::shared_ptr<const ASTSignals> Signals; |
1311 | 1615 Preamble = Worker->getPossiblyStalePreamble(&Signals); |
1312 std::lock_guard<Semaphore> BarrierLock(Barrier); | 1616 |
1313 WithContext Guard(std::move(Ctx)); | 1617 std::lock_guard<Semaphore> BarrierLock(Barrier); |
1314 trace::Span Tracer(Name); | 1618 WithContext Guard(std::move(Ctx)); |
1315 SPAN_ATTACH(Tracer, "file", File); | 1619 trace::Span Tracer(Name); |
1316 Action(InputsAndPreamble{Contents, Command, Preamble.get()}); | 1620 SPAN_ATTACH(Tracer, "file", File); |
1317 }; | 1621 WithContext WithProvidedContext(Opts.ContextProvider(File)); |
1622 Action(InputsAndPreamble{Contents, Command, Preamble.get(), Signals.get()}); | |
1623 }; | |
1318 | 1624 |
1319 PreambleTasks->runAsync("task:" + llvm::sys::path::filename(File), | 1625 PreambleTasks->runAsync("task:" + llvm::sys::path::filename(File), |
1320 std::move(Task)); | 1626 std::move(Task)); |
1321 } | 1627 } |
1322 | 1628 |
1364 DebouncePolicy P; | 1670 DebouncePolicy P; |
1365 P.Min = P.Max = T; | 1671 P.Min = P.Max = T; |
1366 return P; | 1672 return P; |
1367 } | 1673 } |
1368 | 1674 |
1675 void TUScheduler::profile(MemoryTree &MT) const { | |
1676 for (const auto &Elem : fileStats()) { | |
1677 MT.detail(Elem.first()) | |
1678 .child("preamble") | |
1679 .addUsage(Opts.StorePreamblesInMemory ? Elem.second.UsedBytesPreamble | |
1680 : 0); | |
1681 MT.detail(Elem.first()).child("ast").addUsage(Elem.second.UsedBytesAST); | |
1682 MT.child("header_includer_cache").addUsage(HeaderIncluders->getUsedBytes()); | |
1683 } | |
1684 } | |
1369 } // namespace clangd | 1685 } // namespace clangd |
1370 } // namespace clang | 1686 } // namespace clang |