Kokkos Node API and Local Linear Algebra Kernels Version of the Day
DefaultSparseOps_TestSparseOps.cpp
00001 //@HEADER
00002 // ************************************************************************
00003 //
00004 //          Kokkos: Node API and Parallel Node Kernels
00005 //              Copyright (2008) Sandia Corporation
00006 //
00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00008 // the U.S. Government retains certain rights in this software.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ************************************************************************
00040 //@HEADER
00041 
00042 #include <Teuchos_UnitTestHarness.hpp>
00043 
00044 #include "Kokkos_ConfigDefs.hpp"
00045 #include "Kokkos_DefaultNode.hpp"
00046 #include "Kokkos_DefaultSparseOps.hpp"
00047 #include "Kokkos_AltSparseOps.hpp"
00048 #include "Kokkos_Version.hpp"
00049 #include "DefaultSparseOps_TestSparseOps.hpp"
00050 
00051 
00052 namespace {
00053   using Kokkos::DefaultNode;
00054   using Teuchos::arcp;
00055   using Teuchos::ArrayRCP;
00056   using Teuchos::null;
00057   using Teuchos::ParameterList;
00058   using Teuchos::parameterList;
00059   using Teuchos::RCP;
00060   using Teuchos::rcp;
00061 
00062   //
00063   // mfh 28 Jun 2012: scalar_type, ordinal_type, and node_type are the
00064   // template parameters of interest for Kokkos local sparse kernels.
00065   // In practice, ordinal_type is usually int, and always should be a
00066   // signed integer type.  You may want to modify scalar_type if you
00067   // want to check correctness or performance of single-precision,
00068   // extended-precision, or complex arithmetic kernels.
00069   //
00070 
00071   typedef double scalar_type;
00072   typedef int ordinal_type;
00073   // mfh 28 Jun 2012: DefaultNodeType is usually TPINode, which may
00074   // start threads by default.  We use SerialNode to make absolutely
00075   // sure that this is a comparison of sequential kernels.
00076   //
00077   //typedef Kokkos::DefaultNode::DefaultNodeType node_type;
00078   typedef Kokkos::SerialNode node_type;
00079 
00080   typedef Teuchos::ScalarTraits<double> STM;
00081 
00082   //
00083   // Values of command-line arguments.
00084   //
00085   // CommandLineProcessor only accepts double for floating-point
00086   // values, and int for integer values, so we don't use scalar_type
00087   // or ordinal_type here.
00088 
00089   // If not "", then we assume this is the name of a Matrix Market -
00090   // format sparse matrix file to read.
00091   std::string matrixFilename;
00092   // The given tolerance allows some rounding error for triangular
00093   // solves, given that the test problems we generate should be well
00094   // conditioned on average.
00095   double tol = 1000 * Teuchos::ScalarTraits<double>::eps ();
00096   // Number of rows in the sparse matrices to test.
00097   int numRows = 5;
00098   // Number of columns in the sparse matrices to test.
00099   int numCols = 5;
00100   // Number of benchmark trials; timings are cumulative over all trials.
00101   int numTrials = 100;
00102   // If true, run the benchmark instead of the test.
00103   bool benchmark = false;
00104   // Number of columns in the multivectors to benchmark.
00105   int numVecs = 1;
00106   // Number of threads for the Kokkos Node instance.  -1 means use the
00107   // default behavior.
00108   int numThreads = -1;
00109   // Whether to force AltSparseOps to use first-touch allocation.
00110   bool forceFirstTouch = false;
00111   // Verbosity, including that of Kokkos Node initialization.  (Only
00112   // certain Kokkos Node types support this option.)
00113   bool verbose = false;
00114   // Whether to print copious debugging output.
00115   bool debug = false;
00116   // For AltSparseOps: Whether to use the version with loops unrolled
00117   // over the input and output multivectors.
00118   bool unroll = true;
00119   // For AltSparseOps: Which variant of sparse mat-vec to test; "all"
00120   // means test all implemented variants.
00121   std::string variant ("for-for");
00122 
00123   // This will be set after reading the command-line arguments, so
00124   // that we can, for the particular Kokkos Node type, set things like
00125   // the number of threads to run.
00126   RCP<node_type> node;
00127 
00128   // Set up the extra command-line arguments.
00129   TEUCHOS_STATIC_SETUP()
00130   {
00131     Teuchos::CommandLineProcessor &clp = Teuchos::UnitTestRepository::getCLP ();
00132     clp.addOutputSetupOptions (true);
00133     clp.setOption ("matrixFilename", &matrixFilename, "If not \"\", the name "
00134                    "of a Matrix Market - format file from which to read the "
00135                    "sparse matrix A to benchmark or test.  If provided, we only"
00136                    "benchmark or test sparse mat-vec, not sparse triangular "
00137                    "solve.");
00138     clp.setOption ("numRows", &numRows, "Number of rows in the matrices to "
00139                    "test.  Ignored if a matrix file name is provided.");
00140     clp.setOption ("numCols", &numCols, "Number of columns in the matrices to "
00141                    "test.  Ignored if a matrix file name is provided.  We only "
00142                    "test sparse triangular solve if numRows == numCols.");
00143     clp.setOption ("tol", &tol, "Tolerance for relative error.");
00144     clp.setOption ("benchmark", "test", &benchmark, "Whether to run the "
00145                    "benchmark (if true) or the test (if false).");
00146     clp.setOption ("numTrials", &numTrials, "If running the benchmark: number "
00147                    "of benchmark trials.  Timings are cumulative over all "
00148                    "trials.");
00149     clp.setOption ("numVecs", &numVecs, "Number of columns in the multivectors "
00150                    "to benchmark.");
00151     clp.setOption ("numThreads", &numThreads, "Number of threads for the Kokkos "
00152                    "Node instance to use.  -1 means use the default behavior.");
00153     clp.setOption ("verbose", "quiet", &verbose, "Whether Kokkos Node "
00154                    "initialization should print verbose status output, if the "
00155                    "Node type supports this.");
00156     clp.setOption ("debug", "release", &debug, "Whether to print copious "
00157                    "debugging output.");
00158     clp.setOption ("unroll", "dontUnroll", &unroll, "Whether Kokkos::SeqSparse"
00159                    "Ops should unroll across columns of the multivectors.");
00160     clp.setOption ("variant", &variant, "Which algorithm variant Kokkos::Seq"
00161                    "SparseOps should use for sparse mat-vec.  Valid options "
00162                    "are \"for-for\", \"for-while\", and \"for-if\".  You may "
00163                    "also use \"all\", which tests all possibilities.");
00164     clp.setOption ("forceFirstTouch", "dontForceFirstTouch", &forceFirstTouch,
00165                    "Whether to force AltSparseOps to use first-touch allocation.");
00166 
00167     ParameterList nodeParams;
00168     if (numThreads != -1) {
00169       nodeParams.set ("Num Threads", numThreads);
00170     }
00171     nodeParams.set ("Verbose", verbose);
00172     node = rcp (new node_type (nodeParams));
00173   }
00174 
00175   //
00176   // UNIT TESTS
00177   //
00178 
00184   template<class SparseOpsType>
00185   class Tester {
00186   public:
00201     static void
00202     test (const std::string& sparseOpsTypeName,
00203           const bool implicitUnitDiagTriMultCorrect=false)
00204     {
00205       Teuchos::ParameterList params;
00206       test (sparseOpsTypeName, params, implicitUnitDiagTriMultCorrect);
00207     }
00208 
00222     static void
00223     test (const std::string& sparseOpsTypeName,
00224           Teuchos::ParameterList& params,
00225           const bool implicitUnitDiagTriMultCorrect=false)
00226     {
00227       using Teuchos::FancyOStream;
00228       using Teuchos::getFancyOStream;
00229       using Teuchos::RCP;
00230       using Teuchos::rcpFromRef;
00231 
00232       RCP<FancyOStream> out = getFancyOStream (rcpFromRef (std::cout));
00233       TestSparseOps<SparseOpsType> tester (out, verbose, debug);
00234       if (benchmark) {
00235         std::vector<std::pair<std::string, double> > results;
00236         if (matrixFilename == "") {
00237           tester.benchmarkSparseOps (results, sparseOpsTypeName, node, params,
00238                                      numRows, numCols, numVecs, numTrials);
00239         }
00240         else {
00241           tester.benchmarkSparseMatVecFromFile (results, matrixFilename,
00242                                                 sparseOpsTypeName, node,
00243                                                 params, numVecs, numTrials);
00244         }
00245       }
00246       else {
00247         tester.testSparseOps (node, params, numRows, numCols, numVecs, tol,
00248                               implicitUnitDiagTriMultCorrect);
00249       }
00250     }
00251   };
00252 
00253   // Test sparse matrix-(multi)vector multiply and sparse triangular
00254   // solve, using DefaultHostSparseOps.
00255   TEUCHOS_UNIT_TEST( DefaultSparseOps, TestSparseOps )
00256   {
00257     using Kokkos::DefaultHostSparseOps;
00258     typedef DefaultHostSparseOps<scalar_type, ordinal_type, node_type> sparse_ops_type;
00259 
00260     const bool implicitUnitDiagTriMultCorrect = false;
00261     Tester<sparse_ops_type>::test ("DefaultSparseHostOps",
00262                                    implicitUnitDiagTriMultCorrect);
00263   }
00264 
00265   // Test sparse matrix-(multi)vector multiply and sparse triangular solve.
00266   // This test should work, but we omit it to save time.
00267 #if 0
00268   TEUCHOS_UNIT_TEST( AltSparseOpsDefaultParameters, TestSparseOps )
00269   {
00270     using Kokkos::AltSparseOps;
00271     typedef AltSparseOps<scalar_type, ordinal_type, node_type> sparse_ops_type;
00272     const bool implicitUnitDiagTriMultCorrect = true;
00273     Tester<sparse_ops_type>::test ("AltSparseOps",
00274                                    implicitUnitDiagTriMultCorrect);
00275   }
00276 #endif // 0
00277 
00278   // Test sparse matrix-(multi)vector multiply and sparse triangular solve.
00279   TEUCHOS_UNIT_TEST( AltSparseOpsNonDefaultParameters, TestSparseOps )
00280   {
00281     using Teuchos::ParameterList;
00282     using Teuchos::RCP;
00283     using Kokkos::AltSparseOps;
00284     typedef AltSparseOps<scalar_type, ordinal_type, node_type> sparse_ops_type;
00285     const bool implicitUnitDiagTriMultCorrect = false;
00286 
00287     ParameterList params ("AltSparseOps");
00288     params.set ("Unroll across multivectors", unroll);
00289     params.set ("Force first-touch allocation", forceFirstTouch);
00290     if (variant == "all") {
00291       std::string variant = "for-for";
00292       params.set ("Sparse matrix-vector multiply variant", variant);
00293       Tester<sparse_ops_type>::test ("AltSparseOps (for-for)", params,
00294                                      implicitUnitDiagTriMultCorrect);
00295       variant = "for-while";
00296       params.set ("Sparse matrix-vector multiply variant", variant);
00297       Tester<sparse_ops_type>::test ("AltSparseOps (for-while)", params,
00298                                      implicitUnitDiagTriMultCorrect);
00299       variant = "for-if";
00300       params.set ("Sparse matrix-vector multiply variant", variant);
00301       Tester<sparse_ops_type>::test ("AltSparseOps (for-if)", params,
00302                                      implicitUnitDiagTriMultCorrect);
00303     }
00304     else {
00305       params.set ("Sparse matrix-vector multiply variant", variant);
00306       Tester<sparse_ops_type>::test ("AltSparseOps", params,
00307                                      implicitUnitDiagTriMultCorrect);
00308     }
00309 
00310     if (benchmark) {
00311       // Summarize timing results.  You should only call summarize()
00312       // for all the different SparseOps types you plan to test in
00313       // this executable.
00314       //
00315       // Extra endline makes the summarize() output nicer.  In
00316       // benchmark mode, you should run with only one MPI process (if
00317       // building with MPI at all).  We don't plan to run benchmark
00318       // mode for the check-in or continuous integration tests.
00319       std::cout << "\n";
00320       Teuchos::TimeMonitor::summarize ();
00321     }
00322   }
00323 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends