1 //===- llvm/Support/Parallel.h - Parallel algorithms ----------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_SUPPORT_PARALLEL_H
10 #define LLVM_SUPPORT_PARALLEL_H
12 #include "llvm/ADT/STLExtras.h"
13 #include "llvm/Config/llvm-config.h"
14 #include "llvm/Support/MathExtras.h"
17 #include <condition_variable>
21 #if defined(_MSC_VER) && LLVM_ENABLE_THREADS
23 #pragma warning(disable : 4530)
32 struct sequential_execution_policy
{};
33 struct parallel_execution_policy
{};
36 struct is_execution_policy
37 : public std::integral_constant
<
38 bool, llvm::is_one_of
<T
, sequential_execution_policy
,
39 parallel_execution_policy
>::value
> {};
41 constexpr sequential_execution_policy seq
{};
42 constexpr parallel_execution_policy par
{};
46 #if LLVM_ENABLE_THREADS
50 mutable std::mutex Mutex
;
51 mutable std::condition_variable Cond
;
54 explicit Latch(uint32_t Count
= 0) : Count(Count
) {}
58 std::lock_guard
<std::mutex
> lock(Mutex
);
63 std::lock_guard
<std::mutex
> lock(Mutex
);
69 std::unique_lock
<std::mutex
> lock(Mutex
);
70 Cond
.wait(lock
, [&] { return Count
== 0; });
82 void spawn(std::function
<void()> f
);
84 void sync() const { L
.sync(); }
88 template <class RandomAccessIterator
, class Comparator
>
89 void parallel_sort(RandomAccessIterator Start
, RandomAccessIterator End
,
90 const Comparator
&Comp
) {
91 concurrency::parallel_sort(Start
, End
, Comp
);
93 template <class IterTy
, class FuncTy
>
94 void parallel_for_each(IterTy Begin
, IterTy End
, FuncTy Fn
) {
95 concurrency::parallel_for_each(Begin
, End
, Fn
);
98 template <class IndexTy
, class FuncTy
>
99 void parallel_for_each_n(IndexTy Begin
, IndexTy End
, FuncTy Fn
) {
100 concurrency::parallel_for(Begin
, End
, Fn
);
104 const ptrdiff_t MinParallelSize
= 1024;
106 /// Inclusive median.
107 template <class RandomAccessIterator
, class Comparator
>
108 RandomAccessIterator
medianOf3(RandomAccessIterator Start
,
109 RandomAccessIterator End
,
110 const Comparator
&Comp
) {
111 RandomAccessIterator Mid
= Start
+ (std::distance(Start
, End
) / 2);
112 return Comp(*Start
, *(End
- 1))
113 ? (Comp(*Mid
, *(End
- 1)) ? (Comp(*Start
, *Mid
) ? Mid
: Start
)
115 : (Comp(*Mid
, *Start
) ? (Comp(*(End
- 1), *Mid
) ? Mid
: End
- 1)
119 template <class RandomAccessIterator
, class Comparator
>
120 void parallel_quick_sort(RandomAccessIterator Start
, RandomAccessIterator End
,
121 const Comparator
&Comp
, TaskGroup
&TG
, size_t Depth
) {
122 // Do a sequential sort for small inputs.
123 if (std::distance(Start
, End
) < detail::MinParallelSize
|| Depth
== 0) {
124 llvm::sort(Start
, End
, Comp
);
129 auto Pivot
= medianOf3(Start
, End
, Comp
);
130 // Move Pivot to End.
131 std::swap(*(End
- 1), *Pivot
);
132 Pivot
= std::partition(Start
, End
- 1, [&Comp
, End
](decltype(*Start
) V
) {
133 return Comp(V
, *(End
- 1));
135 // Move Pivot to middle of partition.
136 std::swap(*Pivot
, *(End
- 1));
139 TG
.spawn([=, &Comp
, &TG
] {
140 parallel_quick_sort(Start
, Pivot
, Comp
, TG
, Depth
- 1);
142 parallel_quick_sort(Pivot
+ 1, End
, Comp
, TG
, Depth
- 1);
145 template <class RandomAccessIterator
, class Comparator
>
146 void parallel_sort(RandomAccessIterator Start
, RandomAccessIterator End
,
147 const Comparator
&Comp
) {
149 parallel_quick_sort(Start
, End
, Comp
, TG
,
150 llvm::Log2_64(std::distance(Start
, End
)) + 1);
153 template <class IterTy
, class FuncTy
>
154 void parallel_for_each(IterTy Begin
, IterTy End
, FuncTy Fn
) {
155 // TaskGroup has a relatively high overhead, so we want to reduce
156 // the number of spawn() calls. We'll create up to 1024 tasks here.
157 // (Note that 1024 is an arbitrary number. This code probably needs
158 // improving to take the number of available cores into account.)
159 ptrdiff_t TaskSize
= std::distance(Begin
, End
) / 1024;
164 while (TaskSize
< std::distance(Begin
, End
)) {
165 TG
.spawn([=, &Fn
] { std::for_each(Begin
, Begin
+ TaskSize
, Fn
); });
168 std::for_each(Begin
, End
, Fn
);
171 template <class IndexTy
, class FuncTy
>
172 void parallel_for_each_n(IndexTy Begin
, IndexTy End
, FuncTy Fn
) {
173 ptrdiff_t TaskSize
= (End
- Begin
) / 1024;
179 for (; I
+ TaskSize
< End
; I
+= TaskSize
) {
181 for (IndexTy J
= I
, E
= I
+ TaskSize
; J
!= E
; ++J
)
185 for (IndexTy J
= I
; J
< End
; ++J
)
193 template <typename Iter
>
194 using DefComparator
=
195 std::less
<typename
std::iterator_traits
<Iter
>::value_type
>;
197 } // namespace detail
199 // sequential algorithm implementations.
200 template <class Policy
, class RandomAccessIterator
,
201 class Comparator
= detail::DefComparator
<RandomAccessIterator
>>
202 void sort(Policy policy
, RandomAccessIterator Start
, RandomAccessIterator End
,
203 const Comparator
&Comp
= Comparator()) {
204 static_assert(is_execution_policy
<Policy
>::value
,
205 "Invalid execution policy!");
206 llvm::sort(Start
, End
, Comp
);
209 template <class Policy
, class IterTy
, class FuncTy
>
210 void for_each(Policy policy
, IterTy Begin
, IterTy End
, FuncTy Fn
) {
211 static_assert(is_execution_policy
<Policy
>::value
,
212 "Invalid execution policy!");
213 std::for_each(Begin
, End
, Fn
);
216 template <class Policy
, class IndexTy
, class FuncTy
>
217 void for_each_n(Policy policy
, IndexTy Begin
, IndexTy End
, FuncTy Fn
) {
218 static_assert(is_execution_policy
<Policy
>::value
,
219 "Invalid execution policy!");
220 for (IndexTy I
= Begin
; I
!= End
; ++I
)
224 // Parallel algorithm implementations, only available when LLVM_ENABLE_THREADS
226 #if LLVM_ENABLE_THREADS
227 template <class RandomAccessIterator
,
228 class Comparator
= detail::DefComparator
<RandomAccessIterator
>>
229 void sort(parallel_execution_policy policy
, RandomAccessIterator Start
,
230 RandomAccessIterator End
, const Comparator
&Comp
= Comparator()) {
231 detail::parallel_sort(Start
, End
, Comp
);
234 template <class IterTy
, class FuncTy
>
235 void for_each(parallel_execution_policy policy
, IterTy Begin
, IterTy End
,
237 detail::parallel_for_each(Begin
, End
, Fn
);
240 template <class IndexTy
, class FuncTy
>
241 void for_each_n(parallel_execution_policy policy
, IndexTy Begin
, IndexTy End
,
243 detail::parallel_for_each_n(Begin
, End
, Fn
);
247 } // namespace parallel
250 #endif // LLVM_SUPPORT_PARALLEL_H