[clangd] Use llvm::set_thread_priority in background-index

Reviewers: gribozavr

Subscribers: krytarowski, ilya-biryukov, ioeric, MaskRay, jkorous, arphaman, jfb, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D60865

llvm-svn: 358664
This commit is contained in:
Kadir Cetinkaya 2019-04-18 13:46:40 +00:00
parent 196a440411
commit f8537b3c69
6 changed files with 32 additions and 54 deletions

View File

@ -113,33 +113,5 @@ void wait(std::unique_lock<std::mutex> &Lock, std::condition_variable &CV,
CV.wait_until(Lock, D.time()); CV.wait_until(Lock, D.time());
} }
static std::atomic<bool> AvoidThreadStarvation = {false};
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(
pthread_self(),
Priority == ThreadPriority::Low && !AvoidThreadStarvation ? SCHED_IDLE
: SCHED_OTHER,
&priority);
#elif defined(__APPLE__)
// https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getpriority.2.html
setpriority(PRIO_DARWIN_THREAD, 0,
Priority == ThreadPriority::Low && !AvoidThreadStarvation
? PRIO_DARWIN_BG
: 0);
#elif defined(_WIN32)
SetThreadPriority(GetCurrentThread(),
Priority == ThreadPriority::Low && !AvoidThreadStarvation
? THREAD_MODE_BACKGROUND_BEGIN
: THREAD_MODE_BACKGROUND_END);
#endif
}
void preventThreadStarvationInTests() { AvoidThreadStarvation = true; }
} // namespace clangd } // namespace clangd
} // namespace clang } // namespace clang

View File

@ -117,16 +117,6 @@ private:
std::size_t InFlightTasks = 0; std::size_t InFlightTasks = 0;
}; };
enum class ThreadPriority {
Low = 0,
Normal = 1,
};
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.
void preventThreadStarvationInTests();
} // namespace clangd } // namespace clangd
} // namespace clang } // namespace clang
#endif #endif

View File

