10#include "llvm/Config/llvm-config.h"
23#if LLVM_ENABLE_THREADS
26static thread_local unsigned threadIndex = UINT_MAX;
30thread_local unsigned threadIndex = UINT_MAX;
40 virtual ~Executor() =
default;
41 virtual void add(std::function<
void()>
func) = 0;
44 static Executor *getDefaultExecutor();
49class ThreadPoolExecutor :
public Executor {
57 std::lock_guard<std::mutex> Lock(
Mutex);
60 auto &Thread0 = Threads[0];
61 Thread0 = std::thread([
this, S] {
63 Threads.emplace_back([=] { work(S,
I); });
67 ThreadsCreated.set_value();
74 std::lock_guard<std::mutex> Lock(
Mutex);
80 ThreadsCreated.get_future().wait();
83 ~ThreadPoolExecutor()
override {
85 std::thread::id CurrentThreadId = std::this_thread::get_id();
86 for (std::thread &
T : Threads)
87 if (
T.get_id() == CurrentThreadId)
94 static void *call() {
return new ThreadPoolExecutor(
strategy); }
97 static void call(
void *
Ptr) { ((ThreadPoolExecutor *)
Ptr)->stop(); }
100 void add(std::function<
void()>
F)
override {
102 std::lock_guard<std::mutex> Lock(
Mutex);
103 WorkStack.push_back(std::move(
F));
112 threadIndex = ThreadID;
115 std::unique_lock<std::mutex> Lock(
Mutex);
116 Cond.wait(Lock, [&] {
return Stop || !WorkStack.empty(); });
119 auto Task = std::move(WorkStack.back());
120 WorkStack.pop_back();
126 std::atomic<bool> Stop{
false};
127 std::vector<std::function<void()>> WorkStack;
129 std::condition_variable
Cond;
130 std::promise<void> ThreadsCreated;
131 std::vector<std::thread> Threads;
135Executor *Executor::getDefaultExecutor() {
155 static ManagedStatic<ThreadPoolExecutor, ThreadPoolExecutor::Creator,
156 ThreadPoolExecutor::Deleter>
158 static std::unique_ptr<ThreadPoolExecutor> Exec(&(*ManagedExec));
165 static ThreadPoolExecutor Exec(
strategy);
173 return detail::Executor::getDefaultExecutor()->getThreadCount();
181TaskGroup::TaskGroup()
182#if LLVM_ENABLE_THREADS
184 (threadIndex == UINT_MAX)) {}
188TaskGroup::~TaskGroup() {
194void TaskGroup::spawn(std::function<
void()>
F) {
195#if LLVM_ENABLE_THREADS
198 detail::Executor::getDefaultExecutor()->add([&,
F = std::move(
F)] {
213#if LLVM_ENABLE_THREADS
214 if (parallel::strategy.ThreadsRequested != 1) {
215 auto NumItems =
End - Begin;
218 auto TaskSize = NumItems / parallel::detail::MaxTasksPerGroup;
223 for (; Begin + TaskSize <
End; Begin += TaskSize) {
225 for (
size_t I = Begin,
E = Begin + TaskSize;
I !=
E; ++
I)
231 for (
size_t I = Begin;
I !=
End; ++
I)
239 for (; Begin !=
End; ++Begin)
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
const SmallVectorImpl< MachineOperand > & Cond
static cl::opt< int > ThreadCount("threads", cl::init(0))
ManagedStatic - This transparently changes the behavior of global statics to be lazily constructed on...
This tells how a thread pool will be used.
void apply_thread_strategy(unsigned ThreadPoolNum) const
Assign the current thread to an ideal hardware CPU or NUMA node.
unsigned compute_thread_count() const
Retrieves the max available threads for the current strategy.
An efficient, type-erasing, non-owning reference to a callable.
void spawn(std::function< void()> f)
ThreadPoolStrategy strategy
unsigned getThreadIndex()
This is an optimization pass for GlobalISel generic memory operations.
void parallelFor(size_t Begin, size_t End, function_ref< void(size_t)> Fn)