0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[occt.git] / src / OSD / OSD_Parallel.hxx
CommitLineData
c7b59798 1// Copyright (c) 2013-2014 OPEN CASCADE SAS
2//
3// This file is part of Open CASCADE Technology software library.
4//
5// This library is free software; you can redistribute it and/or modify it under
6// the terms of the GNU Lesser General Public License version 2.1 as published
7// by the Free Software Foundation, with special exception defined in the file
8// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9// distribution for complete text of the license and disclaimer of any warranty.
10//
11// Alternatively, this file may be used under the terms of Open CASCADE
12// commercial license or contractual agreement.
13
14#ifndef OSD_Parallel_HeaderFile
15#define OSD_Parallel_HeaderFile
16
fc867b96 17#include <OSD_ThreadPool.hxx>
00af0ebb 18#include <Standard_Type.hxx>
19#include <memory>
c7b59798 20
00af0ebb 21//! @brief Simple tool for code parallelization.
22//!
23//! OSD_Parallel class provides simple interface for parallel processing of
24//! tasks that can be formulated in terms of "for" or "foreach" loops.
25//!
26//! To use this tool it is necessary to:
27//! - organize the data to be processed in a collection accessible by
28//! iteration (usually array or vector);
29//! - implement a functor class providing operator () accepting iterator
30//! (or index in array) that does the job;
31//! - call either For() or ForEach() providing begin and end iterators and
32//! a functor object.
c7b59798 33//!
00af0ebb 34//! Iterators should satisfy requirements of STL forward iterator.
35//! Functor
c7b59798 36//!
37//! @code
38//! class Functor
39//! {
40//! public:
41//! void operator() ([proccesing instance]) const
42//! {
43//! //...
44//! }
45//! };
46//! @endcode
47//!
00af0ebb 48//! The operator () should be implemented in a thread-safe way so that
49//! the same functor object can process different data items in parallel threads.
50//!
51//! Iteration by index (For) is expected to be more efficient than using iterators
52//! (ForEach).
53//!
54//! Implementation uses TBB if OCCT is built with support of TBB; otherwise it
55//! uses ad-hoc parallelization tool. In general, if TBB is available, it is
56//! more efficient to use it directly instead of using OSD_Parallel.
57
c7b59798 58class OSD_Parallel
59{
00af0ebb 60private:
61
62 //! Interface class defining API for polymorphic wrappers over iterators.
63 //! Intended to add polymorphic behaviour to For and ForEach functionality
64 //! for arbitrary objects and eliminate dependency on template parameters.
65 class IteratorInterface
c7b59798 66 {
00af0ebb 67 public:
68 virtual ~IteratorInterface() {}
c7b59798 69
00af0ebb 70 //! Returns true if iterators wrapped by this and theOther are equal
71 virtual bool IsEqual (const IteratorInterface& theOther) const = 0;
c7b59798 72
00af0ebb 73 //! Increments wrapped iterator
74 virtual void Increment () = 0;
75
76 //! Returns new instance of the wrapper containing copy
77 //! of the wrapped iterator.
78 virtual IteratorInterface* Clone() const = 0;
79 };
c7b59798 80
00af0ebb 81 //! Implementation of polymorphic iterator wrapper suitable for basic
82 //! types as well as for std iterators.
83 //! Wraps instance of actual iterator type Type.
84 template<class Type>
85 class IteratorWrapper : public IteratorInterface
86 {
87 public:
88 IteratorWrapper() {}
89 IteratorWrapper(const Type& theValue) : myValue(theValue) {}
90
91 virtual bool IsEqual (const IteratorInterface& theOther) const Standard_OVERRIDE
c7b59798 92 {
00af0ebb 93 return myValue == dynamic_cast<const IteratorWrapper<Type>&>(theOther).myValue;
c7b59798 94 }
95
00af0ebb 96 virtual void Increment () Standard_OVERRIDE
c7b59798 97 {
00af0ebb 98 ++myValue;
c7b59798 99 }
100
00af0ebb 101 virtual IteratorInterface* Clone() const Standard_OVERRIDE
c7b59798 102 {
00af0ebb 103 return new IteratorWrapper<Type>(myValue);
c7b59798 104 }
105
00af0ebb 106 const Type& Value() const { return myValue; }
c7b59798 107
00af0ebb 108 private:
109 Type myValue;
c7b59798 110 };
111
00af0ebb 112protected:
113 // Note: UniversalIterator and FunctorInterface are made protected to be
114 // accessible from specialization using threads (non-TBB).
115
116 //! Fixed-type iterator, implementing STL forward iterator interface, used for
117 //! iteration over objects subject to parallel processing.
118 //! It stores pointer to instance of polymorphic iterator inheriting from
119 //! IteratorInterface, which contains actual type-specific iterator.
8af9bbd5 120 class UniversalIterator
00af0ebb 121 // Note that TBB requires that value_type of iterator be copyable,
122 // thus we use its own type for that
c7b59798 123 {
00af0ebb 124 public:
8af9bbd5 125
126 // Since C++20 inheritance from std::iterator is deprecated, so define predefined types manually:
127 using iterator_category = std::forward_iterator_tag;
b3284f3b 128 using value_type = IteratorInterface*;
8af9bbd5 129 using difference_type = ptrdiff_t;
b3284f3b 130 using pointer = value_type;
131 using reference = value_type;
8af9bbd5 132
00af0ebb 133 UniversalIterator() {}
c7b59798 134
00af0ebb 135 UniversalIterator(IteratorInterface* theOther)
136 : myPtr(theOther)
c7b59798 137 {
138 }
139
00af0ebb 140 UniversalIterator(const UniversalIterator& theOther)
141 : myPtr (theOther.myPtr->Clone())
c7b59798 142 {
00af0ebb 143 }
c7b59798 144
00af0ebb 145 UniversalIterator& operator= (const UniversalIterator& theOther)
146 {
147 myPtr.reset (theOther.myPtr->Clone());
148 return *this;
149 }
c7b59798 150
00af0ebb 151 bool operator!= (const UniversalIterator& theOther) const
152 {
153 return ! myPtr->IsEqual (*theOther.myPtr);
154 }
c7b59798 155
00af0ebb 156 bool operator== (const UniversalIterator& theOther) const
157 {
158 return myPtr->IsEqual (*theOther.myPtr);
c7b59798 159 }
160
00af0ebb 161 UniversalIterator& operator++()
c7b59798 162 {
00af0ebb 163 myPtr->Increment();
164 return *this;
165 }
166
167 UniversalIterator operator++(int)
168 {
169 UniversalIterator aValue(*this);
170 myPtr->Increment();
171 return aValue;
172 }
c7b59798 173
b3284f3b 174 reference operator* () const { return myPtr.get(); }
175 reference operator* () { return myPtr.get(); }
c7b59798 176
00af0ebb 177 private:
00af0ebb 178 std::unique_ptr<IteratorInterface> myPtr;
00af0ebb 179 };
c7b59798 180
00af0ebb 181 //! Interface class representing functor object.
5e6e5914 182 //! Intended to add polymorphic behaviour to For and ForEach functionality
00af0ebb 183 //! enabling execution of arbitrary function in parallel mode.
184 class FunctorInterface
185 {
186 public:
187 virtual ~FunctorInterface() {}
c7b59798 188
b3284f3b 189 virtual void operator () (IteratorInterface* theIterator) const = 0;
190
191 // type cast to actual iterator
192 template <typename Iterator>
193 static const Iterator& DownCast(IteratorInterface* theIterator)
194 {
195 return dynamic_cast<OSD_Parallel::IteratorWrapper<Iterator>*>(theIterator)->Value();
196 }
00af0ebb 197 };
c7b59798 198
00af0ebb 199private:
c7b59798 200
00af0ebb 201 //! Wrapper for functors manipulating on std iterators.
202 template<class Iterator, class Functor>
203 class FunctorWrapperIter : public FunctorInterface
204 {
205 public:
206 FunctorWrapperIter (const Functor& theFunctor)
207 : myFunctor(theFunctor)
208 {
209 }
210
b3284f3b 211 virtual void operator() (IteratorInterface* theIterator) const Standard_OVERRIDE
00af0ebb 212 {
b3284f3b 213 const Iterator& anIt = DownCast<Iterator>(theIterator);
00af0ebb 214 myFunctor(*anIt);
215 }
216
217 private:
218 FunctorWrapperIter (const FunctorWrapperIter&);
219 void operator = (const FunctorWrapperIter&);
220 const Functor& myFunctor;
c7b59798 221 };
222
00af0ebb 223 //! Wrapper for functors manipulating on integer index.
224 template<class Functor>
225 class FunctorWrapperInt : public FunctorInterface
226 {
227 public:
228 FunctorWrapperInt (const Functor& theFunctor)
229 : myFunctor(theFunctor)
230 {
231 }
c7b59798 232
b3284f3b 233 virtual void operator() (IteratorInterface* theIterator) const Standard_OVERRIDE
00af0ebb 234 {
b3284f3b 235 Standard_Integer anIndex = DownCast<Standard_Integer>(theIterator);
00af0ebb 236 myFunctor(anIndex);
237 }
238
239 private:
240 FunctorWrapperInt (const FunctorWrapperInt&);
241 void operator = (const FunctorWrapperInt&);
242 const Functor& myFunctor;
243 };
244
fc867b96 245 //! Wrapper redirecting functor taking element index to functor taking also thread index.
246 template<class Functor>
247 class FunctorWrapperForThreadPool
248 {
249 public:
250 FunctorWrapperForThreadPool (const Functor& theFunctor) : myFunctor(theFunctor) {}
251
252 void operator() (int theThreadIndex, int theElemIndex) const
253 {
254 (void )theThreadIndex;
255 myFunctor (theElemIndex);
256 }
257 private:
258 FunctorWrapperForThreadPool (const FunctorWrapperForThreadPool&);
259 void operator= (const FunctorWrapperForThreadPool&);
260 const Functor& myFunctor;
261 };
262
00af0ebb 263private:
c7b59798 264
5e3047fd 265 //! Simple primitive for parallelization of "foreach" loops, e.g.:
266 //! @code
267 //! for (std::iterator anIter = theBegin; anIter != theEnd; ++anIter) {}
268 //! @endcode
00af0ebb 269 //! Implementation of framework-dependent functionality should be provided by
270 //! forEach_impl function defined in opencascade::parallel namespace.
fc867b96 271 //! @param theBegin the first index (inclusive)
5e3047fd 272 //! @param theEnd the last index (exclusive)
00af0ebb 273 //! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}"
274 //! performing task for the specified iterator position
6f498847 275 //! @param theNbItems number of items passed by iterator, -1 if unknown
fc867b96 276 Standard_EXPORT static void forEachOcct (UniversalIterator& theBegin,
277 UniversalIterator& theEnd,
278 const FunctorInterface& theFunctor,
279 Standard_Integer theNbItems);
280
281 //! Same as forEachOcct() but can be implemented using external threads library.
282 Standard_EXPORT static void forEachExternal (UniversalIterator& theBegin,
283 UniversalIterator& theEnd,
284 const FunctorInterface& theFunctor,
285 Standard_Integer theNbItems);
00af0ebb 286
287public: //! @name public methods
288
fc867b96 289 //! Returns TRUE if OCCT threads should be used instead of auxiliary threads library;
290 //! default value is FALSE if alternative library has been enabled while OCCT building and TRUE otherwise.
291 Standard_EXPORT static Standard_Boolean ToUseOcctThreads();
292
293 //! Sets if OCCT threads should be used instead of auxiliary threads library.
294 //! Has no effect if OCCT has been built with no auxiliary threads library.
295 Standard_EXPORT static void SetUseOcctThreads (Standard_Boolean theToUseOcct);
296
297 //! Returns number of logical processors.
00af0ebb 298 Standard_EXPORT static Standard_Integer NbLogicalProcessors();
c7b59798 299
00af0ebb 300 //! Simple primitive for parallelization of "foreach" loops, equivalent to:
5e3047fd 301 //! @code
00af0ebb 302 //! for (auto anIter = theBegin; anIter != theEnd; ++anIter) {
303 //! theFunctor(*anIter);
304 //! }
5e3047fd 305 //! @endcode
fc867b96 306 //! @param theBegin the first index (inclusive)
5e3047fd 307 //! @param theEnd the last index (exclusive)
00af0ebb 308 //! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}"
309 //! performing task for specified iterator position
5e3047fd 310 //! @param isForceSingleThreadExecution if true, then no threads will be created
6f498847 311 //! @param theNbItems number of items passed by iterator, -1 if unknown
00af0ebb 312 template <typename InputIterator, typename Functor>
313 static void ForEach(InputIterator theBegin,
314 InputIterator theEnd,
315 const Functor& theFunctor,
6f498847 316 const Standard_Boolean isForceSingleThreadExecution = Standard_False,
317 Standard_Integer theNbItems = -1)
c7b59798 318 {
6f498847 319 if (isForceSingleThreadExecution || theNbItems == 1)
c7b59798 320 {
00af0ebb 321 for (InputIterator it(theBegin); it != theEnd; ++it)
322 theFunctor(*it);
c7b59798 323 }
00af0ebb 324 else
c7b59798 325 {
00af0ebb 326 UniversalIterator aBegin(new IteratorWrapper<InputIterator>(theBegin));
327 UniversalIterator aEnd (new IteratorWrapper<InputIterator>(theEnd));
328 FunctorWrapperIter<InputIterator,Functor> aFunctor (theFunctor);
fc867b96 329 if (ToUseOcctThreads())
330 {
331 forEachOcct (aBegin, aEnd, aFunctor, theNbItems);
332 }
333 else
334 {
335 forEachExternal (aBegin, aEnd, aFunctor, theNbItems);
336 }
c7b59798 337 }
338 }
c7b59798 339
00af0ebb 340 //! Simple primitive for parallelization of "for" loops, equivalent to:
341 //! @code
342 //! for (int anIter = theBegin; anIter != theEnd; ++anIter) {
343 //! theFunctor(anIter);
344 //! }
345 //! @endcode
fc867b96 346 //! @param theBegin the first index (inclusive)
00af0ebb 347 //! @param theEnd the last index (exclusive)
348 //! @param theFunctor functor providing an interface "void operator(int theIndex){}"
349 //! performing task for specified index
350 //! @param isForceSingleThreadExecution if true, then no threads will be created
351 template <typename Functor>
352 static void For(const Standard_Integer theBegin,
353 const Standard_Integer theEnd,
354 const Functor& theFunctor,
355 const Standard_Boolean isForceSingleThreadExecution = Standard_False)
c7b59798 356 {
fc867b96 357 const Standard_Integer aRange = theEnd - theBegin;
358 if (isForceSingleThreadExecution || aRange == 1)
c7b59798 359 {
00af0ebb 360 for (Standard_Integer it (theBegin); it != theEnd; ++it)
361 theFunctor(it);
c7b59798 362 }
fc867b96 363 else if (ToUseOcctThreads())
364 {
365 const Handle(OSD_ThreadPool)& aThreadPool = OSD_ThreadPool::DefaultPool();
366 OSD_ThreadPool::Launcher aPoolLauncher (*aThreadPool, aRange);
367 FunctorWrapperForThreadPool<Functor> aFunctor (theFunctor);
368 aPoolLauncher.Perform (theBegin, theEnd, aFunctor);
369 }
00af0ebb 370 else
c7b59798 371 {
00af0ebb 372 UniversalIterator aBegin(new IteratorWrapper<Standard_Integer>(theBegin));
373 UniversalIterator aEnd (new IteratorWrapper<Standard_Integer>(theEnd));
374 FunctorWrapperInt<Functor> aFunctor (theFunctor);
fc867b96 375 forEachExternal (aBegin, aEnd, aFunctor, aRange);
c7b59798 376 }
377 }
c7b59798 378
00af0ebb 379};
c7b59798 380
381#endif