Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:04:37

0001 // Copyright (c) 2013-2014 OPEN CASCADE SAS
0002 //
0003 // This file is part of Open CASCADE Technology software library.
0004 //
0005 // This library is free software; you can redistribute it and/or modify it under
0006 // the terms of the GNU Lesser General Public License version 2.1 as published
0007 // by the Free Software Foundation, with special exception defined in the file
0008 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0009 // distribution for complete text of the license and disclaimer of any warranty.
0010 //
0011 // Alternatively, this file may be used under the terms of Open CASCADE
0012 // commercial license or contractual agreement.
0013 
0014 #ifndef OSD_Parallel_HeaderFile
0015 #define OSD_Parallel_HeaderFile
0016 
0017 #include <OSD_ThreadPool.hxx>
0018 #include <Standard_Type.hxx>
0019 #include <memory>
0020 
0021 //! @brief Simple tool for code parallelization.
0022 //!
0023 //! OSD_Parallel class provides simple interface for parallel processing of 
0024 //! tasks that can be formulated in terms of "for" or "foreach" loops.
0025 //!
0026 //! To use this tool it is necessary to:
0027 //! - organize the data to be processed in a collection accessible by
0028 //!   iteration (usually array or vector);
0029 //! - implement a functor class providing operator () accepting iterator
0030 //!   (or index in array) that does the job;
0031 //! - call either For() or ForEach() providing begin and end iterators and
0032 //!   a functor object.
0033 //!
0034 //! Iterators should satisfy requirements of STL forward iterator.
0035 //! Functor 
0036 //!
0037 //! @code
0038 //! class Functor
0039 //! {
0040 //! public:
0041 //!   void operator() ([proccesing instance]) const
0042 //!   {
0043 //!     //...
0044 //!   }
0045 //! };
0046 //! @endcode
0047 //!
0048 //! The operator () should be implemented in a thread-safe way so that
0049 //! the same functor object can process different data items in parallel threads.
0050 //!
0051 //! Iteration by index (For) is expected to be more efficient than using iterators
0052 //! (ForEach).
0053 //!
0054 //! Implementation uses TBB if OCCT is built with support of TBB; otherwise it
0055 //! uses ad-hoc parallelization tool. In general, if TBB is available, it is
0056 //! more efficient to use it directly instead of using OSD_Parallel.
0057 
0058 class OSD_Parallel
0059 {
0060 private:
0061 
0062   //! Interface class defining API for polymorphic wrappers over iterators.
0063   //! Intended to add polymorphic behaviour to For and ForEach functionality
0064   //! for arbitrary objects and eliminate dependency on template parameters.
0065   class IteratorInterface
0066   {
0067   public:
0068     virtual ~IteratorInterface() {}
0069 
0070     //! Returns true if iterators wrapped by this and theOther are equal
0071     virtual bool IsEqual (const IteratorInterface& theOther) const = 0;
0072 
0073     //! Increments wrapped iterator
0074     virtual void Increment () = 0;
0075 
0076     //! Returns new instance of the wrapper containing copy
0077     //! of the wrapped iterator.
0078     virtual IteratorInterface* Clone() const = 0;
0079   };
0080 
0081   //! Implementation of polymorphic iterator wrapper suitable for basic 
0082   //! types as well as for std iterators.
0083   //! Wraps instance of actual iterator type Type.
0084   template<class Type>
0085   class IteratorWrapper : public IteratorInterface
0086   {
0087   public:
0088     IteratorWrapper() {}
0089     IteratorWrapper(const Type& theValue) : myValue(theValue) {}
0090 
0091     virtual bool IsEqual (const IteratorInterface& theOther) const Standard_OVERRIDE
0092     {
0093       return myValue == dynamic_cast<const IteratorWrapper<Type>&>(theOther).myValue;
0094     }
0095 
0096     virtual void Increment () Standard_OVERRIDE
0097     {
0098       ++myValue;
0099     }
0100 
0101     virtual IteratorInterface* Clone() const Standard_OVERRIDE
0102     {
0103       return new IteratorWrapper<Type>(myValue);
0104     }
0105 
0106     const Type& Value() const { return myValue; }
0107 
0108   private:
0109     Type myValue;
0110   };
0111 
0112 protected:
0113   // Note: UniversalIterator and FunctorInterface are made protected to be
0114   // accessible from specialization using threads (non-TBB).
0115 
0116   //! Fixed-type iterator, implementing STL forward iterator interface, used for 
0117   //! iteration over objects subject to parallel processing.
0118   //! It stores pointer to instance of polymorphic iterator inheriting from 
0119   //! IteratorInterface, which contains actual type-specific iterator.
0120   class UniversalIterator
0121     // Note that TBB requires that value_type of iterator be copyable, 
0122     // thus we use its own type for that
0123   {
0124   public:
0125 
0126     // Since C++20 inheritance from std::iterator is deprecated, so define predefined types manually:
0127     using iterator_category = std::forward_iterator_tag;
0128     using value_type = IteratorInterface*;
0129     using difference_type = ptrdiff_t;
0130     using pointer = value_type;
0131     using reference = value_type;
0132 
0133     UniversalIterator() {}
0134 
0135     UniversalIterator(IteratorInterface* theOther)
0136     : myPtr(theOther)
0137     {
0138     }
0139 
0140     UniversalIterator(const UniversalIterator& theOther)
0141     : myPtr (theOther.myPtr->Clone())
0142     {
0143     }
0144 
0145     UniversalIterator& operator= (const UniversalIterator& theOther)
0146     {
0147       myPtr.reset (theOther.myPtr->Clone());
0148       return *this;
0149     }
0150 
0151     bool operator!= (const UniversalIterator& theOther) const
0152     {
0153       return ! myPtr->IsEqual (*theOther.myPtr);
0154     }
0155 
0156     bool operator== (const UniversalIterator& theOther) const
0157     {
0158       return myPtr->IsEqual (*theOther.myPtr);
0159     }
0160 
0161     UniversalIterator& operator++()
0162     {
0163       myPtr->Increment();
0164       return *this;
0165     }
0166 
0167     UniversalIterator operator++(int)
0168     {
0169       UniversalIterator aValue(*this);
0170       myPtr->Increment();
0171       return aValue;
0172     }
0173 
0174     reference operator* () const { return myPtr.get(); }
0175     reference operator* () { return myPtr.get(); }
0176 
0177   private:
0178     std::unique_ptr<IteratorInterface> myPtr;
0179   };
0180 
0181   //! Interface class representing functor object.
0182   //! Intended to add polymorphic behaviour to For and ForEach functionality
0183   //! enabling execution of arbitrary function in parallel mode.
0184   class FunctorInterface
0185   {
0186   public:
0187     virtual ~FunctorInterface() {}
0188 
0189     virtual void operator () (IteratorInterface* theIterator) const = 0;
0190 
0191     // type cast to actual iterator
0192     template <typename Iterator>
0193     static const Iterator& DownCast(IteratorInterface* theIterator)
0194     {
0195       return dynamic_cast<OSD_Parallel::IteratorWrapper<Iterator>*>(theIterator)->Value();
0196     }
0197   };
0198 
0199 private:
0200 
0201   //! Wrapper for functors manipulating on std iterators.
0202   template<class Iterator, class Functor>
0203   class FunctorWrapperIter : public FunctorInterface
0204   {
0205   public:
0206     FunctorWrapperIter (const Functor& theFunctor)
0207       : myFunctor(theFunctor)
0208     {
0209     }
0210 
0211     virtual void operator() (IteratorInterface* theIterator) const Standard_OVERRIDE
0212     {
0213       const Iterator& anIt = DownCast<Iterator>(theIterator);
0214       myFunctor(*anIt);
0215     }
0216 
0217   private:
0218     FunctorWrapperIter (const FunctorWrapperIter&);
0219     void operator = (const FunctorWrapperIter&);
0220     const Functor& myFunctor;
0221   };
0222 
0223   //! Wrapper for functors manipulating on integer index.
0224   template<class Functor>
0225   class FunctorWrapperInt : public FunctorInterface
0226   {
0227   public:
0228     FunctorWrapperInt (const Functor& theFunctor)
0229       : myFunctor(theFunctor)
0230     {
0231     }
0232 
0233     virtual void operator() (IteratorInterface* theIterator) const Standard_OVERRIDE
0234     {
0235       Standard_Integer anIndex = DownCast<Standard_Integer>(theIterator);
0236       myFunctor(anIndex);
0237     }
0238 
0239   private:
0240     FunctorWrapperInt (const FunctorWrapperInt&);
0241     void operator = (const FunctorWrapperInt&);
0242     const Functor& myFunctor;
0243   };
0244 
0245   //! Wrapper redirecting functor taking element index to functor taking also thread index.
0246   template<class Functor>
0247   class FunctorWrapperForThreadPool
0248   {
0249   public:
0250     FunctorWrapperForThreadPool (const Functor& theFunctor) : myFunctor(theFunctor) {}
0251 
0252     void operator() (int theThreadIndex, int theElemIndex) const
0253     {
0254       (void )theThreadIndex;
0255       myFunctor (theElemIndex);
0256     }
0257   private:
0258     FunctorWrapperForThreadPool (const FunctorWrapperForThreadPool&);
0259     void operator= (const FunctorWrapperForThreadPool&);
0260     const Functor& myFunctor;
0261   };
0262 
0263 private:
0264 
0265   //! Simple primitive for parallelization of "foreach" loops, e.g.:
0266   //! @code
0267   //!   for (std::iterator anIter = theBegin; anIter != theEnd; ++anIter) {}
0268   //! @endcode
0269   //! Implementation of framework-dependent functionality should be provided by
0270   //! forEach_impl function defined in opencascade::parallel namespace.
0271   //! @param theBegin   the first index (inclusive)
0272   //! @param theEnd     the last  index (exclusive)
0273   //! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}" 
0274   //!                   performing task for the specified iterator position
0275   //! @param theNbItems number of items passed by iterator, -1 if unknown
0276   Standard_EXPORT static void forEachOcct (UniversalIterator& theBegin,
0277                                            UniversalIterator& theEnd,
0278                                            const FunctorInterface& theFunctor,
0279                                            Standard_Integer theNbItems);
0280 
0281   //! Same as forEachOcct() but can be implemented using external threads library.
0282   Standard_EXPORT static void forEachExternal (UniversalIterator& theBegin,
0283                                                UniversalIterator& theEnd,
0284                                                const FunctorInterface& theFunctor,
0285                                                Standard_Integer theNbItems);
0286 
0287 public: //! @name public methods
0288 
0289   //! Returns TRUE if OCCT threads should be used instead of auxiliary threads library;
0290   //! default value is FALSE if alternative library has been enabled while OCCT building and TRUE otherwise.
0291   Standard_EXPORT static Standard_Boolean ToUseOcctThreads();
0292 
0293   //! Sets if OCCT threads should be used instead of auxiliary threads library.
0294   //! Has no effect if OCCT has been built with no auxiliary threads library.
0295   Standard_EXPORT static void SetUseOcctThreads (Standard_Boolean theToUseOcct);
0296 
0297   //! Returns number of logical processors.
0298   Standard_EXPORT static Standard_Integer NbLogicalProcessors();
0299 
0300   //! Simple primitive for parallelization of "foreach" loops, equivalent to:
0301   //! @code
0302   //!   for (auto anIter = theBegin; anIter != theEnd; ++anIter) {
0303   //!     theFunctor(*anIter);
0304   //!   }
0305   //! @endcode
0306   //! @param theBegin   the first index (inclusive)
0307   //! @param theEnd     the last  index (exclusive)
0308   //! @param theFunctor functor providing an interface "void operator(InputIterator theIter){}" 
0309   //!                   performing task for specified iterator position
0310   //! @param isForceSingleThreadExecution if true, then no threads will be created
0311   //! @param theNbItems number of items passed by iterator, -1 if unknown
0312   template <typename InputIterator, typename Functor>
0313   static void ForEach(InputIterator          theBegin,
0314                       InputIterator          theEnd,
0315                       const Functor&         theFunctor,
0316                       const Standard_Boolean isForceSingleThreadExecution = Standard_False,
0317                       Standard_Integer theNbItems = -1)
0318   {
0319     if (isForceSingleThreadExecution || theNbItems == 1)
0320     {
0321       for (InputIterator it(theBegin); it != theEnd; ++it)
0322         theFunctor(*it);
0323     }
0324     else
0325     {
0326       UniversalIterator aBegin(new IteratorWrapper<InputIterator>(theBegin));
0327       UniversalIterator aEnd  (new IteratorWrapper<InputIterator>(theEnd));
0328       FunctorWrapperIter<InputIterator,Functor> aFunctor (theFunctor);
0329       if (ToUseOcctThreads())
0330       {
0331         forEachOcct (aBegin, aEnd, aFunctor, theNbItems);
0332       }
0333       else
0334       {
0335         forEachExternal (aBegin, aEnd, aFunctor, theNbItems);
0336       }
0337     }
0338   }
0339 
0340   //! Simple primitive for parallelization of "for" loops, equivalent to:
0341   //! @code
0342   //!   for (int anIter = theBegin; anIter != theEnd; ++anIter) {
0343   //!     theFunctor(anIter);
0344   //!   }
0345   //! @endcode
0346   //! @param theBegin   the first index (inclusive)
0347   //! @param theEnd     the last  index (exclusive)
0348   //! @param theFunctor functor providing an interface "void operator(int theIndex){}" 
0349   //!                   performing task for specified index
0350   //! @param isForceSingleThreadExecution if true, then no threads will be created
0351   template <typename Functor>
0352   static void For(const Standard_Integer theBegin,
0353                   const Standard_Integer theEnd,
0354                   const Functor&         theFunctor,
0355                   const Standard_Boolean isForceSingleThreadExecution = Standard_False)
0356   {
0357     const Standard_Integer aRange = theEnd - theBegin;
0358     if (isForceSingleThreadExecution || aRange == 1)
0359     {
0360       for (Standard_Integer it (theBegin); it != theEnd; ++it)
0361         theFunctor(it);
0362     }
0363     else if (ToUseOcctThreads())
0364     {
0365       const Handle(OSD_ThreadPool)& aThreadPool = OSD_ThreadPool::DefaultPool();
0366       OSD_ThreadPool::Launcher aPoolLauncher (*aThreadPool, aRange);
0367       FunctorWrapperForThreadPool<Functor> aFunctor (theFunctor);
0368       aPoolLauncher.Perform (theBegin, theEnd, aFunctor);
0369     }
0370     else
0371     {
0372       UniversalIterator aBegin(new IteratorWrapper<Standard_Integer>(theBegin));
0373       UniversalIterator aEnd  (new IteratorWrapper<Standard_Integer>(theEnd));
0374       FunctorWrapperInt<Functor> aFunctor (theFunctor);
0375       forEachExternal (aBegin, aEnd, aFunctor, aRange);
0376     }
0377   }
0378 
0379 };
0380 
0381 #endif