MeshLib
 
Loading...
Searching...
No Matches
MRParallelFor.h
Go to the documentation of this file.
1#pragma once
2
3#include "MRVector.h"
5#include "MRParallel.h"
6#include <atomic>
7#include <limits>
8#include <thread>
9
10namespace MR
11{
12
13namespace Parallel
14{
15
16template <typename I, typename CM, typename F>
17void For( I begin, I end, const CM & callMaker, F && f )
18{
19 tbb::parallel_for( tbb::blocked_range( begin, end ),
20 [&] ( const tbb::blocked_range<I>& range )
21 {
22 auto c = callMaker();
23 for ( I i = range.begin(); i < range.end(); ++i )
24 c( f, i );
25 } );
26}
27
28template <typename I, typename CM, typename F>
29bool For( I begin, I end, const CM & callMaker, F && f, ProgressCallback cb, size_t reportProgressEvery = 1024 )
30{
31 if ( !cb )
32 {
33 For( begin, end, callMaker, std::forward<F>( f ) );
34 return true;
35 }
36 const auto size = end - begin;
37 if ( size <= 0 )
38 return true;
39
40 auto callingThreadId = std::this_thread::get_id();
41 std::atomic<bool> keepGoing{ true };
42
43 // avoid false sharing with other local variables
44 // by putting processedBits in its own cache line
45 constexpr int hardware_destructive_interference_size = 64;
46 struct alignas(hardware_destructive_interference_size) S
47 {
48 std::atomic<size_t> processed{ 0 };
49 } s;
50 static_assert( alignof(S) == hardware_destructive_interference_size );
51 static_assert( sizeof(S) == hardware_destructive_interference_size );
52
53 tbb::parallel_for( tbb::blocked_range( begin, end ),
54 [&] ( const tbb::blocked_range<I>& range )
55 {
56 const bool report = std::this_thread::get_id() == callingThreadId;
57 size_t myProcessed = 0;
58 auto c = callMaker();
59 for ( I i = range.begin(); i < range.end(); ++i )
60 {
61 if ( !keepGoing.load( std::memory_order_relaxed ) )
62 break;
63 c( f, i );
64 if ( ( ++myProcessed % reportProgressEvery ) == 0 )
65 {
66 if ( report )
67 {
68 if ( !cb( float( myProcessed + s.processed.load( std::memory_order_relaxed ) ) / size ) )
69 keepGoing.store( false, std::memory_order_relaxed );
70 }
71 else
72 {
73 s.processed.fetch_add( myProcessed, std::memory_order_relaxed );
74 myProcessed = 0;
75 }
76 }
77 }
78 const auto total = s.processed.fetch_add( myProcessed, std::memory_order_relaxed );
79 if ( report && !cb( float( total ) / size ) )
80 keepGoing.store( false, std::memory_order_relaxed );
81 } );
82 return keepGoing.load( std::memory_order_relaxed );
83}
84
85} //namespace Parallel
86
89
93template <typename I, typename ...F>
94inline auto ParallelFor( I begin, I end, F &&... f )
95{
96 return Parallel::For( begin, end, Parallel::CallSimplyMaker{}, std::forward<F>( f )... );
97}
98
103template <typename I, typename L, typename ...F>
104inline auto ParallelFor( I begin, I end, tbb::enumerable_thread_specific<L> & e, F &&... f )
105{
106 return Parallel::For( begin, end, Parallel::CallWithTLSMaker<L>{ e }, std::forward<F>( f )... );
107}
108
112template <typename T, typename ...F>
113inline auto ParallelFor( const std::vector<T> & v, F &&... f )
114{
115 return ParallelFor( size_t(0), v.size(), std::forward<F>( f )... );
116}
117
121template <typename T, typename I, typename ...F>
122inline auto ParallelFor( const Vector<T, I> & v, F &&... f )
123{
124 return ParallelFor( v.beginId(), v.endId(), std::forward<F>( f )... );
125}
126
129template<typename T>
130std::pair<T, T> parallelMinMax( const std::vector<T>& vec, const T * topExcluding = nullptr )
131{
132 struct MinMax
133 {
134 T min = std::numeric_limits<T>::max();
135 T max = std::numeric_limits<T>::lowest();
136 };
137
138 auto minmax = tbb::parallel_reduce( tbb::blocked_range<size_t>( 0, vec.size() ), MinMax{},
139 [&] ( const tbb::blocked_range<size_t> range, MinMax curMinMax )
140 {
141 for ( size_t i = range.begin(); i < range.end(); i++ )
142 {
143 T val = vec[i];
144 if ( topExcluding && std::abs( val ) >= *topExcluding )
145 continue;
146 if ( val < curMinMax.min )
147 curMinMax.min = val;
148 if ( val > curMinMax.max )
149 curMinMax.max = val;
150 }
151 return curMinMax;
152 },
153 [&] ( const MinMax& a, const MinMax& b )
154 {
155 MinMax res;
156 if ( a.min < b.min )
157 {
158 res.min = a.min;
159 }
160 else
161 {
162 res.min = b.min;
163 }
164 if ( a.max > b.max )
165 {
166 res.max = a.max;
167 }
168 else
169 {
170 res.max = b.max;
171 }
172 return res;
173 } );
174
175 return { minmax.min, minmax.max };
176}
177
180template<typename T, typename I>
181auto parallelMinMaxArg( const Vector<T, I>& vec, const T * topExcluding = nullptr )
182{
183 struct MinMaxArg
184 {
185 T min = std::numeric_limits<T>::max();
186 T max = std::numeric_limits<T>::lowest();
187 I minArg, maxArg;
188 };
189
190 return tbb::parallel_reduce( tbb::blocked_range<I>( I(0), vec.endId() ), MinMaxArg{},
191 [&] ( const tbb::blocked_range<I> range, MinMaxArg curr )
192 {
193 for ( I i = range.begin(); i < range.end(); i++ )
194 {
195 T val = vec[i];
196 if ( topExcluding && std::abs( val ) >= *topExcluding )
197 continue;
198 if ( val < curr.min )
199 {
200 curr.min = val;
201 curr.minArg = i;
202 }
203 if ( val > curr.max )
204 {
205 curr.max = val;
206 curr.maxArg = i;
207 }
208 }
209 return curr;
210 },
211 [&] ( MinMaxArg a, const MinMaxArg& b )
212 {
213 if ( b.min < a.min )
214 {
215 a.min = b.min;
216 a.minArg = b.minArg;
217 }
218 if ( b.max > a.max )
219 {
220 a.max = b.max;
221 a.maxArg = b.maxArg;
222 }
223 return a;
224 } );
225}
226
228
229} // namespace MR
std::vector<T>-like container that requires specific indexing type,
Definition MRMesh/MRVector.h:19
I beginId() const
returns the identifier of the first element
Definition MRMesh/MRVector.h:121
I endId() const
returns backId() + 1
Definition MRMesh/MRVector.h:125
auto begin(const BitSet &a)
Definition MRMesh/MRBitSet.h:263
auto end(const BitSet &)
Definition MRMesh/MRBitSet.h:265
auto parallelMinMaxArg(const Vector< T, I > &vec, const T *topExcluding=nullptr)
Definition MRParallelFor.h:181
auto ParallelFor(I begin, I end, F &&... f)
Definition MRParallelFor.h:94
std::pair< T, T > parallelMinMax(const std::vector< T > &vec, const T *topExcluding=nullptr)
Definition MRParallelFor.h:130
std::function< bool(float)> ProgressCallback
Definition MRMesh/MRMeshFwd.h:589
void For(I begin, I end, const CM &callMaker, F &&f)
Definition MRParallelFor.h:17
Definition MRCameraOrientationPlugin.h:7
ImVec2 size(const ViewportRectangle &rect)
Definition MRViewport.h:32
I
Definition MRMesh/MRMeshFwd.h:88
Definition MRParallel.h:18
Definition MRParallel.h:32