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