15517e702SDimitry Andric //===- llvm/Support/Parallel.cpp - Parallel algorithms --------------------===// 25517e702SDimitry Andric // 35517e702SDimitry Andric // The LLVM Compiler Infrastructure 45517e702SDimitry Andric // 55517e702SDimitry Andric // This file is distributed under the University of Illinois Open Source 65517e702SDimitry Andric // License. See LICENSE.TXT for details. 75517e702SDimitry Andric // 85517e702SDimitry Andric //===----------------------------------------------------------------------===// 95517e702SDimitry Andric 105517e702SDimitry Andric #include "llvm/Support/Parallel.h" 115517e702SDimitry Andric #include "llvm/Config/llvm-config.h" 12*4ba319b5SDimitry Andric 13*4ba319b5SDimitry Andric #if LLVM_ENABLE_THREADS 14*4ba319b5SDimitry Andric 152cab237bSDimitry Andric #include "llvm/Support/Threading.h" 165517e702SDimitry Andric 175517e702SDimitry Andric #include <atomic> 185517e702SDimitry Andric #include <stack> 195517e702SDimitry Andric #include <thread> 205517e702SDimitry Andric 215517e702SDimitry Andric using namespace llvm; 225517e702SDimitry Andric 235517e702SDimitry Andric namespace { 245517e702SDimitry Andric 25*4ba319b5SDimitry Andric /// An abstract class that takes closures and runs them asynchronously. 265517e702SDimitry Andric class Executor { 275517e702SDimitry Andric public: 285517e702SDimitry Andric virtual ~Executor() = default; 295517e702SDimitry Andric virtual void add(std::function<void()> func) = 0; 305517e702SDimitry Andric 315517e702SDimitry Andric static Executor *getDefaultExecutor(); 325517e702SDimitry Andric }; 335517e702SDimitry Andric 34*4ba319b5SDimitry Andric #if defined(_MSC_VER) 35*4ba319b5SDimitry Andric /// An Executor that runs tasks via ConcRT. 365517e702SDimitry Andric class ConcRTExecutor : public Executor { 375517e702SDimitry Andric struct Taskish { Taskish__anon6be6bc8e0111::ConcRTExecutor::Taskish385517e702SDimitry Andric Taskish(std::function<void()> Task) : Task(Task) {} 395517e702SDimitry Andric 405517e702SDimitry Andric std::function<void()> Task; 415517e702SDimitry Andric run__anon6be6bc8e0111::ConcRTExecutor::Taskish425517e702SDimitry Andric static void run(void *P) { 435517e702SDimitry Andric Taskish *Self = static_cast<Taskish *>(P); 445517e702SDimitry Andric Self->Task(); 455517e702SDimitry Andric concurrency::Free(Self); 465517e702SDimitry Andric } 475517e702SDimitry Andric }; 485517e702SDimitry Andric 495517e702SDimitry Andric public: add(std::function<void ()> F)505517e702SDimitry Andric virtual void add(std::function<void()> F) { 515517e702SDimitry Andric Concurrency::CurrentScheduler::ScheduleTask( 525517e702SDimitry Andric Taskish::run, new (concurrency::Alloc(sizeof(Taskish))) Taskish(F)); 535517e702SDimitry Andric } 545517e702SDimitry Andric }; 555517e702SDimitry Andric getDefaultExecutor()565517e702SDimitry AndricExecutor *Executor::getDefaultExecutor() { 575517e702SDimitry Andric static ConcRTExecutor exec; 585517e702SDimitry Andric return &exec; 595517e702SDimitry Andric } 605517e702SDimitry Andric 615517e702SDimitry Andric #else 62*4ba319b5SDimitry Andric /// An implementation of an Executor that runs closures on a thread pool 635517e702SDimitry Andric /// in filo order. 645517e702SDimitry Andric class ThreadPoolExecutor : public Executor { 655517e702SDimitry Andric public: ThreadPoolExecutor(unsigned ThreadCount=hardware_concurrency ())662cab237bSDimitry Andric explicit ThreadPoolExecutor(unsigned ThreadCount = hardware_concurrency()) 675517e702SDimitry Andric : Done(ThreadCount) { 685517e702SDimitry Andric // Spawn all but one of the threads in another thread as spawning threads 695517e702SDimitry Andric // can take a while. 705517e702SDimitry Andric std::thread([&, ThreadCount] { 715517e702SDimitry Andric for (size_t i = 1; i < ThreadCount; ++i) { 725517e702SDimitry Andric std::thread([=] { work(); }).detach(); 735517e702SDimitry Andric } 745517e702SDimitry Andric work(); 755517e702SDimitry Andric }).detach(); 765517e702SDimitry Andric } 775517e702SDimitry Andric ~ThreadPoolExecutor()785517e702SDimitry Andric ~ThreadPoolExecutor() override { 795517e702SDimitry Andric std::unique_lock<std::mutex> Lock(Mutex); 805517e702SDimitry Andric Stop = true; 815517e702SDimitry Andric Lock.unlock(); 825517e702SDimitry Andric Cond.notify_all(); 835517e702SDimitry Andric // Wait for ~Latch. 845517e702SDimitry Andric } 855517e702SDimitry Andric add(std::function<void ()> F)865517e702SDimitry Andric void add(std::function<void()> F) override { 875517e702SDimitry Andric std::unique_lock<std::mutex> Lock(Mutex); 885517e702SDimitry Andric WorkStack.push(F); 895517e702SDimitry Andric Lock.unlock(); 905517e702SDimitry Andric Cond.notify_one(); 915517e702SDimitry Andric } 925517e702SDimitry Andric 935517e702SDimitry Andric private: work()945517e702SDimitry Andric void work() { 955517e702SDimitry Andric while (true) { 965517e702SDimitry Andric std::unique_lock<std::mutex> Lock(Mutex); 975517e702SDimitry Andric Cond.wait(Lock, [&] { return Stop || !WorkStack.empty(); }); 985517e702SDimitry Andric if (Stop) 995517e702SDimitry Andric break; 1005517e702SDimitry Andric auto Task = WorkStack.top(); 1015517e702SDimitry Andric WorkStack.pop(); 1025517e702SDimitry Andric Lock.unlock(); 1035517e702SDimitry Andric Task(); 1045517e702SDimitry Andric } 1055517e702SDimitry Andric Done.dec(); 1065517e702SDimitry Andric } 1075517e702SDimitry Andric 1085517e702SDimitry Andric std::atomic<bool> Stop{false}; 1095517e702SDimitry Andric std::stack<std::function<void()>> WorkStack; 1105517e702SDimitry Andric std::mutex Mutex; 1115517e702SDimitry Andric std::condition_variable Cond; 1125517e702SDimitry Andric parallel::detail::Latch Done; 1135517e702SDimitry Andric }; 1145517e702SDimitry Andric getDefaultExecutor()1155517e702SDimitry AndricExecutor *Executor::getDefaultExecutor() { 1165517e702SDimitry Andric static ThreadPoolExecutor exec; 1175517e702SDimitry Andric return &exec; 1185517e702SDimitry Andric } 1195517e702SDimitry Andric #endif 1205517e702SDimitry Andric } 1215517e702SDimitry Andric spawn(std::function<void ()> F)1225517e702SDimitry Andricvoid parallel::detail::TaskGroup::spawn(std::function<void()> F) { 1235517e702SDimitry Andric L.inc(); 1245517e702SDimitry Andric Executor::getDefaultExecutor()->add([&, F] { 1255517e702SDimitry Andric F(); 1265517e702SDimitry Andric L.dec(); 1275517e702SDimitry Andric }); 1285517e702SDimitry Andric } 129*4ba319b5SDimitry Andric #endif // LLVM_ENABLE_THREADS 130