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