Index: clangd/Threading.h =================================================================== --- clangd/Threading.h +++ clangd/Threading.h @@ -121,7 +121,7 @@ Low = 0, Normal = 1, }; -void setThreadPriority(std::thread &T, ThreadPriority Priority); +void setCurrentThreadPriority(ThreadPriority Priority); // Avoid the use of scheduler policies that may starve low-priority threads. // This prevents tests from timing out on loaded systems. // Affects subsequent setThreadPriority() calls. Index: clangd/Threading.cpp =================================================================== --- clangd/Threading.cpp +++ clangd/Threading.cpp @@ -103,13 +103,13 @@ static std::atomic AvoidThreadStarvation = {false}; -void setThreadPriority(std::thread &T, ThreadPriority Priority) { +void setCurrentThreadPriority(ThreadPriority Priority) { // Some *really* old glibcs are missing SCHED_IDLE. #if defined(__linux__) && defined(SCHED_IDLE) sched_param priority; priority.sched_priority = 0; pthread_setschedparam( - T.native_handle(), + pthread_self(), Priority == ThreadPriority::Low && !AvoidThreadStarvation ? SCHED_IDLE : SCHED_OTHER, &priority); Index: clangd/index/Background.h =================================================================== --- clangd/index/Background.h +++ clangd/index/Background.h @@ -13,6 +13,7 @@ #include "Context.h" #include "FSProvider.h" #include "GlobalCompilationDatabase.h" +#include "Threading.h" #include "index/FileIndex.h" #include "index/Index.h" #include "index/Serialization.h" @@ -110,7 +111,7 @@ // queue management using Task = std::function; void run(); // Main loop executed by Thread. Runs tasks from Queue. - void enqueueTask(Task T); + void enqueueTask(Task T, ThreadPriority Prioirty); void enqueueLocked(tooling::CompileCommand Cmd, BackgroundIndexStorage *IndexStorage); std::mutex QueueMu; Index: clangd/index/Background.cpp =================================================================== --- clangd/index/Background.cpp +++ clangd/index/Background.cpp @@ -22,6 +22,7 @@ #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/SHA1.h" @@ -104,11 +105,6 @@ assert(this->IndexStorageFactory && "Storage factory can not be null!"); while (ThreadPoolSize--) { ThreadPool.emplace_back([this] { run(); }); - // Set priority to low, since background indexing is a long running task we - // do not want to eat up cpu when there are any other high priority threads. - // FIXME: In the future we might want a more general way of handling this to - // support tasks with various priorities. - setThreadPriority(ThreadPool.back(), ThreadPriority::Low); } } @@ -160,44 +156,61 @@ } void BackgroundIndex::enqueue(const std::vector &ChangedFiles) { - enqueueTask([this, ChangedFiles] { - trace::Span Tracer("BackgroundIndexEnqueue"); - // We're doing this asynchronously, because we'll read shards here too. - // FIXME: read shards here too. - - log("Enqueueing {0} commands for indexing", ChangedFiles.size()); - SPAN_ATTACH(Tracer, "files", int64_t(ChangedFiles.size())); - - // We shuffle the files because processing them in a random order should - // quickly give us good coverage of headers in the project. - std::vector Permutation(ChangedFiles.size()); - std::iota(Permutation.begin(), Permutation.end(), 0); - std::mt19937 Generator(std::random_device{}()); - std::shuffle(Permutation.begin(), Permutation.end(), Generator); - - for (const unsigned I : Permutation) - enqueue(ChangedFiles[I]); - }); + enqueueTask( + [this, ChangedFiles] { + trace::Span Tracer("BackgroundIndexEnqueue"); + // We're doing this asynchronously, because we'll read shards here too. + // FIXME: read shards here too. + + log("Enqueueing {0} commands for indexing", ChangedFiles.size()); + SPAN_ATTACH(Tracer, "files", int64_t(ChangedFiles.size())); + + // We shuffle the files because processing them in a random order should + // quickly give us good coverage of headers in the project. + std::vector Permutation(ChangedFiles.size()); + std::iota(Permutation.begin(), Permutation.end(), 0); + std::mt19937 Generator(std::random_device{}()); + std::shuffle(Permutation.begin(), Permutation.end(), Generator); + + for (const unsigned I : Permutation) + enqueue(ChangedFiles[I]); + }, + ThreadPriority::Normal); } void BackgroundIndex::enqueue(const std::string &File) { ProjectInfo Project; if (auto Cmd = CDB.getCompileCommand(File, &Project)) { auto *Storage = IndexStorageFactory(Project.SourceRoot); + // Set priority to low, since background indexing is a long running + // task we do not want to eat up cpu when there are any other high + // priority threads. enqueueTask(Bind( - [this, File, Storage](tooling::CompileCommand Cmd) { - Cmd.CommandLine.push_back("-resource-dir=" + ResourceDir); - if (auto Error = index(std::move(Cmd), Storage)) - log("Indexing {0} failed: {1}", File, std::move(Error)); - }, - std::move(*Cmd))); + [this, File, Storage](tooling::CompileCommand Cmd) { + Cmd.CommandLine.push_back("-resource-dir=" + ResourceDir); + if (auto Error = index(std::move(Cmd), Storage)) + log("Indexing {0} failed: {1}", File, std::move(Error)); + }, + std::move(*Cmd)), + ThreadPriority::Low); } } -void BackgroundIndex::enqueueTask(Task T) { +void BackgroundIndex::enqueueTask(Task T, ThreadPriority Priority) { { std::lock_guard Lock(QueueMu); - Queue.push_back(std::move(T)); + if (Priority == ThreadPriority::Low) { + Queue.push_back(Bind( + [](Task T) { + // FIXME: In the future we might want a more general way of handling + // this to support tasks with various priorities. + setCurrentThreadPriority(ThreadPriority::Low); + T(); + setCurrentThreadPriority(ThreadPriority::Normal); + }, + std::move(T))); + } else + Queue.push_front(std::move(T)); } QueueCV.notify_all(); }