kadircet updated this revision to Diff 178094.
kadircet marked 2 inline comments as done.
kadircet added a comment.
- Use std::deque instead of std::list
Repository:
rCTE Clang Tools Extra
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D55315/new/
https://reviews.llvm.org/D55315
Files:
clangd/Threading.cpp
clangd/Threading.h
clangd/index/Background.cpp
clangd/index/Background.h
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,14 +111,14 @@
// queue management
using Task = std::function<void()>;
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;
+ std::mutex TasksMu;
unsigned NumActiveTasks = 0; // Only idle when queue is empty *and* no tasks.
- std::condition_variable QueueCV;
+ std::condition_variable TasksCV;
bool ShouldStop = false;
- std::deque<Task> Queue;
+ std::deque<std::pair<Task, ThreadPriority>> Tasks;
std::vector<std::thread> ThreadPool; // FIXME: Abstract this away.
GlobalCompilationDatabase::CommandChanged::Subscription CommandsChanged;
};
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"
@@ -102,14 +103,8 @@
})) {
assert(ThreadPoolSize > 0 && "Thread pool size can't be zero.");
assert(this->IndexStorageFactory && "Storage factory can not be null!");
- while (ThreadPoolSize--) {
+ 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);
- }
}
BackgroundIndex::~BackgroundIndex() {
@@ -120,86 +115,109 @@
void BackgroundIndex::stop() {
{
- std::lock_guard<std::mutex> Lock(QueueMu);
+ std::lock_guard<std::mutex> Lock(TasksMu);
ShouldStop = true;
}
- QueueCV.notify_all();
+ TasksCV.notify_all();
}
void BackgroundIndex::run() {
WithContext Background(BackgroundContext.clone());
while (true) {
Optional<Task> Task;
+ ThreadPriority Priority;
{
- std::unique_lock<std::mutex> Lock(QueueMu);
- QueueCV.wait(Lock, [&] { return ShouldStop || !Queue.empty(); });
+ std::unique_lock<std::mutex> Lock(TasksMu);
+ TasksCV.wait(Lock, [&] { return ShouldStop || !Tasks.empty(); });
if (ShouldStop) {
- Queue.clear();
- QueueCV.notify_all();
+ Tasks.clear();
+ TasksCV.notify_all();
return;
}
++NumActiveTasks;
- Task = std::move(Queue.front());
- Queue.pop_front();
+ std::tie(Task, Priority) = std::move(Tasks.front());
+ Tasks.pop_front();
}
+
+ if (Priority != ThreadPriority::Normal)
+ setCurrentThreadPriority(Priority);
(*Task)();
+ if (Priority != ThreadPriority::Normal)
+ setCurrentThreadPriority(ThreadPriority::Normal);
+
{
- std::unique_lock<std::mutex> Lock(QueueMu);
+ std::unique_lock<std::mutex> Lock(TasksMu);
assert(NumActiveTasks > 0 && "before decrementing");
--NumActiveTasks;
}
- QueueCV.notify_all();
+ TasksCV.notify_all();
}
}
bool BackgroundIndex::blockUntilIdleForTest(
llvm::Optional<double> TimeoutSeconds) {
- std::unique_lock<std::mutex> Lock(QueueMu);
- return wait(Lock, QueueCV, timeoutSeconds(TimeoutSeconds),
- [&] { return Queue.empty() && NumActiveTasks == 0; });
+ std::unique_lock<std::mutex> Lock(TasksMu);
+ return wait(Lock, TasksCV, timeoutSeconds(TimeoutSeconds),
+ [&] { return Tasks.empty() && NumActiveTasks == 0; });
}
void BackgroundIndex::enqueue(const std::vector<std::string> &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<unsigned> 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<unsigned> 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<std::mutex> Lock(QueueMu);
- Queue.push_back(std::move(T));
+ std::lock_guard<std::mutex> Lock(TasksMu);
+ auto I = Tasks.end();
+ // We first store the tasks with Normal priority in the front of the queue.
+ // 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
+ // linear search and insert after that.
+ if (Priority == ThreadPriority::Normal) {
+ I = llvm::find_if(Tasks, [](const std::pair<Task, ThreadPriority> &Elem) {
+ return Elem.second == ThreadPriority::Low;
+ });
+ }
+ Tasks.insert(I, {std::move(T), Priority});
}
- QueueCV.notify_all();
+ TasksCV.notify_all();
}
/// Given index results from a TU, only update files in \p FilesToUpdate.
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<bool> 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);
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits