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)});
119 void helpSync(
const parallel::detail::Latch &L) {
120 while (
L.getCount() != 0) {
121 std::unique_lock<std::mutex> Lock(
Mutex);
122 if (Stop || WorkStack.empty())
133 void popAndRun(std::unique_lock<std::mutex> &Lock) {
134 auto Item = std::move(WorkStack.back());
135 WorkStack.pop_back();
140 void work(ThreadPoolStrategy S,
unsigned ThreadID) {
141 threadIndex = ThreadID;
160 ExponentialBackoff Backoff(std::chrono::hours(24));
165 Slot = TheJobserver->tryAcquire();
168 }
while (Backoff.waitForNextAttempt());
171 [&] { TheJobserver->release(std::move(Slot)); });
174 std::unique_lock<std::mutex> Lock(
Mutex);
175 Cond.wait(Lock, [&] {
return Stop || !WorkStack.empty(); });
176 if (Stop && WorkStack.empty())
178 if (WorkStack.empty())
183 std::unique_lock<std::mutex> Lock(
Mutex);
184 Cond.wait(Lock, [&] {
return Stop || !WorkStack.empty(); });
192 std::atomic<bool> Stop{
false};
193 std::vector<WorkItem> WorkStack;
195 std::condition_variable
Cond;
196 std::promise<void> ThreadsCreated;
197 std::vector<std::thread> Threads;
200 JobserverClient *TheJobserver =
nullptr;
204static ThreadPoolExecutor *getDefaultExecutor() {
210 static ManagedStatic<ThreadPoolExecutor, ThreadPoolExecutor::Creator,
211 ThreadPoolExecutor::Deleter>
213 static std::unique_ptr<ThreadPoolExecutor>
Exec(&(*ManagedExec));
226 return getDefaultExecutor()->getThreadCount();
231#if LLVM_ENABLE_THREADS
232 return threadIndex != UINT_MAX;
240#
if LLVM_ENABLE_THREADS
249#if LLVM_ENABLE_THREADS
252 getDefaultExecutor()->helpSync(L);
258#if LLVM_ENABLE_THREADS
261 getDefaultExecutor()->add(std::move(
F), L);
270#if LLVM_ENABLE_THREADS
271 if (
strategy.ThreadsRequested != 1) {
272 size_t NumItems = End - Begin;
281 size_t ChunkSize = std::max(
size_t(1), NumItems / (NumWorkers * 4));
282 std::atomic<size_t> Idx{Begin};
285 size_t I = Idx.fetch_add(ChunkSize, std::memory_order_relaxed);
288 size_t IEnd = std::min(
I + ChunkSize, End);
289 for (;
I < IEnd; ++
I)
295 for (
size_t I = 0;
I != NumWorkers; ++
I)
301 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)