Parallelizer.h
Go to the documentation of this file.
00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2010 Gael Guennebaud <gael.guennebaud@inria.fr>
00005 //
00006 // Eigen is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 3 of the License, or (at your option) any later version.
00010 //
00011 // Alternatively, you can redistribute it and/or
00012 // modify it under the terms of the GNU General Public License as
00013 // published by the Free Software Foundation; either version 2 of
00014 // the License, or (at your option) any later version.
00015 //
00016 // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
00017 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00018 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
00019 // GNU General Public License for more details.
00020 //
00021 // You should have received a copy of the GNU Lesser General Public
00022 // License and a copy of the GNU General Public License along with
00023 // Eigen. If not, see <http://www.gnu.org/licenses/>.
00024 
00025 #ifndef EIGEN_PARALLELIZER_H
00026 #define EIGEN_PARALLELIZER_H
00027 
00028 namespace internal {
00029 
00031 inline void manage_multi_threading(Action action, int* v)
00032 {
00033   static EIGEN_UNUSED int m_maxThreads = -1;
00034 
00035   if(action==SetAction)
00036   {
00037     eigen_internal_assert(v!=0);
00038     m_maxThreads = *v;
00039   }
00040   else if(action==GetAction)
00041   {
00042     eigen_internal_assert(v!=0);
00043     #ifdef EIGEN_HAS_OPENMP
00044     if(m_maxThreads>0)
00045       *v = m_maxThreads;
00046     else
00047       *v = omp_get_max_threads();
00048     #else
00049     *v = 1;
00050     #endif
00051   }
00052   else
00053   {
00054     eigen_internal_assert(false);
00055   }
00056 }
00057 
00060 inline int nbThreads()
00061 {
00062   int ret;
00063   manage_multi_threading(GetAction, &ret);
00064   return ret;
00065 }
00066 
00069 inline void setNbThreads(int v)
00070 {
00071   manage_multi_threading(SetAction, &v);
00072 }
00073 
00074 template<typename Index> struct GemmParallelInfo
00075 {
00076   GemmParallelInfo() : sync(-1), users(0), rhs_start(0), rhs_length(0) {}
00077 
00078   int volatile sync;
00079   int volatile users;
00080 
00081   Index rhs_start;
00082   Index rhs_length;
00083 };
00084 
00085 template<bool Condition, typename Functor, typename Index>
00086 void parallelize_gemm(const Functor& func, Index rows, Index cols, bool transpose)
00087 {
00088 #ifndef EIGEN_HAS_OPENMP
00089   // FIXME the transpose variable is only needed to properly split
00090   // the matrix product when multithreading is enabled. This is a temporary
00091   // fix to support row-major destination matrices. This whole
00092   // parallelizer mechanism has to be redisigned anyway.
00093   EIGEN_UNUSED_VARIABLE(transpose);
00094   func(0,rows, 0,cols);
00095 #else
00096 
00097   // Dynamically check whether we should enable or disable OpenMP.
00098   // The conditions are:
00099   // - the max number of threads we can create is greater than 1
00100   // - we are not already in a parallel code
00101   // - the sizes are large enough
00102 
00103   // 1- are we already in a parallel session?
00104   // FIXME omp_get_num_threads()>1 only works for openmp, what if the user does not use openmp?
00105   if((!Condition) || (omp_get_num_threads()>1))
00106     return func(0,rows, 0,cols);
00107 
00108   Index size = transpose ? cols : rows;
00109 
00110   // 2- compute the maximal number of threads from the size of the product:
00111   // FIXME this has to be fine tuned
00112   Index max_threads = std::max<Index>(1,size / 32);
00113 
00114   // 3 - compute the number of threads we are going to use
00115   Index threads = std::min<Index>(nbThreads(), max_threads);
00116 
00117   if(threads==1)
00118     return func(0,rows, 0,cols);
00119 
00120   func.initParallelSession();
00121 
00122   if(transpose)
00123     std::swap(rows,cols);
00124 
00125   Index blockCols = (cols / threads) & ~Index(0x3);
00126   Index blockRows = (rows / threads) & ~Index(0x7);
00127   
00128   GemmParallelInfo<Index>* info = new GemmParallelInfo<Index>[threads];
00129 
00130   #pragma omp parallel for schedule(static,1) num_threads(threads)
00131   for(Index i=0; i<threads; ++i)
00132   {
00133     Index r0 = i*blockRows;
00134     Index actualBlockRows = (i+1==threads) ? rows-r0 : blockRows;
00135 
00136     Index c0 = i*blockCols;
00137     Index actualBlockCols = (i+1==threads) ? cols-c0 : blockCols;
00138 
00139     info[i].rhs_start = c0;
00140     info[i].rhs_length = actualBlockCols;
00141 
00142     if(transpose)
00143       func(0, cols, r0, actualBlockRows, info);
00144     else
00145       func(r0, actualBlockRows, 0,cols, info);
00146   }
00147 
00148   delete[] info;
00149 #endif
00150 }
00151 
00152 } // end namespace internal
00153 
00154 #endif // EIGEN_PARALLELIZER_H


libicr
Author(s): Robert Krug
autogenerated on Mon Jan 6 2014 11:33:08