diff options
Diffstat (limited to 'lld')
-rw-r--r-- | lld/COFF/ICF.cpp | 2 | ||||
-rw-r--r-- | lld/COFF/MapFile.cpp | 2 | ||||
-rw-r--r-- | lld/COFF/Writer.cpp | 2 | ||||
-rw-r--r-- | lld/ELF/Threads.h | 10 | ||||
-rw-r--r-- | lld/include/lld/Core/Parallel.h | 210 | ||||
-rw-r--r-- | lld/include/lld/Core/TaskGroup.h | 65 | ||||
-rw-r--r-- | lld/lib/Core/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lld/lib/Core/TaskGroup.cpp | 141 | ||||
-rw-r--r-- | lld/lib/ReaderWriter/MachO/LayoutPass.cpp | 4 | ||||
-rw-r--r-- | lld/unittests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lld/unittests/CoreTests/CMakeLists.txt | 7 | ||||
-rw-r--r-- | lld/unittests/CoreTests/ParallelTest.cpp | 46 |
12 files changed, 10 insertions, 481 deletions
diff --git a/lld/COFF/ICF.cpp b/lld/COFF/ICF.cpp index e3a7d27c39b..3b7cc424f0a 100644 --- a/lld/COFF/ICF.cpp +++ b/lld/COFF/ICF.cpp @@ -21,9 +21,9 @@ #include "Chunks.h" #include "Error.h" #include "Symbols.h" -#include "lld/Core/Parallel.h" #include "llvm/ADT/Hashing.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Parallel.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> #include <atomic> diff --git a/lld/COFF/MapFile.cpp b/lld/COFF/MapFile.cpp index 7df88f38879..b63d4672c7d 100644 --- a/lld/COFF/MapFile.cpp +++ b/lld/COFF/MapFile.cpp @@ -25,7 +25,7 @@ #include "Symbols.h" #include "Writer.h" -#include "lld/Core/Parallel.h" +#include "llvm/Support/Parallel.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp index d61d87172f4..5c9c8375dad 100644 --- a/lld/COFF/Writer.cpp +++ b/lld/COFF/Writer.cpp @@ -17,13 +17,13 @@ #include "PDB.h" #include "SymbolTable.h" #include "Symbols.h" -#include "lld/Core/Parallel.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Endian.h" #include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/Parallel.h" #include "llvm/Support/RandomNumberGenerator.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> diff --git a/lld/ELF/Threads.h b/lld/ELF/Threads.h index 0c291c7b703..e01afd4d3fc 100644 --- a/lld/ELF/Threads.h +++ b/lld/ELF/Threads.h @@ -61,7 +61,7 @@ #include "Config.h" -#include "lld/Core/Parallel.h" +#include "llvm/Support/Parallel.h" #include <functional> namespace lld { @@ -70,17 +70,17 @@ namespace elf { template <class IterTy, class FuncTy> void parallelForEach(IterTy Begin, IterTy End, FuncTy Fn) { if (Config->Threads) - for_each(parallel::par, Begin, End, Fn); + for_each(llvm::parallel::par, Begin, End, Fn); else - for_each(parallel::seq, Begin, End, Fn); + for_each(llvm::parallel::seq, Begin, End, Fn); } inline void parallelForEachN(size_t Begin, size_t End, std::function<void(size_t)> Fn) { if (Config->Threads) - for_each_n(parallel::par, Begin, End, Fn); + for_each_n(llvm::parallel::par, Begin, End, Fn); else - for_each_n(parallel::seq, Begin, End, Fn); + for_each_n(llvm::parallel::seq, Begin, End, Fn); } } } diff --git a/lld/include/lld/Core/Parallel.h b/lld/include/lld/Core/Parallel.h deleted file mode 100644 index 20b774112ca..00000000000 --- a/lld/include/lld/Core/Parallel.h +++ /dev/null @@ -1,210 +0,0 @@ -//===- lld/Core/Parallel.h - Parallel utilities ---------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_CORE_PARALLEL_H -#define LLD_CORE_PARALLEL_H - -#include "lld/Core/LLVM.h" -#include "lld/Core/TaskGroup.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/Config/llvm-config.h" -#include "llvm/Support/MathExtras.h" - -#include <algorithm> - -#if defined(_MSC_VER) && LLVM_ENABLE_THREADS -#include <concrt.h> -#include <ppl.h> -#endif - -namespace lld { - -namespace parallel { -struct sequential_execution_policy {}; -struct parallel_execution_policy {}; - -template <typename T> -struct is_execution_policy - : public std::integral_constant< - bool, llvm::is_one_of<T, sequential_execution_policy, - parallel_execution_policy>::value> {}; - -constexpr sequential_execution_policy seq{}; -constexpr parallel_execution_policy par{}; - -namespace detail { - -#if LLVM_ENABLE_THREADS - -#if defined(_MSC_VER) -template <class RandomAccessIterator, class Comparator> -void parallel_sort(RandomAccessIterator Start, RandomAccessIterator End, - const Comparator &Comp) { - concurrency::parallel_sort(Start, End, Comp); -} -template <class IterTy, class FuncTy> -void parallel_for_each(IterTy Begin, IterTy End, FuncTy Fn) { - concurrency::parallel_for_each(Begin, End, Fn); -} - -template <class IndexTy, class FuncTy> -void parallel_for_each_n(IndexTy Begin, IndexTy End, FuncTy Fn) { - concurrency::parallel_for(Begin, End, Fn); -} - -#else -const ptrdiff_t MinParallelSize = 1024; - -/// \brief Inclusive median. -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 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); - 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)); - }); - // 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); - }); - parallel_quick_sort(Pivot + 1, End, Comp, TG, Depth - 1); -} - -template <class RandomAccessIterator, class Comparator> -void parallel_sort(RandomAccessIterator Start, RandomAccessIterator End, - const Comparator &Comp) { - TaskGroup TG; - parallel_quick_sort(Start, End, Comp, TG, - llvm::Log2_64(std::distance(Start, End)) + 1); -} - -template <class IterTy, class FuncTy> -void parallel_for_each(IterTy Begin, IterTy End, FuncTy Fn) { - // TaskGroup has a relatively high overhead, so we want to reduce - // the number of spawn() calls. We'll create up to 1024 tasks here. - // (Note that 1024 is an arbitrary number. This code probably needs - // improving to take the number of available cores into account.) - ptrdiff_t TaskSize = std::distance(Begin, End) / 1024; - if (TaskSize == 0) - TaskSize = 1; - - TaskGroup TG; - while (TaskSize <= std::distance(Begin, End)) { - TG.spawn([=, &Fn] { std::for_each(Begin, Begin + TaskSize, Fn); }); - Begin += TaskSize; - } - TG.spawn([=, &Fn] { std::for_each(Begin, End, Fn); }); -} - -template <class IndexTy, class FuncTy> -void parallel_for_each_n(IndexTy Begin, IndexTy End, FuncTy Fn) { - ptrdiff_t TaskSize = (End - Begin) / 1024; - if (TaskSize == 0) - TaskSize = 1; - - TaskGroup TG; - IndexTy I = Begin; - for (; I + TaskSize < End; I += TaskSize) { - TG.spawn([=, &Fn] { - for (IndexTy J = I, E = I + TaskSize; J != E; ++J) - Fn(J); - }); - } - TG.spawn([=, &Fn] { - for (IndexTy J = I; J < End; ++J) - Fn(J); - }); -} - -#endif - -#endif - -template <typename Iter> -using DefComparator = - std::less<typename std::iterator_traits<Iter>::value_type>; - -} // namespace detail - -// sequential algorithm implementations. -template <class Policy, class RandomAccessIterator, - class Comparator = detail::DefComparator<RandomAccessIterator>> -void sort(Policy policy, RandomAccessIterator Start, RandomAccessIterator End, - const Comparator &Comp = Comparator()) { - static_assert(is_execution_policy<Policy>::value, - "Invalid execution policy!"); - std::sort(Start, End, Comp); -} - -template <class Policy, class IterTy, class FuncTy> -void for_each(Policy policy, IterTy Begin, IterTy End, FuncTy Fn) { - static_assert(is_execution_policy<Policy>::value, - "Invalid execution policy!"); - std::for_each(Begin, End, Fn); -} - -template <class Policy, class IndexTy, class FuncTy> -void for_each_n(Policy policy, IndexTy Begin, IndexTy End, FuncTy Fn) { - static_assert(is_execution_policy<Policy>::value, - "Invalid execution policy!"); - for (IndexTy I = Begin; I != End; ++I) - Fn(I); -} - -// Parallel algorithm implementations, only available when LLVM_ENABLE_THREADS -// is true. -#if LLVM_ENABLE_THREADS -template <class RandomAccessIterator, - class Comparator = detail::DefComparator<RandomAccessIterator>> -void sort(parallel_execution_policy policy, RandomAccessIterator Start, - RandomAccessIterator End, const Comparator &Comp = Comparator()) { - detail::parallel_sort(Start, End, Comp); -} - -template <class IterTy, class FuncTy> -void for_each(parallel_execution_policy policy, IterTy Begin, IterTy End, - FuncTy Fn) { - detail::parallel_for_each(Begin, End, Fn); -} - -template <class IndexTy, class FuncTy> -void for_each_n(parallel_execution_policy policy, IndexTy Begin, IndexTy End, - FuncTy Fn) { - detail::parallel_for_each_n(Begin, End, Fn); -} -#endif - -} // namespace parallel -} // End namespace lld - -#endif // LLD_CORE_PARALLEL_H diff --git a/lld/include/lld/Core/TaskGroup.h b/lld/include/lld/Core/TaskGroup.h deleted file mode 100644 index 6cd173ebbbb..00000000000 --- a/lld/include/lld/Core/TaskGroup.h +++ /dev/null @@ -1,65 +0,0 @@ -//===- 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 Mutex; - mutable std::condition_variable Cond; - -public: - explicit Latch(uint32_t count = 0) : Count(count) {} - ~Latch() { sync(); } - - void inc() { - std::unique_lock<std::mutex> lock(Mutex); - ++Count; - } - - void dec() { - std::unique_lock<std::mutex> lock(Mutex); - if (--Count == 0) - Cond.notify_all(); - } - - void sync() const { - std::unique_lock<std::mutex> lock(Mutex); - 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 L; - -public: - void spawn(std::function<void()> F); - - void sync() const { L.sync(); } -}; -} - -#endif diff --git a/lld/lib/Core/CMakeLists.txt b/lld/lib/Core/CMakeLists.txt index cdd4e679ffa..f2bf9050929 100644 --- a/lld/lib/Core/CMakeLists.txt +++ b/lld/lib/Core/CMakeLists.txt @@ -12,7 +12,6 @@ add_lld_library(lldCore Resolver.cpp SymbolTable.cpp TargetOptionsCommandFlags.cpp - TaskGroup.cpp Writer.cpp ADDITIONAL_HEADER_DIRS diff --git a/lld/lib/Core/TaskGroup.cpp b/lld/lib/Core/TaskGroup.cpp deleted file mode 100644 index 6cd5d22b7e8..00000000000 --- a/lld/lib/Core/TaskGroup.cpp +++ /dev/null @@ -1,141 +0,0 @@ -//===- 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> -#include <thread> - -#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) { - L.inc(); - Executor::getDefaultExecutor()->add([&, F] { - F(); - L.dec(); - }); -} diff --git a/lld/lib/ReaderWriter/MachO/LayoutPass.cpp b/lld/lib/ReaderWriter/MachO/LayoutPass.cpp index 2b5a46cc98f..7bca07eb16d 100644 --- a/lld/lib/ReaderWriter/MachO/LayoutPass.cpp +++ b/lld/lib/ReaderWriter/MachO/LayoutPass.cpp @@ -9,12 +9,12 @@ #include "LayoutPass.h" #include "lld/Core/Instrumentation.h" -#include "lld/Core/Parallel.h" #include "lld/Core/PassManager.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Parallel.h" #include <algorithm> #include <set> #include <utility> @@ -461,7 +461,7 @@ llvm::Error LayoutPass::perform(SimpleFile &mergedFile) { }); std::vector<LayoutPass::SortKey> vec = decorate(atomRange); - sort(parallel::par, vec.begin(), vec.end(), + sort(llvm::parallel::par, vec.begin(), vec.end(), [&](const LayoutPass::SortKey &l, const LayoutPass::SortKey &r) -> bool { return compareAtoms(l, r, _customSorter); }); diff --git a/lld/unittests/CMakeLists.txt b/lld/unittests/CMakeLists.txt index 9cd085398c3..84d35d43f4e 100644 --- a/lld/unittests/CMakeLists.txt +++ b/lld/unittests/CMakeLists.txt @@ -12,6 +12,5 @@ function(add_lld_unittest test_dirname) target_link_libraries(${test_dirname} ${LLVM_COMMON_LIBS}) endfunction() -add_subdirectory(CoreTests) add_subdirectory(DriverTests) add_subdirectory(MachOTests) diff --git a/lld/unittests/CoreTests/CMakeLists.txt b/lld/unittests/CoreTests/CMakeLists.txt deleted file mode 100644 index 9f68f56a6c0..00000000000 --- a/lld/unittests/CoreTests/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -add_lld_unittest(CoreTests - ParallelTest.cpp - ) - -target_link_libraries(CoreTests - lldCore ${LLVM_PTHREAD_LIB} - ) diff --git a/lld/unittests/CoreTests/ParallelTest.cpp b/lld/unittests/CoreTests/ParallelTest.cpp deleted file mode 100644 index 601a2b0839b..00000000000 --- a/lld/unittests/CoreTests/ParallelTest.cpp +++ /dev/null @@ -1,46 +0,0 @@ -//===- lld/unittest/ParallelTest.cpp --------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// \brief Parallel.h unit tests. -/// -//===----------------------------------------------------------------------===// - -#include "gtest/gtest.h" -#include "lld/Core/Parallel.h" -#include <array> -#include <random> - -uint32_t array[1024 * 1024]; - -TEST(Parallel, sort) { - std::mt19937 randEngine; - std::uniform_int_distribution<uint32_t> dist; - - for (auto &i : array) - i = dist(randEngine); - - sort(lld::parallel::par, std::begin(array), std::end(array)); - ASSERT_TRUE(std::is_sorted(std::begin(array), std::end(array))); -} - -TEST(Parallel, parallel_for) { - // We need to test the case with a TaskSize > 1. We are white-box testing - // here. The TaskSize is calculated as (End - Begin) / 1024 at the time of - // writing. - uint32_t range[2050]; - std::fill(range, range + 2050, 1); - for_each_n(lld::parallel::par, 0, 2049, [&range](size_t I) { ++range[I]; }); - - uint32_t expected[2049]; - std::fill(expected, expected + 2049, 2); - ASSERT_TRUE(std::equal(range, range + 2049, expected)); - // Check that we don't write past the end of the requested range. - ASSERT_EQ(range[2049], 1u); -} |