Kokkos Node API and Local Linear Algebra Kernels Version of the Day
Tsqr_NodeTsqrFactory.hpp
00001 //@HEADER
00002 // ************************************************************************
00003 // 
00004 //          Kokkos: Node API and Parallel Node Kernels
00005 //              Copyright (2009) Sandia Corporation
00006 // 
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 // 
00010 // This library is free software; you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as
00012 // published by the Free Software Foundation; either version 2.1 of the
00013 // License, or (at your option) any later version.
00014 //  
00015 // This library is distributed in the hope that it will be useful, but
00016 // WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 // Lesser General Public License for more details.
00019 //  
00020 // You should have received a copy of the GNU Lesser General Public
00021 // License along with this library; if not, write to the Free Software
00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00023 // USA
00024 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 
00025 // 
00026 // ************************************************************************
00027 //@HEADER
00028 
00029 #ifndef __TSQR_NodeTsqrFactory_hpp
00030 #define __TSQR_NodeTsqrFactory_hpp
00031 
00032 #include <Kokkos_ConfigDefs.hpp> // HAVE_KOKKOS_TBB
00033 
00034 #ifdef HAVE_KOKKOS_TBB
00035 #  include <Kokkos_TBBNode.hpp>
00036 #  include <TbbTsqr.hpp>
00037 #  include <tbb/task_scheduler_init.h>
00038 #endif // HAVE_KOKKOS_TBB
00039 
00040 #include <Kokkos_SerialNode.hpp>
00041 #include <Tsqr_SequentialTsqr.hpp>
00042 
00043 #include <Teuchos_ParameterList.hpp>
00044 #include <Teuchos_ParameterListExceptions.hpp>
00045 #include <Teuchos_RCP.hpp>
00046 #include <Teuchos_ScalarTraits.hpp>
00047 
00048 #include <stdexcept>
00049 
00052 
00053 namespace TSQR {
00054 
00057   template<class Node, class Scalar, class LocalOrdinal>
00058   class NodeTsqrFactory {
00059   public:
00060     typedef Node node_type;
00061     typedef Teuchos::RCP<node_type> node_ptr;
00062     // Just a default
00063     typedef SequentialTsqr<LocalOrdinal, Scalar> node_tsqr_type;
00064 
00071     static Teuchos::RCP<const Teuchos::ParameterList>
00072     getDefaultParameters ()
00073     {
00074       using Teuchos::ParameterList;
00075       using Teuchos::RCP;
00076 
00077       // FIXME (mfh 28 Oct 2010) The use of persistent data means that
00078       // this routine is NOT reentrant.  That means that it is not
00079       // thread-safe, for example.  One way to make this routine
00080       // reentrant would be to use a construct like pthread_once().
00081       static RCP< const ParameterList > defaultParams_;
00082       if (defaultParams_.is_null())
00083   {
00084     RCP<ParameterList> params = Teuchos::parameterList();
00085     defaultParams_ = params;
00086   }
00087       return defaultParams_;
00088     }
00089 
00096     static Teuchos::RCP< node_tsqr_type >
00097     makeNodeTsqr (const Teuchos::RCP<const Teuchos::ParameterList>& plist)
00098     {
00099       throw std::logic_error("TSQR is not supported on your Kokkos Node type");
00100     }
00101   };
00102 
00103   template< class T >
00104   static void
00105   getParamValue (const Teuchos::RCP<const Teuchos::ParameterList>& plist,
00106      const char name[],
00107      T& value, // set to default before calling
00108      bool& gotValue)
00109   {
00110     if (plist.is_null())
00111       {
00112   gotValue = false;
00113   return;
00114       }
00115     // All this try/catch stuff is because the C++ compiler can't
00116     // deduce the right two-argument get() function (second argument
00117     // would be the default).
00118     T retrievedValue;
00119     try {
00120       const std::string paramName (name);
00121       // We know from above that plist is not null.
00122       retrievedValue = plist->get< T > (paramName);
00123       gotValue = true;
00124     } catch (Teuchos::Exceptions::InvalidParameter&) { 
00125       // Could be wrong type (InvalidParameterType) or wrong name
00126       // (InvalidParameterName).  In either case, we just say that the
00127       // value doesn't exist.  
00128       //
00129       // For now, we just ignore the parameter if the type is wrong.
00130       // This is because we want TSQR "just to work" even if the
00131       // parameters are wrong; the parameters are "options" and should
00132       // be "optional."
00133       gotValue = false;
00134     }
00135     // Only write to the output argument if we got a value out of the
00136     // parameter list.  (This means that getParamValue() has the
00137     // strong exception guarantee (no destructive updates if it
00138     // throws), as long as T's assignment operator also has the strong
00139     // exception guarantee.)
00140     if (gotValue)
00141       value = retrievedValue;
00142   }
00143 
00144   static size_t
00145   getCacheSizeHint (const Teuchos::RCP<const Teuchos::ParameterList>& params, 
00146         const Teuchos::RCP<const Teuchos::ParameterList>& defaultParams)
00147   {
00148     // We try to guess among some reasonable names.  The first in the
00149     // list is the canonical name.  "cacheBlockSize" and related names
00150     // are retained only for backwards compatibility and may be
00151     // removed at any time.
00152     const char* possibleNames[] = {"cacheSizeHint",
00153            "cache_size_hint",
00154            "cacheSize",
00155            "cache_size",
00156            "cacheBlockSize",
00157            "cache_block_size"};
00158     const int numPossibleNames = 6;
00159     size_t cacheSizeHint = 0;
00160     bool gotCacheSizeHint = false;
00161       
00162     for (int trial = 0; trial < numPossibleNames && ! gotCacheSizeHint; ++trial)
00163       getParamValue< size_t > (params, possibleNames[trial], 
00164              cacheSizeHint, gotCacheSizeHint);
00165     if (! gotCacheSizeHint)
00166       {
00167   // Default parameters had better have the value, so we don't
00168   // try to catch any exceptions here.
00169   const std::string canonicalName (possibleNames[0]);
00170   cacheSizeHint = defaultParams->get< size_t > (canonicalName);
00171       }
00172     return cacheSizeHint;
00173   }
00174 
00175 #ifdef HAVE_KOKKOS_TBB
00176   static int
00177   getNumCores (const Teuchos::RCP<const Teuchos::ParameterList>& params,
00178          const Teuchos::RCP<const Teuchos::ParameterList>& defaultParams)
00179   {
00180     // We try to guess among some reasonable names.
00181     // The first in the list is the canonical name.
00182     const char* possibleNames[] = {"numCores",
00183            "ncores",
00184            "numThreads",
00185            "nthreads", 
00186            "numTasks",
00187            "ntasks"};
00188     const int numPossibleNames = 6;
00189     int numCores = 1; // will reset this below
00190     bool gotNumCores = false;
00191 
00192     for (int trial = 0; trial < numPossibleNames && ! gotNumCores; ++trial)
00193       getParamValue< int > (params, possibleNames[trial], 
00194           numCores, gotNumCores);
00195     if (! gotNumCores)
00196       {
00197   // Default parameters had better have the value, so we don't
00198   // try to catch any exceptions here.
00199   const std::string canonicalName (possibleNames[0]);
00200   numCores = defaultParams->get< int > (canonicalName);
00201       }
00202     return numCores;
00203   }
00204 
00205   template<class Scalar, class LocalOrdinal>
00206   class NodeTsqrFactory<Kokkos::TBBNode, Scalar, LocalOrdinal> {
00207   public:
00208     typedef Kokkos::TBBNode node_type;
00209     typedef Teuchos::RCP<node_type> node_ptr;
00210     typedef TBB::TbbTsqr<LocalOrdinal, Scalar> node_tsqr_type;
00211 
00226     static Teuchos::RCP<const Teuchos::ParameterList>
00227     getDefaultParameters ()
00228     {
00229       using Teuchos::ParameterList;
00230       using Teuchos::RCP;
00231 
00232       // FIXME (mfh 28 Oct 2010) The use of persistent data means that
00233       // this routine is NOT reentrant.  That means that it is not
00234       // thread-safe, for example.  One way to make this routine
00235       // reentrant would be to use a construct like pthread_once().
00236       static RCP<const ParameterList> defaultParams_;
00237       if (defaultParams_.is_null())
00238   {
00239     RCP<ParameterList> params = Teuchos::parameterList();
00240     // The TSQR implementation sets a reasonable default value
00241     // if you tell it that the cache block size is zero.
00242     const size_t defaultCacheSizeHint = 0;
00243     params->set ("cacheSizeHint", defaultCacheSizeHint,
00244            "Cache size hint in bytes (as a size_t) to use for intr"
00245            "anode TSQR.  If zero, the intranode TSQR implementation"
00246            " will pick a reasonable default.");
00247     // TSQR uses a recursive division of the tall skinny matrix
00248     // into TBB tasks.  Each task works on a block row.  The TBB
00249     // task scheduler ensures that oversubscribing TBB tasks
00250     // won't oversubscribe cores, so it's OK if
00251     // default_num_threads() is too many.  For example, TBB
00252     // might say default_num_threads() is the number of cores on
00253     // the node, but the TBB task scheduler might have been
00254     // initialized with the number of cores per NUMA region, for
00255     // hybrid MPI + TBB parallelism.
00256     const int defaultNumCores = 
00257       tbb::task_scheduler_init::default_num_threads();
00258     params->set ("numCores", defaultNumCores, 
00259            "Number of tasks (\"threads\") to use in the intranode "
00260            "parallel part of TSQR.  There is little/no performance "
00261            "penalty for mild oversubscription, but a potential "
00262            "penalty for undersubscription.");
00263     defaultParams_ = params;
00264   }
00265       return defaultParams_;
00266     }
00267 
00268     static Teuchos::RCP<node_tsqr_type>
00269     makeNodeTsqr (const Teuchos::RCP<const Teuchos::ParameterList>& params)
00270     {
00271       Teuchos::RCP<const Teuchos::ParameterList> defaultParams = 
00272   getDefaultParameters ();
00273       const size_t cacheSizeHint = getCacheSizeHint (params, defaultParams);
00274       const int numCores = getNumCores (params, defaultParams);
00275       return Teuchos::rcp (new node_tsqr_type (numCores, cacheSizeHint));
00276     }
00277   };
00278 #endif // HAVE_KOKKOS_TBB
00279 
00280   template< class Scalar, class LocalOrdinal >
00281   class NodeTsqrFactory<Kokkos::SerialNode, Scalar, LocalOrdinal> {
00282   public:
00283     typedef Kokkos::SerialNode node_type;
00284     typedef Teuchos::RCP<node_type> node_ptr;
00285     typedef SequentialTsqr<LocalOrdinal, Scalar> node_tsqr_type;
00286 
00296     static Teuchos::RCP< const Teuchos::ParameterList >
00297     getDefaultParameters ()
00298     {
00299       using Teuchos::ParameterList;
00300       using Teuchos::RCP;
00301 
00302       // FIXME (mfh 28 Oct 2010) The use of persistent data means that
00303       // this routine is NOT reentrant.  That means that it is not
00304       // thread-safe, for example.  One way to make this routine
00305       // reentrant would be to use a construct like pthread_once().
00306       static RCP<const ParameterList> defaultParams_;
00307       if (defaultParams_.is_null())
00308   {
00309     RCP<ParameterList> params = Teuchos::parameterList();
00310     // The TSQR implementation sets a reasonable default value
00311     // if you give it a cache size hint of zero.
00312     const size_t defaultCacheSizeHint = 0;
00313     params->set ("cacheSizeHint", defaultCacheSizeHint,
00314            "Cache size hint in bytes (as a size_t) to use for intra"
00315            "node TSQR.  If zero, the intranode TSQR implementation "
00316            "will pick a reasonable default.");
00317     defaultParams_ = params;
00318   }
00319       return defaultParams_;
00320     }
00321 
00322     static Teuchos::RCP<node_tsqr_type>
00323     makeNodeTsqr (const Teuchos::RCP<const Teuchos::ParameterList>& params)
00324     {
00325       Teuchos::RCP<const Teuchos::ParameterList> defaultParams = 
00326   getDefaultParameters ();
00327       const size_t cacheSizeHint = getCacheSizeHint (params, defaultParams);
00328       return Teuchos::rcp (new node_tsqr_type (cacheSizeHint));
00329     }
00330   };
00331 
00332 } // namespace TSQR
00333 
00334 #endif // __TSQR_NodeTsqrFactory_hpp
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends