11#include "llvm/Config/llvm-config.h"
29#if LLVM_ENABLE_THREADS
31static thread_local unsigned threadIndex = UINT_MAX;
36class ThreadPoolExecutor {
47 std::lock_guard<std::mutex> Lock(
Mutex);
50 auto &Thread0 = Threads[0];
51 Thread0 = std::thread([
this, S] {
53 Threads.emplace_back([
this, S,
I] { work(S,
I); });
57 ThreadsCreated.set_value();
64 ThreadPoolExecutor() =
delete;
68 std::lock_guard<std::mutex> Lock(
Mutex);
74 ThreadsCreated.get_future().wait();
76 std::thread::id CurrentThreadId = std::this_thread::get_id();
77 for (std::thread &
T : Threads)
78 if (
T.get_id() == CurrentThreadId)
84 ~ThreadPoolExecutor() { stop(); }
87 static void *call() {
return new ThreadPoolExecutor(
strategy); }
90 static void call(
void *Ptr) { ((ThreadPoolExecutor *)Ptr)->stop(); }
94 std::function<void()>
F;
95 std::reference_wrapper<parallel::detail::Latch> L;
104 std::lock_guard<std::mutex> Lock(
Mutex);
105 WorkStack.push_back({std::move(
F), std::ref(L)});
114 while (L.getCount() != 0) {
115 std::unique_lock<std::mutex> Lock(
Mutex);
116 if (Stop || WorkStack.empty())
127 void popAndRun(std::unique_lock<std::mutex> &Lock) {
128 auto Item = std::move(WorkStack.back());
129 WorkStack.pop_back();
135 threadIndex = ThreadID;
159 Slot = TheJobserver->tryAcquire();
165 [&] { TheJobserver->release(std::move(Slot)); });
168 std::unique_lock<std::mutex> Lock(
Mutex);
169 Cond.wait(Lock, [&] {
return Stop || !WorkStack.empty(); });
170 if (Stop && WorkStack.empty())
172 if (WorkStack.empty())
177 std::unique_lock<std::mutex> Lock(
Mutex);
178 Cond.wait(Lock, [&] {
return Stop || !WorkStack.empty(); });
186 std::atomic<bool> Stop{
false};
187 std::vector<WorkItem> WorkStack;
189 std::condition_variable
Cond;
190 std::promise<void> ThreadsCreated;
191 std::vector<std::thread> Threads;
198static ThreadPoolExecutor *getDefaultExecutor() {
204 static ManagedStatic<ThreadPoolExecutor, ThreadPoolExecutor::Creator,
205 ThreadPoolExecutor::Deleter>
207 static std::unique_ptr<ThreadPoolExecutor> Exec(&(*ManagedExec));
214 static ThreadPoolExecutor Exec(
strategy);
220 return getDefaultExecutor()->getThreadCount();
226#
if LLVM_ENABLE_THREADS
235#if LLVM_ENABLE_THREADS
237 bool IsNested = threadIndex != UINT_MAX;
238 if (Parallel && IsNested)
239 getDefaultExecutor()->helpSync(L);
245#if LLVM_ENABLE_THREADS
248 getDefaultExecutor()->add(std::move(
F), L);
257#if LLVM_ENABLE_THREADS
258 if (
strategy.ThreadsRequested != 1) {
259 size_t NumItems = End - Begin;
268 size_t ChunkSize = std::max(
size_t(1), NumItems / (NumWorkers * 4));
269 std::atomic<size_t> Idx{Begin};
272 size_t I = Idx.fetch_add(ChunkSize, std::memory_order_relaxed);
275 size_t IEnd = std::min(
I + ChunkSize, End);
276 for (;
I < IEnd; ++
I)
291 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))
A class to help implement exponential backoff.
LLVM_ABI bool waitForNextAttempt()
Blocks while waiting for the next attempt.
A JobSlot represents a single job slot that can be acquired from or released to a jobserver pool.
The public interface for a jobserver client.
static 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
SmartMutex< false > Mutex
Mutex - A standard, always enforced mutex.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI void parallelFor(size_t Begin, size_t End, function_ref< void(size_t)> Fn)