[lld] r302288 - Split up Parallel and LLVM'ize naming conventions.
Rui Ueyama via llvm-commits
llvm-commits at lists.llvm.org
Fri May 5 14:27:45 PDT 2017
On Fri, May 5, 2017 at 2:09 PM, Zachary Turner via llvm-commits <
llvm-commits at lists.llvm.org> wrote:
> Author: zturner
> Date: Fri May 5 16:09:26 2017
> New Revision: 302288
>
> URL: http://llvm.org/viewvc/llvm-project?rev=302288&view=rev
> Log:
> Split up Parallel and LLVM'ize naming conventions.
>
> This is one step in preparation of raising this up to
> LLVM. This hides all of the Executor stuff in a private
> implementation file, leaving only the core algorithms and
> the TaskGroup class exposed. In doing so, fix up all the
> variable names to conform to LLVM style.
>
> Differential Revision: https://reviews.llvm.org/D32890
>
> Added:
> lld/trunk/include/lld/Core/TaskGroup.h
> lld/trunk/lib/Core/TaskGroup.cpp
> Modified:
> lld/trunk/include/lld/Core/Parallel.h
> lld/trunk/lib/Core/CMakeLists.txt
> lld/trunk/unittests/CoreTests/CMakeLists.txt
>
> Modified: lld/trunk/include/lld/Core/Parallel.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/
> Core/Parallel.h?rev=302288&r1=302287&r2=302288&view=diff
> ============================================================
> ==================
> --- lld/trunk/include/lld/Core/Parallel.h (original)
> +++ lld/trunk/include/lld/Core/Parallel.h Fri May 5 16:09:26 2017
> @@ -10,16 +10,12 @@
> #ifndef LLD_CORE_PARALLEL_H
> #define LLD_CORE_PARALLEL_H
>
> -#include "lld/Core/Instrumentation.h"
> #include "lld/Core/LLVM.h"
> +#include "lld/Core/TaskGroup.h"
> #include "llvm/Support/MathExtras.h"
> -#include "llvm/Support/thread.h"
> +#include "llvm/config/llvm-config.h"
>
> #include <algorithm>
> -#include <atomic>
> -#include <condition_variable>
> -#include <mutex>
> -#include <stack>
>
> #if defined(_MSC_VER) && LLVM_ENABLE_THREADS
> #include <concrt.h>
> @@ -27,249 +23,84 @@
> #endif
>
> namespace lld {
> -/// \brief Allows one or more threads to wait on a potentially unknown
> number of
> -/// events.
> -///
> -/// A latch starts at \p count. inc() increments this, and dec()
> decrements it.
> -/// All calls to sync() will block while the count is not 0.
> -///
> -/// Calling dec() on a Latch with a count of 0 has undefined behaivor.
> -class Latch {
> - uint32_t _count;
> - mutable std::mutex _condMut;
> - mutable std::condition_variable _cond;
> -
> -public:
> - explicit Latch(uint32_t count = 0) : _count(count) {}
> - ~Latch() { sync(); }
> -
> - void inc() {
> - std::unique_lock<std::mutex> lock(_condMut);
> - ++_count;
> - }
> -
> - void dec() {
> - std::unique_lock<std::mutex> lock(_condMut);
> - if (--_count == 0)
> - _cond.notify_all();
> - }
> -
> - void sync() const {
> - std::unique_lock<std::mutex> lock(_condMut);
> - _cond.wait(lock, [&] {
> - return _count == 0;
> - });
> - }
> -};
> -
> -// Classes in this namespace are implementation details of this header.
> -namespace internal {
> -
> -/// \brief An abstract class that takes closures and runs them
> asynchronously.
> -class Executor {
> -public:
> - virtual ~Executor() = default;
> - virtual void add(std::function<void()> func) = 0;
> -};
> -
> -#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0
> -class SyncExecutor : public Executor {
> -public:
> - virtual void add(std::function<void()> func) {
> - func();
> - }
> -};
> -
> -inline Executor *getDefaultExecutor() {
> - static SyncExecutor exec;
> - return &exec;
> -}
> -#elif defined(_MSC_VER)
> -/// \brief An Executor that runs tasks via ConcRT.
> -class ConcRTExecutor : public Executor {
> - struct Taskish {
> - Taskish(std::function<void()> task) : _task(task) {}
> -
> - std::function<void()> _task;
> -
> - static void run(void *p) {
> - Taskish *self = static_cast<Taskish *>(p);
> - self->_task();
> - concurrency::Free(self);
> - }
> - };
> -
> -public:
> - virtual void add(std::function<void()> func) {
> - Concurrency::CurrentScheduler::ScheduleTask(Taskish::run,
> - new (concurrency::Alloc(sizeof(Taskish))) Taskish(func));
> - }
> -};
> -
> -inline Executor *getDefaultExecutor() {
> - static ConcRTExecutor exec;
> - return &exec;
> -}
> -#else
> -/// \brief An implementation of an Executor that runs closures on a
> thread pool
> -/// in filo order.
> -class ThreadPoolExecutor : public Executor {
> -public:
> - explicit ThreadPoolExecutor(unsigned threadCount =
> - std::thread::hardware_concurrency())
> - : _stop(false), _done(threadCount) {
> - // Spawn all but one of the threads in another thread as spawning
> threads
> - // can take a while.
> - std::thread([&, threadCount] {
> - for (size_t i = 1; i < threadCount; ++i) {
> - std::thread([=] {
> - work();
> - }).detach();
> - }
> - work();
> - }).detach();
> - }
> -
> - ~ThreadPoolExecutor() override {
> - std::unique_lock<std::mutex> lock(_mutex);
> - _stop = true;
> - lock.unlock();
> - _cond.notify_all();
> - // Wait for ~Latch.
> - }
> -
> - void add(std::function<void()> f) override {
> - std::unique_lock<std::mutex> lock(_mutex);
> - _workStack.push(f);
> - lock.unlock();
> - _cond.notify_one();
> - }
> -
> -private:
> - void work() {
> - while (true) {
> - std::unique_lock<std::mutex> lock(_mutex);
> - _cond.wait(lock, [&] {
> - return _stop || !_workStack.empty();
> - });
> - if (_stop)
> - break;
> - auto task = _workStack.top();
> - _workStack.pop();
> - lock.unlock();
> - task();
> - }
> - _done.dec();
> - }
> -
> - std::atomic<bool> _stop;
> - std::stack<std::function<void()>> _workStack;
> - std::mutex _mutex;
> - std::condition_variable _cond;
> - Latch _done;
> -};
> -
> -inline Executor *getDefaultExecutor() {
> - static ThreadPoolExecutor exec;
> - return &exec;
> -}
> -#endif
> -
> -} // namespace internal
> -
> -/// \brief Allows launching a number of tasks and waiting for them to
> finish
> -/// either explicitly via sync() or implicitly on destruction.
> -class TaskGroup {
> - Latch _latch;
>
You missed to fix this variable name.
> -
> -public:
> - void spawn(std::function<void()> f) {
> - _latch.inc();
> - internal::getDefaultExecutor()->add([&, f] {
> - f();
> - _latch.dec();
> - });
> - }
> -
> - void sync() const { _latch.sync(); }
> -};
>
> -#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0
> -template <class RandomAccessIterator, class Comp>
> +#if !LLVM_ENABLE_THREADS
> +template <class RandomAccessIterator, class Comparator>
> void parallel_sort(
> - RandomAccessIterator start, RandomAccessIterator end,
> - const Comp &comp = std::less<
> + RandomAccessIterator Start, RandomAccessIterator End,
> + const Comparator &Comp = std::less<
> typename std::iterator_traits<RandomAccessIterator>::value_type>())
> {
> - std::sort(start, end, comp);
> + std::sort(Start, End, Comp);
> }
> #elif defined(_MSC_VER)
> // Use ppl parallel_sort on Windows.
> -template <class RandomAccessIterator, class Comp>
> +template <class RandomAccessIterator, class Comparator>
> void parallel_sort(
> - RandomAccessIterator start, RandomAccessIterator end,
> - const Comp &comp = std::less<
> + RandomAccessIterator Start, RandomAccessIterator End,
> + const Comparator &Comp = std::less<
> typename std::iterator_traits<RandomAccessIterator>::value_type>())
> {
> - concurrency::parallel_sort(start, end, comp);
> + concurrency::parallel_sort(Start, End, Comp);
> }
> #else
> namespace detail {
> -const ptrdiff_t minParallelSize = 1024;
> +const ptrdiff_t MinParallelSize = 1024;
>
> /// \brief Inclusive median.
> -template <class RandomAccessIterator, class Comp>
> -RandomAccessIterator medianOf3(RandomAccessIterator start,
> - RandomAccessIterator end, const Comp
> &comp) {
> - RandomAccessIterator mid = start + (std::distance(start, end) / 2);
> - return comp(*start, *(end - 1))
> - ? (comp(*mid, *(end - 1)) ? (comp(*start, *mid) ? mid : start)
> - : end - 1)
> - : (comp(*mid, *start) ? (comp(*(end - 1), *mid) ? mid : end - 1)
> - : start);
> +template <class RandomAccessIterator, class Comparator>
> +RandomAccessIterator medianOf3(RandomAccessIterator Start,
> + RandomAccessIterator End,
> + const Comparator &Comp) {
> + RandomAccessIterator Mid = Start + (std::distance(Start, End) / 2);
> + return Comp(*Start, *(End - 1))
> + ? (Comp(*Mid, *(End - 1)) ? (Comp(*Start, *Mid) ? Mid :
> Start)
> + : End - 1)
> + : (Comp(*Mid, *Start) ? (Comp(*(End - 1), *Mid) ? Mid : End
> - 1)
> + : Start);
> }
>
> -template <class RandomAccessIterator, class Comp>
> -void parallel_quick_sort(RandomAccessIterator start,
> RandomAccessIterator end,
> - const Comp &comp, TaskGroup &tg, size_t depth) {
> +template <class RandomAccessIterator, class Comparator>
> +void parallel_quick_sort(RandomAccessIterator Start,
> RandomAccessIterator End,
> + const Comparator &Comp, TaskGroup &TG, size_t
> Depth) {
> // Do a sequential sort for small inputs.
> - if (std::distance(start, end) < detail::minParallelSize || depth == 0) {
> - std::sort(start, end, comp);
> + if (std::distance(Start, End) < detail::MinParallelSize || Depth == 0) {
> + std::sort(Start, End, Comp);
> return;
> }
>
> // Partition.
> - auto pivot = medianOf3(start, end, comp);
> - // Move pivot to end.
> - std::swap(*(end - 1), *pivot);
> - pivot = std::partition(start, end - 1, [&comp, end](decltype(*start) v)
> {
> - return comp(v, *(end - 1));
> + auto Pivot = medianOf3(Start, End, Comp);
> + // Move Pivot to End.
> + std::swap(*(End - 1), *Pivot);
> + Pivot = std::partition(Start, End - 1, [&Comp, End](decltype(*Start) V)
> {
> + return Comp(V, *(End - 1));
> });
> - // Move pivot to middle of partition.
> - std::swap(*pivot, *(end - 1));
> + // Move Pivot to middle of partition.
> + std::swap(*Pivot, *(End - 1));
>
> // Recurse.
> - tg.spawn([=, &comp, &tg] {
> - parallel_quick_sort(start, pivot, comp, tg, depth - 1);
> + TG.spawn([=, &Comp, &TG] {
> + parallel_quick_sort(Start, Pivot, Comp, TG, Depth - 1);
> });
> - parallel_quick_sort(pivot + 1, end, comp, tg, depth - 1);
> + parallel_quick_sort(Pivot + 1, End, Comp, TG, Depth - 1);
> }
> }
>
> -template <class RandomAccessIterator, class Comp>
> +template <class RandomAccessIterator, class Comparator>
> void parallel_sort(
> - RandomAccessIterator start, RandomAccessIterator end,
> - const Comp &comp = std::less<
> + RandomAccessIterator Start, RandomAccessIterator End,
> + const Comparator &Comp = std::less<
> typename std::iterator_traits<RandomAccessIterator>::value_type>())
> {
> - TaskGroup tg;
> - detail::parallel_quick_sort(start, end, comp, tg,
> - llvm::Log2_64(std::distance(start, end)) +
> 1);
> + TaskGroup TG;
> + detail::parallel_quick_sort(Start, End, Comp, TG,
> + llvm::Log2_64(std::distance(Start, End)) +
> 1);
> }
> #endif
>
> -template <class T> void parallel_sort(T *start, T *end) {
> - parallel_sort(start, end, std::less<T>());
> +template <class T> void parallel_sort(T *Start, T *End) {
> + parallel_sort(Start, End, std::less<T>());
> }
>
> -#if !defined(LLVM_ENABLE_THREADS) || LLVM_ENABLE_THREADS == 0
> +#if !LLVM_ENABLE_THREADS
> template <class IterTy, class FuncTy>
> void parallel_for_each(IterTy Begin, IterTy End, FuncTy Fn) {
> std::for_each(Begin, End, Fn);
> @@ -302,12 +133,12 @@ void parallel_for_each(IterTy Begin, Ite
> if (TaskSize == 0)
> TaskSize = 1;
>
> - TaskGroup Tg;
> + TaskGroup TG;
> while (TaskSize <= std::distance(Begin, End)) {
> - Tg.spawn([=, &Fn] { std::for_each(Begin, Begin + TaskSize, Fn); });
> + TG.spawn([=, &Fn] { std::for_each(Begin, Begin + TaskSize, Fn); });
> Begin += TaskSize;
> }
> - Tg.spawn([=, &Fn] { std::for_each(Begin, End, Fn); });
> + TG.spawn([=, &Fn] { std::for_each(Begin, End, Fn); });
> }
>
> template <class IndexTy, class FuncTy>
> @@ -316,20 +147,20 @@ void parallel_for(IndexTy Begin, IndexTy
> if (TaskSize == 0)
> TaskSize = 1;
>
> - TaskGroup Tg;
> + TaskGroup TG;
> IndexTy I = Begin;
> for (; I + TaskSize < End; I += TaskSize) {
> - Tg.spawn([=, &Fn] {
> + TG.spawn([=, &Fn] {
> for (IndexTy J = I, E = I + TaskSize; J != E; ++J)
> Fn(J);
> });
> }
> - Tg.spawn([=, &Fn] {
> + TG.spawn([=, &Fn] {
> for (IndexTy J = I; J < End; ++J)
> Fn(J);
> });
> }
> #endif
> -} // end namespace lld
> +} // End namespace lld
>
> #endif // LLD_CORE_PARALLEL_H
>
> Added: lld/trunk/include/lld/Core/TaskGroup.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/include/lld/
> Core/TaskGroup.h?rev=302288&view=auto
> ============================================================
> ==================
> --- lld/trunk/include/lld/Core/TaskGroup.h (added)
> +++ lld/trunk/include/lld/Core/TaskGroup.h Fri May 5 16:09:26 2017
> @@ -0,0 +1,65 @@
> +//===- lld/Core/TaskGroup.h - Task Group ------------------------------
> ----===//
> +//
> +// The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#ifndef LLD_CORE_TASKGROUP_H
> +#define LLD_CORE_TASKGROUP_H
> +
> +#include "lld/Core/LLVM.h"
> +
> +#include <condition_variable>
> +#include <functional>
> +#include <mutex>
> +
> +namespace lld {
> +/// \brief Allows one or more threads to wait on a potentially unknown
> number of
> +/// events.
> +///
> +/// A latch starts at \p count. inc() increments this, and dec()
> decrements it.
> +/// All calls to sync() will block while the count is not 0.
> +///
> +/// Calling dec() on a Latch with a count of 0 has undefined behaivor.
> +class Latch {
> + uint32_t _count;
> + mutable std::mutex _condMut;
> + mutable std::condition_variable _cond;
> +
> +public:
> + explicit Latch(uint32_t count = 0) : _count(count) {}
> + ~Latch() { sync(); }
> +
> + void inc() {
> + std::unique_lock<std::mutex> lock(_condMut);
> + ++_count;
> + }
> +
> + void dec() {
> + std::unique_lock<std::mutex> lock(_condMut);
> + if (--_count == 0)
> + _cond.notify_all();
> + }
> +
> + void sync() const {
> + std::unique_lock<std::mutex> lock(_condMut);
> + _cond.wait(lock, [&] { return _count == 0; });
> + }
> +};
> +
> +/// \brief Allows launching a number of tasks and waiting for them to
> finish
> +/// either explicitly via sync() or implicitly on destruction.
> +class TaskGroup {
> + Latch _latch;
> +
> +public:
> + void spawn(std::function<void()> f);
> +
> + void sync() const { _latch.sync(); }
> +};
> +}
> +
> +#endif
>
> Modified: lld/trunk/lib/Core/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/
> CMakeLists.txt?rev=302288&r1=302287&r2=302288&view=diff
> ============================================================
> ==================
> --- lld/trunk/lib/Core/CMakeLists.txt (original)
> +++ lld/trunk/lib/Core/CMakeLists.txt Fri May 5 16:09:26 2017
> @@ -12,6 +12,7 @@ add_lld_library(lldCore
> Resolver.cpp
> SymbolTable.cpp
> TargetOptionsCommandFlags.cpp
> + TaskGroup.cpp
> Writer.cpp
>
> ADDITIONAL_HEADER_DIRS
>
> Added: lld/trunk/lib/Core/TaskGroup.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/Core/
> TaskGroup.cpp?rev=302288&view=auto
> ============================================================
> ==================
> --- lld/trunk/lib/Core/TaskGroup.cpp (added)
> +++ lld/trunk/lib/Core/TaskGroup.cpp Fri May 5 16:09:26 2017
> @@ -0,0 +1,140 @@
> +//===- lld/Core/TaskGroup.cpp - Task Group ------------------------------
> --===//
> +//
> +// The LLVM Linker
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===------------------------------------------------------
> ----------------===//
> +
> +#include "lld/Core/TaskGroup.h"
> +#include "llvm/config/llvm-config.h"
> +
> +#include <atomic>
> +#include <stack>
> +
> +#if defined(_MSC_VER) && LLVM_ENABLE_THREADS
> +#include <concrt.h>
> +#include <ppl.h>
> +#endif
> +
> +using namespace lld;
> +
> +namespace {
> +
> +/// \brief An abstract class that takes closures and runs them
> asynchronously.
> +class Executor {
> +public:
> + virtual ~Executor() = default;
> + virtual void add(std::function<void()> func) = 0;
> +
> + static Executor *getDefaultExecutor();
> +};
> +
> +#if !LLVM_ENABLE_THREADS
> +class SyncExecutor : public Executor {
> +public:
> + virtual void add(std::function<void()> F) { F(); }
> +};
> +
> +Executor *Executor::getDefaultExecutor() {
> + static SyncExecutor Exec;
> + return &Exec;
> +}
> +
> +#elif defined(_MSC_VER)
> +/// \brief An Executor that runs tasks via ConcRT.
> +class ConcRTExecutor : public Executor {
> + struct Taskish {
> + Taskish(std::function<void()> Task) : Task(Task) {}
> +
> + std::function<void()> Task;
> +
> + static void run(void *P) {
> + Taskish *Self = static_cast<Taskish *>(P);
> + Self->Task();
> + concurrency::Free(Self);
> + }
> + };
> +
> +public:
> + virtual void add(std::function<void()> F) {
> + Concurrency::CurrentScheduler::ScheduleTask(
> + Taskish::run, new (concurrency::Alloc(sizeof(Taskish)))
> Taskish(F));
> + }
> +};
> +
> +Executor *Executor::getDefaultExecutor() {
> + static ConcRTExecutor exec;
> + return &exec;
> +}
> +
> +#else
> +/// \brief An implementation of an Executor that runs closures on a
> thread pool
> +/// in filo order.
> +class ThreadPoolExecutor : public Executor {
> +public:
> + explicit ThreadPoolExecutor(
> + unsigned ThreadCount = std::thread::hardware_concurrency())
> + : Done(ThreadCount) {
> + // Spawn all but one of the threads in another thread as spawning
> threads
> + // can take a while.
> + std::thread([&, ThreadCount] {
> + for (size_t i = 1; i < ThreadCount; ++i) {
> + std::thread([=] { work(); }).detach();
> + }
> + work();
> + }).detach();
> + }
> +
> + ~ThreadPoolExecutor() override {
> + std::unique_lock<std::mutex> Lock(Mutex);
> + Stop = true;
> + Lock.unlock();
> + Cond.notify_all();
> + // Wait for ~Latch.
> + }
> +
> + void add(std::function<void()> F) override {
> + std::unique_lock<std::mutex> Lock(Mutex);
> + WorkStack.push(F);
> + Lock.unlock();
> + Cond.notify_one();
> + }
> +
> +private:
> + void work() {
> + while (true) {
> + std::unique_lock<std::mutex> Lock(Mutex);
> + Cond.wait(Lock, [&] { return Stop || !WorkStack.empty(); });
> + if (Stop)
> + break;
> + auto Task = WorkStack.top();
> + WorkStack.pop();
> + Lock.unlock();
> + Task();
> + }
> + Done.dec();
> + }
> +
> + std::atomic<bool> Stop{false};
> + std::stack<std::function<void()>> WorkStack;
> + std::mutex Mutex;
> + std::condition_variable Cond;
> + Latch Done;
> +};
> +
> +Executor *Executor::getDefaultExecutor() {
> + static ThreadPoolExecutor exec;
> + return &exec;
> +}
> +#endif
> +}
> +
> +void TaskGroup::spawn(std::function<void()> f) {
> + _latch.inc();
> + Executor::getDefaultExecutor()->add([&, f] {
> + f();
> + _latch.dec();
> + });
> +}
>
> Modified: lld/trunk/unittests/CoreTests/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/unittests/
> CoreTests/CMakeLists.txt?rev=302288&r1=302287&r2=302288&view=diff
> ============================================================
> ==================
> --- lld/trunk/unittests/CoreTests/CMakeLists.txt (original)
> +++ lld/trunk/unittests/CoreTests/CMakeLists.txt Fri May 5 16:09:26 2017
> @@ -3,5 +3,5 @@ add_lld_unittest(CoreTests
> )
>
> target_link_libraries(CoreTests
> - ${LLVM_PTHREAD_LIB}
> + lldCore ${LLVM_PTHREAD_LIB}
> )
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20170505/0ad9e747/attachment.html>
More information about the llvm-commits
mailing list