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; });
78 void spawn(std::function
<void()> f
);
80 void sync() const { L
.sync(); }
84 template <class RandomAccessIterator
, class Comparator
>
85 void parallel_sort(RandomAccessIterator Start
, RandomAccessIterator End
,
86 const Comparator
&Comp
) {
87 concurrency::parallel_sort(Start
, End
, Comp
);
89 template <class IterTy
, class FuncTy
>
90 void parallel_for_each(IterTy Begin
, IterTy End
, FuncTy Fn
) {
91 concurrency::parallel_for_each(Begin
, End
, Fn
);
94 template <class IndexTy
, class FuncTy
>
95 void parallel_for_each_n(IndexTy Begin
, IndexTy End
, FuncTy Fn
) {
96 concurrency::parallel_for(Begin
, End
, Fn
);
100 const ptrdiff_t MinParallelSize
= 1024;
102 /// Inclusive median.
103 template <class RandomAccessIterator
, class Comparator
>
104 RandomAccessIterator
medianOf3(RandomAccessIterator Start
,
105 RandomAccessIterator End
,
106 const Comparator
&Comp
) {
107 RandomAccessIterator Mid
= Start
+ (std::distance(Start
, End
) / 2);
108 return Comp(*Start
, *(End
- 1))
109 ? (Comp(*Mid
, *(End
- 1)) ? (Comp(*Start
, *Mid
) ? Mid
: Start
)
111 : (Comp(*Mid
, *Start
) ? (Comp(*(End
- 1), *Mid
) ? Mid
: End
- 1)
115 template <class RandomAccessIterator
, class Comparator
>
116 void parallel_quick_sort(RandomAccessIterator Start
, RandomAccessIterator End
,
117 const Comparator
&Comp
, TaskGroup
&TG
, size_t Depth
) {
118 // Do a sequential sort for small inputs.
119 if (std::distance(Start
, End
) < detail::MinParallelSize
|| Depth
== 0) {
120 llvm::sort(Start
, End
, Comp
);
125 auto Pivot
= medianOf3(Start
, End
, Comp
);
126 // Move Pivot to End.
127 std::swap(*(End
- 1), *Pivot
);
128 Pivot
= std::partition(Start
, End
- 1, [&Comp
, End
](decltype(*Start
) V
) {
129 return Comp(V
, *(End
- 1));
131 // Move Pivot to middle of partition.
132 std::swap(*Pivot
, *(End
- 1));
135 TG
.spawn([=, &Comp
, &TG
] {
136 parallel_quick_sort(Start
, Pivot
, Comp
, TG
, Depth
- 1);
138 parallel_quick_sort(Pivot
+ 1, End
, Comp
, TG
, Depth
- 1);
141 template <class RandomAccessIterator
, class Comparator
>
142 void parallel_sort(RandomAccessIterator Start
, RandomAccessIterator End
,
143 const Comparator
&Comp
) {
145 parallel_quick_sort(Start
, End
, Comp
, TG
,
146 llvm::Log2_64(std::distance(Start
, End
)) + 1);
149 template <class IterTy
, class FuncTy
>
150 void parallel_for_each(IterTy Begin
, IterTy End
, FuncTy Fn
) {
151 // TaskGroup has a relatively high overhead, so we want to reduce
152 // the number of spawn() calls. We'll create up to 1024 tasks here.
153 // (Note that 1024 is an arbitrary number. This code probably needs
154 // improving to take the number of available cores into account.)
155 ptrdiff_t TaskSize
= std::distance(Begin
, End
) / 1024;
160 while (TaskSize
< std::distance(Begin
, End
)) {
161 TG
.spawn([=, &Fn
] { std::for_each(Begin
, Begin
+ TaskSize
, Fn
); });
164 std::for_each(Begin
, End
, Fn
);
167 template <class IndexTy
, class FuncTy
>
168 void parallel_for_each_n(IndexTy Begin
, IndexTy End
, FuncTy Fn
) {
169 ptrdiff_t TaskSize
= (End
- Begin
) / 1024;
175 for (; I
+ TaskSize
< End
; I
+= TaskSize
) {
177 for (IndexTy J
= I
, E
= I
+ TaskSize
; J
!= E
; ++J
)
181 for (IndexTy J
= I
; J
< End
; ++J
)
189 template <typename Iter
>
190 using DefComparator
=
191 std::less
<typename
std::iterator_traits
<Iter
>::value_type
>;
193 } // namespace detail
195 // sequential algorithm implementations.
196 template <class Policy
, class RandomAccessIterator
,
197 class Comparator
= detail::DefComparator
<RandomAccessIterator
>>
198 void sort(Policy policy
, RandomAccessIterator Start
, RandomAccessIterator End
,
199 const Comparator
&Comp
= Comparator()) {
200 static_assert(is_execution_policy
<Policy
>::value
,
201 "Invalid execution policy!");
202 llvm::sort(Start
, End
, Comp
);
205 template <class Policy
, class IterTy
, class FuncTy
>
206 void for_each(Policy policy
, IterTy Begin
, IterTy End
, FuncTy Fn
) {
207 static_assert(is_execution_policy
<Policy
>::value
,
208 "Invalid execution policy!");
209 std::for_each(Begin
, End
, Fn
);
212 template <class Policy
, class IndexTy
, class FuncTy
>
213 void for_each_n(Policy policy
, IndexTy Begin
, IndexTy End
, FuncTy Fn
) {
214 static_assert(is_execution_policy
<Policy
>::value
,
215 "Invalid execution policy!");
216 for (IndexTy I
= Begin
; I
!= End
; ++I
)
220 // Parallel algorithm implementations, only available when LLVM_ENABLE_THREADS
222 #if LLVM_ENABLE_THREADS
223 template <class RandomAccessIterator
,
224 class Comparator
= detail::DefComparator
<RandomAccessIterator
>>
225 void sort(parallel_execution_policy policy
, RandomAccessIterator Start
,
226 RandomAccessIterator End
, const Comparator
&Comp
= Comparator()) {
227 detail::parallel_sort(Start
, End
, Comp
);
230 template <class IterTy
, class FuncTy
>
231 void for_each(parallel_execution_policy policy
, IterTy Begin
, IterTy End
,
233 detail::parallel_for_each(Begin
, End
, Fn
);
236 template <class IndexTy
, class FuncTy
>
237 void for_each_n(parallel_execution_policy policy
, IndexTy Begin
, IndexTy End
,
239 detail::parallel_for_each_n(Begin
, End
, Fn
);
243 } // namespace parallel
246 #endif // LLVM_SUPPORT_PARALLEL_H