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(); }
99 void add(std::function<
void()>
F) {
101 std::lock_guard<std::mutex> Lock(
Mutex);
102 WorkStack.push_back(std::move(
F));
110 void work(ThreadPoolStrategy S,
unsigned ThreadID) {
111 threadIndex = ThreadID;
130 ExponentialBackoff Backoff(std::chrono::hours(24));
135 Slot = TheJobserver->tryAcquire();
138 }
while (Backoff.waitForNextAttempt());
141 [&] { TheJobserver->release(std::move(Slot)); });
144 std::function<void()> Task;
146 std::unique_lock<std::mutex> Lock(
Mutex);
147 Cond.wait(Lock, [&] {
return Stop || !WorkStack.empty(); });
148 if (Stop && WorkStack.empty())
150 if (WorkStack.empty())
152 Task = std::move(WorkStack.back());
153 WorkStack.pop_back();
158 std::unique_lock<std::mutex> Lock(
Mutex);
159 Cond.wait(Lock, [&] {
return Stop || !WorkStack.empty(); });
162 auto Task = std::move(WorkStack.back());
163 WorkStack.pop_back();
170 std::atomic<bool> Stop{
false};
171 std::vector<std::function<void()>> WorkStack;
173 std::condition_variable
Cond;
174 std::promise<void> ThreadsCreated;
175 std::vector<std::thread> Threads;
178 JobserverClient *TheJobserver =
nullptr;
182static ThreadPoolExecutor *getDefaultExecutor() {
188 static ManagedStatic<ThreadPoolExecutor, ThreadPoolExecutor::Creator,
189 ThreadPoolExecutor::Deleter>
191 static std::unique_ptr<ThreadPoolExecutor>
Exec(&(*ManagedExec));
204 return getDefaultExecutor()->getThreadCount();
214#
if LLVM_ENABLE_THREADS
215 strategy.ThreadsRequested != 1 && threadIndex == UINT_MAX
228#if LLVM_ENABLE_THREADS
231 getDefaultExecutor()->add([&,
F = std::move(
F)] {
243#if LLVM_ENABLE_THREADS
244 if (
strategy.ThreadsRequested != 1) {
245 size_t NumItems = End - Begin;
254 size_t ChunkSize = std::max(
size_t(1), NumItems / (NumWorkers * 4));
255 std::atomic<size_t> Idx{Begin};
258 size_t I = Idx.fetch_add(ChunkSize, std::memory_order_relaxed);
261 size_t IEnd = std::min(
I + ChunkSize, End);
262 for (;
I < IEnd; ++
I)
268 for (
size_t I = 0;
I != NumWorkers; ++
I)
274 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)