Skip to content

Commit 0f7146d

Browse files
committed
[clangd] Prioritize indexing of files that share a basename with the open file.
Summary: In practice, opening Foo.h will still often result in Foo.cpp making the second index build instead of the first, as the rebuild policy doesn't know to wait. Reviewers: kadircet Subscribers: ilya-biryukov, javed.absar, MaskRay, jkorous, arphaman, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D64575 llvm-svn: 365888
1 parent 9c0391b commit 0f7146d

File tree

7 files changed

+97
-8
lines changed

7 files changed

+97
-8
lines changed

clang-tools-extra/clangd/ClangdServer.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,10 @@ void ClangdServer::addDocument(PathRef File, llvm::StringRef Contents,
151151
Inputs.Contents = Contents;
152152
Inputs.Opts = std::move(Opts);
153153
Inputs.Index = Index;
154-
WorkScheduler.update(File, Inputs, WantDiags);
154+
bool NewFile = WorkScheduler.update(File, Inputs, WantDiags);
155+
// If we loaded Foo.h, we want to make sure Foo.cpp is indexed.
156+
if (NewFile && BackgroundIdx)
157+
BackgroundIdx->boostRelated(File);
155158
}
156159

157160
void ClangdServer::removeDocument(PathRef File) { WorkScheduler.remove(File); }

clang-tools-extra/clangd/TUScheduler.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -860,9 +860,10 @@ bool TUScheduler::blockUntilIdle(Deadline D) const {
860860
return true;
861861
}
862862

863-
void TUScheduler::update(PathRef File, ParseInputs Inputs,
863+
bool TUScheduler::update(PathRef File, ParseInputs Inputs,
864864
WantDiagnostics WantDiags) {
865865
std::unique_ptr<FileData> &FD = Files[File];
866+
bool NewFile = FD == nullptr;
866867
if (!FD) {
867868
// Create a new worker to process the AST-related tasks.
868869
ASTWorkerHandle Worker = ASTWorker::create(
@@ -875,6 +876,7 @@ void TUScheduler::update(PathRef File, ParseInputs Inputs,
875876
FD->Contents = Inputs.Contents;
876877
}
877878
FD->Worker->update(std::move(Inputs), WantDiags);
879+
return NewFile;
878880
}
879881

880882
void TUScheduler::remove(PathRef File) {

clang-tools-extra/clangd/TUScheduler.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,14 @@ class TUScheduler {
142142
/// contain files that currently run something over their AST.
143143
std::vector<Path> getFilesWithCachedAST() const;
144144

145-
/// Schedule an update for \p File. Adds \p File to a list of tracked files if
146-
/// \p File was not part of it before. The compile command in \p Inputs is
147-
/// ignored; worker queries CDB to get the actual compile command.
145+
/// Schedule an update for \p File.
146+
/// The compile command in \p Inputs is ignored; worker queries CDB to get
147+
/// the actual compile command.
148148
/// If diagnostics are requested (Yes), and the context is cancelled
149149
/// before they are prepared, they may be skipped if eventual-consistency
150150
/// permits it (i.e. WantDiagnostics is downgraded to Auto).
151-
void update(PathRef File, ParseInputs Inputs, WantDiagnostics WD);
151+
/// Returns true if the file was not previously tracked.
152+
bool update(PathRef File, ParseInputs Inputs, WantDiagnostics WD);
152153

153154
/// Remove \p File from the list of tracked files and schedule removal of its
154155
/// resources. Pending diagnostics for closed files may not be delivered, even

clang-tools-extra/clangd/index/Background.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "index/SymbolCollector.h"
2828
#include "clang/Basic/SourceLocation.h"
2929
#include "clang/Basic/SourceManager.h"
30+
#include "clang/Driver/Types.h"
3031
#include "llvm/ADT/Hashing.h"
3132
#include "llvm/ADT/STLExtras.h"
3233
#include "llvm/ADT/ScopeExit.h"
@@ -171,6 +172,11 @@ BackgroundQueue::Task BackgroundIndex::changedFilesTask(
171172
return T;
172173
}
173174

175+
static llvm::StringRef filenameWithoutExtension(llvm::StringRef Path) {
176+
Path = llvm::sys::path::filename(Path);
177+
return Path.drop_back(llvm::sys::path::extension(Path).size());
178+
}
179+
174180
BackgroundQueue::Task
175181
BackgroundIndex::indexFileTask(tooling::CompileCommand Cmd,
176182
BackgroundIndexStorage *Storage) {
@@ -182,9 +188,19 @@ BackgroundIndex::indexFileTask(tooling::CompileCommand Cmd,
182188
elog("Indexing {0} failed: {1}", FileName, std::move(Error));
183189
});
184190
T.QueuePri = IndexFile;
191+
T.Tag = filenameWithoutExtension(Cmd.Filename);
185192
return T;
186193
}
187194

195+
void BackgroundIndex::boostRelated(llvm::StringRef Path) {
196+
namespace types = clang::driver::types;
197+
auto Type =
198+
types::lookupTypeForExtension(llvm::sys::path::extension(Path).substr(1));
199+
// is this a header?
200+
if (Type != types::TY_INVALID && types::onlyPrecompileType(Type))
201+
Queue.boost(filenameWithoutExtension(Path), IndexBoostedFile);
202+
}
203+
188204
/// Given index results from a TU, only update symbols coming from files that
189205
/// are different or missing from than \p ShardVersionsSnapshot. Also stores new
190206
/// index information on IndexStorage.

clang-tools-extra/clangd/index/Background.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,19 @@ class BackgroundQueue {
6969

7070
std::function<void()> Run;
7171
llvm::ThreadPriority ThreadPri = llvm::ThreadPriority::Background;
72-
// Higher-priority tasks will run first.
73-
unsigned QueuePri = 0;
72+
unsigned QueuePri = 0; // Higher-priority tasks will run first.
73+
std::string Tag; // Allows priority to be boosted later.
7474

7575
bool operator<(const Task &O) const { return QueuePri < O.QueuePri; }
7676
};
7777

7878
// Add tasks to the queue.
7979
void push(Task);
8080
void append(std::vector<Task>);
81+
// Boost priority of current and new tasks with matching Tag, if they are
82+
// lower priority.
83+
// Reducing the boost of a tag affects future tasks but not current ones.
84+
void boost(llvm::StringRef Tag, unsigned NewPriority);
8185

8286
// Process items on the queue until the queue is stopped.
8387
// If the queue becomes empty, OnIdle will be called (on one worker).
@@ -98,6 +102,7 @@ class BackgroundQueue {
98102
std::condition_variable CV;
99103
bool ShouldStop = false;
100104
std::vector<Task> Queue; // max-heap
105+
llvm::StringMap<unsigned> Boosts;
101106
};
102107

103108
// Builds an in-memory index by by running the static indexer action over
@@ -123,6 +128,10 @@ class BackgroundIndex : public SwapIndex {
123128
Queue.push(changedFilesTask(ChangedFiles));
124129
}
125130

131+
/// Boosts priority of indexing related to Path.
132+
/// Typically used to index TUs when headers are opened.
133+
void boostRelated(llvm::StringRef Path);
134+
126135
// Cause background threads to stop after ther current task, any remaining
127136
// tasks will be discarded.
128137
void stop() {
@@ -187,6 +196,7 @@ class BackgroundIndex : public SwapIndex {
187196
// from lowest to highest priority
188197
enum QueuePriority {
189198
IndexFile,
199+
IndexBoostedFile,
190200
LoadShards,
191201
};
192202
BackgroundQueue Queue;

clang-tools-extra/clangd/index/BackgroundQueue.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ void BackgroundQueue::stop() {
6767
void BackgroundQueue::push(Task T) {
6868
{
6969
std::lock_guard<std::mutex> Lock(Mu);
70+
T.QueuePri = std::max(T.QueuePri, Boosts.lookup(T.Tag));
7071
Queue.push_back(std::move(T));
7172
std::push_heap(Queue.begin(), Queue.end());
7273
}
@@ -76,12 +77,33 @@ void BackgroundQueue::push(Task T) {
7677
void BackgroundQueue::append(std::vector<Task> Tasks) {
7778
{
7879
std::lock_guard<std::mutex> Lock(Mu);
80+
for (Task &T : Tasks)
81+
T.QueuePri = std::max(T.QueuePri, Boosts.lookup(T.Tag));
7982
std::move(Tasks.begin(), Tasks.end(), std::back_inserter(Queue));
8083
std::make_heap(Queue.begin(), Queue.end());
8184
}
8285
CV.notify_all();
8386
}
8487

88+
void BackgroundQueue::boost(llvm::StringRef Tag, unsigned NewPriority) {
89+
std::lock_guard<std::mutex> Lock(Mu);
90+
unsigned &Boost = Boosts[Tag];
91+
bool Increase = NewPriority > Boost;
92+
Boost = NewPriority;
93+
if (!Increase)
94+
return; // existing tasks unaffected
95+
96+
unsigned Changes = 0;
97+
for (Task &T : Queue)
98+
if (Tag == T.Tag && NewPriority > T.QueuePri) {
99+
T.QueuePri = NewPriority;
100+
++Changes;
101+
}
102+
if (Changes)
103+
std::make_heap(Queue.begin(), Queue.end());
104+
// No need to signal, only rearranged items in the queue.
105+
}
106+
85107
bool BackgroundQueue::blockUntilIdleForTest(
86108
llvm::Optional<double> TimeoutSeconds) {
87109
std::unique_lock<std::mutex> Lock(Mu);

clang-tools-extra/clangd/unittests/BackgroundIndexTests.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,5 +678,40 @@ TEST(BackgroundQueueTest, Priority) {
678678
EXPECT_EQ(LoRan, 0u);
679679
}
680680

681+
TEST(BackgroundQueueTest, Boost) {
682+
std::string Sequence;
683+
684+
BackgroundQueue::Task A([&] { Sequence.push_back('A'); });
685+
A.Tag = "A";
686+
A.QueuePri = 1;
687+
688+
BackgroundQueue::Task B([&] { Sequence.push_back('B'); });
689+
B.QueuePri = 2;
690+
B.Tag = "B";
691+
692+
{
693+
BackgroundQueue Q;
694+
Q.append({A, B});
695+
Q.work([&] { Q.stop(); });
696+
EXPECT_EQ("BA", Sequence) << "priority order";
697+
}
698+
Sequence.clear();
699+
{
700+
BackgroundQueue Q;
701+
Q.boost("A", 3);
702+
Q.append({A, B});
703+
Q.work([&] { Q.stop(); });
704+
EXPECT_EQ("AB", Sequence) << "A was boosted before enqueueing";
705+
}
706+
Sequence.clear();
707+
{
708+
BackgroundQueue Q;
709+
Q.append({A, B});
710+
Q.boost("A", 3);
711+
Q.work([&] { Q.stop(); });
712+
EXPECT_EQ("AB", Sequence) << "A was boosted after enqueueing";
713+
}
714+
}
715+
681716
} // namespace clangd
682717
} // namespace clang

0 commit comments

Comments
 (0)