@ -26,7 +26,9 @@
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
#include "llvm/Support/SHA1.h" #include "llvm/Support/SHA1.h"
#include "llvm/Support/Threading.h"
#include <atomic>
#include <chrono> #include <chrono>
#include <memory> #include <memory>
#include <numeric> #include <numeric>
@ -38,6 +40,9 @@
namespace clang { namespace clang {
namespace clangd { namespace clangd {
namespace { namespace {
static std::atomic<bool> PreventStarvation = {false};
// Resolves URI to file paths with cache. // Resolves URI to file paths with cache.
class URIToFileCache { class URIToFileCache {
public: public:
@ -172,7 +177,7 @@ void BackgroundIndex::run() {
WithContext Background(BackgroundContext.clone()); WithContext Background(BackgroundContext.clone());
while (true) { while (true) {
llvm::Optional<Task> Task; llvm::Optional<Task> Task;
ThreadPriority Priority; llvm::ThreadPriority Priority;
{ {
std::unique_lock<std::mutex> Lock(QueueMu); std::unique_lock<std::mutex> Lock(QueueMu);
QueueCV.wait(Lock, [&] { return ShouldStop || !Queue.empty(); }); QueueCV.wait(Lock, [&] { return ShouldStop || !Queue.empty(); });
@ -186,11 +191,11 @@ void BackgroundIndex::run() {
Queue.pop_front(); Queue.pop_front();
} }
if (Priority != ThreadPriority::Normal) if (Priority != llvm::ThreadPriority::Default && !PreventStarvation.load())
setCurrentThreadPriority(Priority); llvm::set_thread_priority(Priority);
(*Task)(); (*Task)();
if (Priority != ThreadPriority::Normal) if (Priority != llvm::ThreadPriority::Default)
setCurrentThreadPriority(ThreadPriority::Normal); llvm::set_thread_priority(llvm::ThreadPriority::Default);
{ {
std::unique_lock<std::mutex> Lock(QueueMu); std::unique_lock<std::mutex> Lock(QueueMu);
@ -223,7 +228,7 @@ void BackgroundIndex::enqueue(const std::vector<std::string> &ChangedFiles) {
for (auto &Elem : NeedsReIndexing) for (auto &Elem : NeedsReIndexing)
enqueue(std::move(Elem.first), Elem.second); enqueue(std::move(Elem.first), Elem.second);
}, },
ThreadPriority::Normal); llvm::ThreadPriority::Default);
} }
void BackgroundIndex::enqueue(tooling::CompileCommand Cmd, void BackgroundIndex::enqueue(tooling::CompileCommand Cmd,
@ -238,10 +243,10 @@ void BackgroundIndex::enqueue(tooling::CompileCommand Cmd,
std::move(Error)); std::move(Error));
}, },
std::move(Cmd)), std::move(Cmd)),
ThreadPriority::Low); llvm::ThreadPriority::Background);
} }
void BackgroundIndex::enqueueTask(Task T, ThreadPriority Priority) { void BackgroundIndex::enqueueTask(Task T, llvm::ThreadPriority Priority) {
{ {
std::lock_guard<std::mutex> Lock(QueueMu); std::lock_guard<std::mutex> Lock(QueueMu);
auto I = Queue.end(); auto I = Queue.end();
@ -249,10 +254,11 @@ void BackgroundIndex::enqueueTask(Task T, ThreadPriority Priority) {
// Then we store low priority tasks. Normal priority tasks are pretty rare, // Then we store low priority tasks. Normal priority tasks are pretty rare,
// they should not grow beyond single-digit numbers, so it is OK to do // they should not grow beyond single-digit numbers, so it is OK to do
// linear search and insert after that. // linear search and insert after that.
if (Priority == ThreadPriority::Normal) { if (Priority == llvm::ThreadPriority::Default) {
I = llvm::find_if(Queue, [](const std::pair<Task, ThreadPriority> &Elem) { I = llvm::find_if(
return Elem.second == ThreadPriority::Low; Queue, [](const std::pair<Task, llvm::ThreadPriority> &Elem) {
}); return Elem.second == llvm::ThreadPriority::Background;
});
} }
Queue.insert(I, {std::move(T), Priority}); Queue.insert(I, {std::move(T), Priority});
} }
@ -611,5 +617,9 @@ BackgroundIndex::loadShards(std::vector<std::string> ChangedFiles) {
return NeedsReIndexing; return NeedsReIndexing;
} }
void BackgroundIndex::preventThreadStarvationInTests() {
PreventStarvation.store(true);
}
} // namespace clangd } // namespace clangd
} // namespace clang } // namespace clang

View File

@ -88,6 +88,10 @@ public:
LLVM_NODISCARD bool LLVM_NODISCARD bool
blockUntilIdleForTest(llvm::Optional<double> TimeoutSeconds = 10); blockUntilIdleForTest(llvm::Optional<double> TimeoutSeconds = 10);
// Disables thread priority lowering in background index to make sure it can
// progress on loaded systems. Only affects tasks that run after the call.
static void preventThreadStarvationInTests();
private: private:
/// Given index results from a TU, only update symbols coming from files with /// Given index results from a TU, only update symbols coming from files with
/// different digests than \p DigestsSnapshot. Also stores new index /// different digests than \p DigestsSnapshot. Also stores new index
@ -134,14 +138,14 @@ private:
// queue management // queue management
using Task = std::function<void()>; using Task = std::function<void()>;
void run(); // Main loop executed by Thread. Runs tasks from Queue. void run(); // Main loop executed by Thread. Runs tasks from Queue.
void enqueueTask(Task T, ThreadPriority Prioirty); void enqueueTask(Task T, llvm::ThreadPriority Prioirty);
void enqueueLocked(tooling::CompileCommand Cmd, void enqueueLocked(tooling::CompileCommand Cmd,
BackgroundIndexStorage *IndexStorage); BackgroundIndexStorage *IndexStorage);
std::mutex QueueMu; std::mutex QueueMu;
unsigned NumActiveTasks = 0; // Only idle when queue is empty *and* no tasks. unsigned NumActiveTasks = 0; // Only idle when queue is empty *and* no tasks.
std::condition_variable QueueCV; std::condition_variable QueueCV;
bool ShouldStop = false; bool ShouldStop = false;
std::deque<std::pair<Task, ThreadPriority>> Queue; std::deque<std::pair<Task, llvm::ThreadPriority>> Queue;
std::vector<std::thread> ThreadPool; // FIXME: Abstract this away. std::vector<std::thread> ThreadPool; // FIXME: Abstract this away.
GlobalCompilationDatabase::CommandChanged::Subscription CommandsChanged; GlobalCompilationDatabase::CommandChanged::Subscription CommandsChanged;
}; };

View File

@ -13,6 +13,7 @@
#include "Protocol.h" #include "Protocol.h"
#include "Trace.h" #include "Trace.h"
#include "Transport.h" #include "Transport.h"
#include "index/Background.h"
#include "index/Serialization.h" #include "index/Serialization.h"
#include "clang/Basic/Version.h" #include "clang/Basic/Version.h"
#include "llvm/ADT/Optional.h" #include "llvm/ADT/Optional.h"
@ -332,7 +333,8 @@ int main(int argc, char *argv[]) {
InputStyle = JSONStreamStyle::Delimited; InputStyle = JSONStreamStyle::Delimited;
LogLevel = Logger::Verbose; LogLevel = Logger::Verbose;
PrettyPrint = true; PrettyPrint = true;
preventThreadStarvationInTests(); // Ensure background index makes progress. // Ensure background index makes progress.
BackgroundIndex::preventThreadStarvationInTests();
} }
if (Test || EnableTestScheme) { if (Test || EnableTestScheme) {
static URISchemeRegistry::Add<TestScheme> X( static URISchemeRegistry::Add<TestScheme> X(

View File

@ -70,7 +70,7 @@ public:
class BackgroundIndexTest : public ::testing::Test { class BackgroundIndexTest : public ::testing::Test {
protected: protected:
BackgroundIndexTest() { preventThreadStarvationInTests(); } BackgroundIndexTest() { BackgroundIndex::preventThreadStarvationInTests(); }
}; };
TEST_F(BackgroundIndexTest, NoCrashOnErrorFile) { TEST_F(BackgroundIndexTest, NoCrashOnErrorFile) {