blob: 010e42916f957633f57b8531d870bf37930b9b43 [file] [log] [blame]
Zachary Turner3a57fbd2017-05-11 00:03:52 +00001//===- llvm/Support/Parallel.cpp - Parallel algorithms --------------------===//
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +00002//
Zachary Turner3a57fbd2017-05-11 00:03:52 +00003// The LLVM Compiler Infrastructure
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +00004//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Zachary Turner3a57fbd2017-05-11 00:03:52 +000010#include "llvm/Support/Parallel.h"
Zachary Turner6083b2b2017-05-05 21:14:55 +000011#include "llvm/Config/llvm-config.h"
Rafael Espindola8c0ff952017-10-04 20:27:01 +000012#include "llvm/Support/Threading.h"
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +000013
14#include <atomic>
15#include <stack>
Rui Ueyama552c2902017-05-05 21:27:30 +000016#include <thread>
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +000017
Zachary Turner3a57fbd2017-05-11 00:03:52 +000018using namespace llvm;
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +000019
20namespace {
21
22/// \brief An abstract class that takes closures and runs them asynchronously.
23class Executor {
24public:
25 virtual ~Executor() = default;
26 virtual void add(std::function<void()> func) = 0;
27
28 static Executor *getDefaultExecutor();
29};
30
31#if !LLVM_ENABLE_THREADS
32class SyncExecutor : public Executor {
33public:
34 virtual void add(std::function<void()> F) { F(); }
35};
36
37Executor *Executor::getDefaultExecutor() {
38 static SyncExecutor Exec;
39 return &Exec;
40}
41
42#elif defined(_MSC_VER)
43/// \brief An Executor that runs tasks via ConcRT.
44class ConcRTExecutor : public Executor {
45 struct Taskish {
46 Taskish(std::function<void()> Task) : Task(Task) {}
47
48 std::function<void()> Task;
49
50 static void run(void *P) {
51 Taskish *Self = static_cast<Taskish *>(P);
52 Self->Task();
53 concurrency::Free(Self);
54 }
55 };
56
57public:
58 virtual void add(std::function<void()> F) {
59 Concurrency::CurrentScheduler::ScheduleTask(
60 Taskish::run, new (concurrency::Alloc(sizeof(Taskish))) Taskish(F));
61 }
62};
63
64Executor *Executor::getDefaultExecutor() {
65 static ConcRTExecutor exec;
66 return &exec;
67}
68
69#else
70/// \brief An implementation of an Executor that runs closures on a thread pool
71/// in filo order.
72class ThreadPoolExecutor : public Executor {
73public:
Rafael Espindola8c0ff952017-10-04 20:27:01 +000074 explicit ThreadPoolExecutor(unsigned ThreadCount = hardware_concurrency())
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +000075 : Done(ThreadCount) {
76 // Spawn all but one of the threads in another thread as spawning threads
77 // can take a while.
78 std::thread([&, ThreadCount] {
79 for (size_t i = 1; i < ThreadCount; ++i) {
80 std::thread([=] { work(); }).detach();
81 }
82 work();
83 }).detach();
84 }
85
86 ~ThreadPoolExecutor() override {
87 std::unique_lock<std::mutex> Lock(Mutex);
88 Stop = true;
89 Lock.unlock();
90 Cond.notify_all();
91 // Wait for ~Latch.
92 }
93
94 void add(std::function<void()> F) override {
95 std::unique_lock<std::mutex> Lock(Mutex);
96 WorkStack.push(F);
97 Lock.unlock();
98 Cond.notify_one();
99 }
100
101private:
102 void work() {
103 while (true) {
104 std::unique_lock<std::mutex> Lock(Mutex);
105 Cond.wait(Lock, [&] { return Stop || !WorkStack.empty(); });
106 if (Stop)
107 break;
108 auto Task = WorkStack.top();
109 WorkStack.pop();
110 Lock.unlock();
111 Task();
112 }
113 Done.dec();
114 }
115
116 std::atomic<bool> Stop{false};
117 std::stack<std::function<void()>> WorkStack;
118 std::mutex Mutex;
119 std::condition_variable Cond;
Zachary Turner7a2d5682017-05-11 00:22:18 +0000120 parallel::detail::Latch Done;
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +0000121};
122
123Executor *Executor::getDefaultExecutor() {
124 static ThreadPoolExecutor exec;
125 return &exec;
126}
127#endif
128}
129
Hans Wennborg905da742017-05-11 15:32:47 +0000130#if LLVM_ENABLE_THREADS
Zachary Turner20c8e912017-05-11 00:18:52 +0000131void parallel::detail::TaskGroup::spawn(std::function<void()> F) {
Zachary Turner0a340ce2017-05-10 17:39:18 +0000132 L.inc();
133 Executor::getDefaultExecutor()->add([&, F] {
134 F();
135 L.dec();
Zachary Turnerf7ca8fc2017-05-05 21:09:26 +0000136 });
137}
Hans Wennborg905da742017-05-11 15:32:47 +0000138#endif