11#include "llvm/Config/llvm-config.h"
29#if LLVM_ENABLE_THREADS
32static thread_local unsigned threadIndex = UINT_MAX;
36thread_local unsigned parallel::threadIndex = UINT_MAX;
42class ThreadPoolExecutor {
53 std::lock_guard<std::mutex> Lock(
Mutex);
56 auto &Thread0 = Threads[0];
57 Thread0 = std::thread([
this, S] {
59 Threads.emplace_back([
this, S,
I] { work(S,
I); });
63 ThreadsCreated.set_value();
70 ThreadPoolExecutor() =
delete;
74 std::lock_guard<std::mutex> Lock(
Mutex);
80 ThreadsCreated.get_future().wait();
82 std::thread::id CurrentThreadId = std::this_thread::get_id();
83 for (std::thread &
T : Threads)
84 if (
T.get_id() == CurrentThreadId)
90 ~ThreadPoolExecutor() { stop(); }
93 static void *call() {
return new ThreadPoolExecutor(
strategy); }
96 static void call(
void *Ptr) { ((ThreadPoolExecutor *)Ptr)->stop(); }
100 std::function<void()>
F;
101 std::reference_wrapper<parallel::detail::Latch>
L;
108 void add(std::function<
void()>
F, parallel::detail::Latch &L) {
110 std::lock_guard<std::mutex> Lock(
Mutex);
111 WorkStack.push_back({std::move(
F), std::ref(L)});
121 void popAndRun(std::unique_lock<std::mutex> &Lock) {
122 auto Item = std::move(WorkStack.back());
123 WorkStack.pop_back();
128 void work(ThreadPoolStrategy S,
unsigned ThreadID) {
129 threadIndex = ThreadID;
148 ExponentialBackoff Backoff(std::chrono::hours(24));
153 Slot = TheJobserver->tryAcquire();
156 }
while (Backoff.waitForNextAttempt());
159 [&] { TheJobserver->release(std::move(Slot)); });
162 std::unique_lock<std::mutex> Lock(
Mutex);
163 Cond.wait(Lock, [&] {
return Stop || !WorkStack.empty(); });
164 if (Stop && WorkStack.empty())
166 if (WorkStack.empty())
171 std::unique_lock<std::mutex> Lock(
Mutex);
172 Cond.wait(Lock, [&] {
return Stop || !WorkStack.empty(); });
180 std::atomic<bool> Stop{
false};
181 std::vector<WorkItem> WorkStack;
183 std::condition_variable
Cond;
184 std::promise<void> ThreadsCreated;
185 std::vector<std::thread> Threads;
188 JobserverClient *TheJobserver =
nullptr;
192static ThreadPoolExecutor *getDefaultExecutor() {
198 static ManagedStatic<ThreadPoolExecutor, ThreadPoolExecutor::Creator,
199 ThreadPoolExecutor::Deleter>
201 static std::unique_ptr<ThreadPoolExecutor>
Exec(&(*ManagedExec));
214 return getDefaultExecutor()->getThreadCount();
224#
if LLVM_ENABLE_THREADS
225 strategy.ThreadsRequested != 1 && threadIndex == UINT_MAX
238#if LLVM_ENABLE_THREADS
241 getDefaultExecutor()->add(std::move(
F), L);
250#if LLVM_ENABLE_THREADS
251 if (
strategy.ThreadsRequested != 1) {
252 size_t NumItems = End - Begin;
261 size_t ChunkSize = std::max(
size_t(1), NumItems / (NumWorkers * 4));
262 std::atomic<size_t> Idx{Begin};
265 size_t I = Idx.fetch_add(ChunkSize, std::memory_order_relaxed);
268 size_t IEnd = std::min(
I + ChunkSize, End);
269 for (;
I < IEnd; ++
I)
275 for (
size_t I = 0;
I != NumWorkers; ++
I)
281 for (; Begin != End; ++Begin)
const SmallVectorImpl< MachineOperand > & Cond
This file defines the make_scope_exit function, which executes user-defined cleanup logic at scope ex...
static cl::opt< int > ThreadCount("threads", cl::init(0))
static LLVM_ABI_FOR_TEST JobserverClient * getInstance()
Returns the singleton instance of the JobserverClient.
ManagedStatic - This transparently changes the behavior of global statics to be lazily constructed on...
This tells how a thread pool will be used.
LLVM_ABI void apply_thread_strategy(unsigned ThreadPoolNum) const
Assign the current thread to an ideal hardware CPU or NUMA node.
LLVM_ABI unsigned compute_thread_count() const
Retrieves the max available threads for the current strategy.
bool UseJobserver
If true, the thread pool will attempt to coordinate with a GNU Make jobserver, acquiring a job slot b...
An efficient, type-erasing, non-owning reference to a callable.
LLVM_ABI void spawn(std::function< void()> f)
LLVM_ABI ThreadPoolStrategy strategy
unsigned getThreadIndex()
SmartMutex< false > Mutex
Mutex - A standard, always enforced mutex.
This is an optimization pass for GlobalISel generic memory operations.
scope_exit(Callable) -> scope_exit< Callable >
LLVM_ABI void parallelFor(size_t Begin, size_t End, function_ref< void(size_t)> Fn)