didOpen: Sort index requests by approximity to working files

For a large project, it is preferable to prioritize indexing files
neighboring working files.
This commit is contained in:
Fangrui Song 2024-10-21 17:49:54 -07:00
parent ddbe41300f
commit 349cdc471b
6 changed files with 40 additions and 8 deletions

View File

@ -17,14 +17,14 @@ struct Out_cclsInfo {
int files, funcs, types, vars; int files, funcs, types, vars;
} db; } db;
struct Pipeline { struct Pipeline {
int64_t lastIdle, completed, enqueued; int64_t lastIdle, completed, enqueued, opened;
} pipeline; } pipeline;
struct Project { struct Project {
int entries; int entries;
} project; } project;
}; };
REFLECT_STRUCT(Out_cclsInfo::DB, files, funcs, types, vars); REFLECT_STRUCT(Out_cclsInfo::DB, files, funcs, types, vars);
REFLECT_STRUCT(Out_cclsInfo::Pipeline, lastIdle, completed, enqueued); REFLECT_STRUCT(Out_cclsInfo::Pipeline, lastIdle, completed, enqueued, opened);
REFLECT_STRUCT(Out_cclsInfo::Project, entries); REFLECT_STRUCT(Out_cclsInfo::Project, entries);
REFLECT_STRUCT(Out_cclsInfo, db, pipeline, project); REFLECT_STRUCT(Out_cclsInfo, db, pipeline, project);
} // namespace } // namespace
@ -38,6 +38,7 @@ void MessageHandler::ccls_info(EmptyParam &, ReplyOnce &reply) {
result.pipeline.lastIdle = pipeline::stats.last_idle; result.pipeline.lastIdle = pipeline::stats.last_idle;
result.pipeline.completed = pipeline::stats.completed; result.pipeline.completed = pipeline::stats.completed;
result.pipeline.enqueued = pipeline::stats.enqueued; result.pipeline.enqueued = pipeline::stats.enqueued;
result.pipeline.opened = pipeline::stats.opened;
result.project.entries = 0; result.project.entries = 0;
for (auto &[_, folder] : project->root2folder) for (auto &[_, folder] : project->root2folder)
result.project.entries += folder.entries.size(); result.project.entries += folder.entries.size();

View File

@ -50,6 +50,20 @@ void MessageHandler::textDocument_didOpen(DidOpenTextDocumentParam &param) {
project->indexRelated(path); project->indexRelated(path);
manager->onView(path); manager->onView(path);
// For the first few didOpen, sort indexer requests based on path similarity.
if (++pipeline::stats.opened >= 5)
return;
std::unordered_map<std::string, int> dir2prio;
{
std::lock_guard lock(wfiles->mutex);
for (auto &[f, wf] : wfiles->files) {
std::string cur = lowerPathIfInsensitive(f);
for (int pri = 1 << 20; !(cur = llvm::sys::path::parent_path(cur)).empty(); pri /= 2)
dir2prio[cur] += pri;
}
}
pipeline::indexerSort(dir2prio);
} }
void MessageHandler::textDocument_didSave(TextDocumentParam &param) { void MessageHandler::textDocument_didSave(TextDocumentParam &param) {

View File

@ -87,6 +87,7 @@ struct IndexRequest {
bool must_exist = false; bool must_exist = false;
RequestId id; RequestId id;
int64_t ts = tick++; int64_t ts = tick++;
int prio = 0; // For didOpen sorting
}; };
std::mutex thread_mtx; std::mutex thread_mtx;
@ -488,6 +489,23 @@ void indexer_Main(SemaManager *manager, VFS *vfs, Project *project,
break; break;
} }
void indexerSort(const std::unordered_map<std::string, int> &dir2prio) {
index_request->apply([&](std::deque<IndexRequest> &q) {
for (IndexRequest &request : q) {
std::string cur = lowerPathIfInsensitive(request.path);
while (!(cur = llvm::sys::path::parent_path(cur)).empty()) {
auto it = dir2prio.find(cur);
if (it != dir2prio.end()) {
request.prio = it->second;
LOG_V(3) << "set priority " << request.prio << " to " << request.path;
break;
}
}
}
std::stable_sort(q.begin(), q.end(), [](auto &l, auto &r) { return l.prio > r.prio; });
});
}
void main_OnIndexed(DB *db, WorkingFiles *wfiles, IndexUpdate *update) { void main_OnIndexed(DB *db, WorkingFiles *wfiles, IndexUpdate *update) {
if (update->refresh) { if (update->refresh) {
LOG_S(INFO) LOG_S(INFO)

View File

@ -40,7 +40,7 @@ enum class IndexMode {
}; };
struct IndexStats { struct IndexStats {
std::atomic<int64_t> last_idle, completed, enqueued; std::atomic<int64_t> last_idle, completed, enqueued, opened;
}; };
namespace pipeline { namespace pipeline {
@ -56,6 +56,7 @@ void launchStdin();
void launchStdout(); void launchStdout();
void indexer_Main(SemaManager *manager, VFS *vfs, Project *project, void indexer_Main(SemaManager *manager, VFS *vfs, Project *project,
WorkingFiles *wfiles); WorkingFiles *wfiles);
void indexerSort(const std::unordered_map<std::string, int> &dir2prio);
void mainLoop(); void mainLoop();
void standalone(const std::string &root); void standalone(const std::string &root);

View File

@ -28,6 +28,7 @@ struct Project {
// 0 unless coming from a compile_commands.json entry. // 0 unless coming from a compile_commands.json entry.
int compdb_size = 0; int compdb_size = 0;
int id = -1; int id = -1;
int prio = 0;
}; };
struct Folder { struct Folder {

View File

@ -161,12 +161,9 @@ public:
return std::nullopt; return std::nullopt;
} }
template <typename Fn> void iterate(Fn fn) { template <typename Fn> void apply(Fn fn) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
for (auto &entry : priority_) fn(queue_);
fn(entry);
for (auto &entry : queue_)
fn(entry);
} }
mutable std::mutex mutex_; mutable std::mutex mutex_;