1 //=================================================================================================
2 /*!
3 //  \file src/main/TDMatSVecMult.cpp
4 //  \brief Source file for the transpose dense matrix/sparse vector multiplication benchmark
5 //
6 //  Copyright (C) 2012-2020 Klaus Iglberger - All Rights Reserved
7 //
8 //  This file is part of the Blaze library. You can redistribute it and/or modify it under
9 //  the terms of the New (Revised) BSD License. Redistribution and use in source and binary
10 //  forms, with or without modification, are permitted provided that the following conditions
11 //  are met:
12 //
13 //  1. Redistributions of source code must retain the above copyright notice, this list of
14 //     conditions and the following disclaimer.
15 //  2. Redistributions in binary form must reproduce the above copyright notice, this list
16 //     of conditions and the following disclaimer in the documentation and/or other materials
17 //     provided with the distribution.
18 //  3. Neither the names of the Blaze development group nor the names of its contributors
19 //     may be used to endorse or promote products derived from this software without specific
20 //     prior written permission.
21 //
22 //  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
23 //  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 //  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25 //  SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 //  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27 //  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 //  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 //  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 //  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 //  DAMAGE.
32 */
33 //=================================================================================================
34 
35 
36 //*************************************************************************************************
37 // Includes
38 //*************************************************************************************************
39 
40 #include <algorithm>
41 #include <cstdlib>
42 #include <iostream>
43 #include <stdexcept>
44 #include <string>
45 #include <vector>
46 #include <blaze/math/CompressedVector.h>
47 #include <blaze/math/DynamicMatrix.h>
48 #include <blaze/math/DynamicVector.h>
49 #include <blaze/math/Infinity.h>
50 #include <blaze/util/algorithms/Max.h>
51 #include <blaze/util/Random.h>
52 #include <blaze/util/Timing.h>
53 #include <blazemark/blaze/init/CompressedVector.h>
54 #include <blazemark/blaze/init/DynamicMatrix.h>
55 #include <blazemark/blaze/TDMatSVecMult.h>
56 #include <blazemark/boost/TDMatSVecMult.h>
57 #include <blazemark/gmm/TDMatSVecMult.h>
58 #include <blazemark/system/Boost.h>
59 #include <blazemark/system/Config.h>
60 #include <blazemark/system/GMM.h>
61 #include <blazemark/system/Types.h>
62 #include <blazemark/util/Benchmarks.h>
63 #include <blazemark/util/DynamicSparseRun.h>
64 #include <blazemark/util/Parser.h>
65 
66 #ifdef BLAZE_USE_HPX_THREADS
67 #  include <hpx/hpx_main.hpp>
68 #endif
69 
70 
71 //*************************************************************************************************
72 // Using declarations
73 //*************************************************************************************************
74 
75 using blazemark::Benchmarks;
76 using blazemark::DynamicSparseRun;
77 using blazemark::Parser;
78 
79 
80 
81 
82 //=================================================================================================
83 //
84 //  TYPE DEFINITIONS
85 //
86 //=================================================================================================
87 
88 //*************************************************************************************************
89 /*!\brief Type of a benchmark run.
90 //
91 // This type definition specifies the type of a single benchmark run for the transpose dense
92 // matrix/sparse vector multiplication benchmark.
93 */
94 using Run = DynamicSparseRun;
95 //*************************************************************************************************
96 
97 
98 
99 
100 //=================================================================================================
101 //
102 //  UTILITY FUNCTIONS
103 //
104 //=================================================================================================
105 
106 //*************************************************************************************************
107 /*!\brief Estimating the necessary number of steps for each benchmark.
108 //
109 // \param run The parameters for the benchmark run.
110 // \return void
111 //
112 // This function estimates the necessary number of steps for the given benchmark based on the
113 // performance of the Blaze library.
114 */
estimateSteps(Run & run)115 void estimateSteps( Run& run )
116 {
117    using blazemark::element_t;
118    using blaze::columnVector;
119    using blaze::columnMajor;
120 
121    ::blaze::setSeed( ::blazemark::seed );
122 
123    const size_t N( run.getSize() );
124    const size_t F( run.getNonZeros() );
125 
126    blaze::DynamicMatrix<element_t,columnMajor> A( N, N );
127    blaze::CompressedVector<element_t,columnVector> a( N, F );
128    blaze::DynamicVector<element_t,columnVector> b( N );
129    blaze::timing::WcTimer timer;
130    double wct( 0.0 );
131    size_t steps( 1UL );
132 
133    blazemark::blaze::init( A );
134    blazemark::blaze::init( a, F );
135 
136    while( true ) {
137       timer.start();
138       for( size_t i=0UL; i<steps; ++i ) {
139          b = A * a;
140       }
141       timer.end();
142       wct = timer.last();
143       if( wct >= 0.2 ) break;
144       steps *= 2UL;
145    }
146 
147    if( b.size() != N )
148       std::cerr << " Line " << __LINE__ << ": ERROR detected!!!\n";
149 
150    const size_t estimatedSteps( ( blazemark::runtime * steps ) / timer.last() );
151    run.setSteps( blaze::max( 1UL, estimatedSteps ) );
152 }
153 //*************************************************************************************************
154 
155 
156 //*************************************************************************************************
157 /*!\brief Estimating the necessary number of floating point operations.
158 //
159 // \param run The parameters for the benchmark run.
160 // \return void
161 //
162 // This function estimates the number of floating point operations required for a single
163 // computation of the (composite) arithmetic operation.
164 */
estimateFlops(Run & run)165 void estimateFlops( Run& run )
166 {
167    const size_t N( run.getSize()     );
168    const size_t F( run.getNonZeros() );
169 
170    run.setFlops( 2U*N*F - N );
171 }
172 //*************************************************************************************************
173 
174 
175 
176 
177 //=================================================================================================
178 //
179 //  BENCHMARK FUNCTIONS
180 //
181 //=================================================================================================
182 
183 //*************************************************************************************************
184 /*!\brief Transpose dense matrix/sparse vector multiplication benchmark function.
185 //
186 // \param runs The specified benchmark runs.
187 // \param benchmarks The selection of benchmarks.
188 // \return void
189 */
tdmatsvecmult(std::vector<Run> & runs,Benchmarks benchmarks)190 void tdmatsvecmult( std::vector<Run>& runs, Benchmarks benchmarks )
191 {
192    std::cout << std::left;
193 
194    std::sort( runs.begin(), runs.end() );
195 
196    size_t slowSize( blaze::inf );
197    for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run )
198    {
199       estimateFlops( *run );
200 
201       if( run->getSteps() == 0UL ) {
202          if( run->getSize() < slowSize ) {
203             estimateSteps( *run );
204             if( run->getSteps() == 1UL )
205                slowSize = run->getSize();
206          }
207          else run->setSteps( 1UL );
208       }
209    }
210 
211    if( benchmarks.runBlaze ) {
212       std::vector<Run>::iterator run=runs.begin();
213       while( run != runs.end() ) {
214          const float fill( run->getFillingDegree() );
215          std::cout << "   Blaze (" << fill << "% filled) [MFlop/s]:\n";
216          for( ; run!=runs.end(); ++run ) {
217             if( run->getFillingDegree() != fill ) break;
218             const size_t N    ( run->getSize()     );
219             const size_t F    ( run->getNonZeros() );
220             const size_t steps( run->getSteps()    );
221             run->setBlazeResult( blazemark::blaze::tdmatsvecmult( N, F, steps ) );
222             const double mflops( run->getFlops() * steps / run->getBlazeResult() / 1E6 );
223             std::cout << "     " << std::setw(12) << N << mflops << std::endl;
224          }
225       }
226    }
227 
228 #if BLAZEMARK_BOOST_MODE
229    if( benchmarks.runBoost ) {
230       std::vector<Run>::iterator run=runs.begin();
231       while( run != runs.end() ) {
232          const float fill( run->getFillingDegree() );
233          std::cout << "   Boost uBLAS (" << fill << "% filled) [MFlop/s]:\n";
234          for( ; run!=runs.end(); ++run ) {
235             if( run->getFillingDegree() != fill ) break;
236             const size_t N    ( run->getSize()     );
237             const size_t F    ( run->getNonZeros() );
238             const size_t steps( run->getSteps()    );
239             run->setBoostResult( blazemark::boost::tdmatsvecmult( N, F, steps ) );
240             const double mflops( run->getFlops() * steps / run->getBoostResult() / 1E6 );
241             std::cout << "     " << std::setw(12) << N << mflops << std::endl;
242          }
243       }
244    }
245 #endif
246 
247 #if BLAZEMARK_GMM_MODE
248    if( benchmarks.runGMM ) {
249       std::vector<Run>::iterator run=runs.begin();
250       while( run != runs.end() ) {
251          const float fill( run->getFillingDegree() );
252          std::cout << "   GMM++ (" << fill << "% filled) [MFlop/s]:\n";
253          for( ; run!=runs.end(); ++run ) {
254             if( run->getFillingDegree() != fill ) break;
255             const size_t N    ( run->getSize()     );
256             const size_t F    ( run->getNonZeros() );
257             const size_t steps( run->getSteps()    );
258             run->setGMMResult( blazemark::gmm::tdmatsvecmult( N, F, steps ) );
259             const double mflops( run->getFlops() * steps / run->getGMMResult() / 1E6 );
260             std::cout << "     " << std::setw(12) << N << mflops << std::endl;
261          }
262       }
263    }
264 #endif
265 
266    for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run ) {
267       std::cout << *run;
268    }
269 }
270 //*************************************************************************************************
271 
272 
273 
274 
275 //=================================================================================================
276 //
277 //  MAIN FUNCTION
278 //
279 //=================================================================================================
280 
281 //*************************************************************************************************
282 /*!\brief The main function for the transpose dense matrix/sparse vector multiplication benchmark.
283 //
284 // \param argc The total number of command line arguments.
285 // \param argv The array of command line arguments.
286 // \return void
287 */
main(int argc,char ** argv)288 int main( int argc, char** argv )
289 {
290    std::cout << "\n Transpose Dense Matrix/Sparse Vector Multiplication:\n";
291 
292    Benchmarks benchmarks;
293 
294    try {
295       parseCommandLineArguments( argc, argv, benchmarks );
296    }
297    catch( std::exception& ex ) {
298       std::cerr << "   " << ex.what() << "\n";
299       return EXIT_FAILURE;
300    }
301 
302    const std::string installPath( INSTALL_PATH );
303    const std::string parameterFile( installPath + "/params/tdmatsvecmult.prm" );
304    Parser<Run> parser;
305    std::vector<Run> runs;
306 
307    try {
308       parser.parse( parameterFile.c_str(), runs );
309    }
310    catch( std::exception& ex ) {
311       std::cerr << "   Error during parameter extraction: " << ex.what() << "\n";
312       return EXIT_FAILURE;
313    }
314 
315    try {
316       tdmatsvecmult( runs, benchmarks );
317    }
318    catch( std::exception& ex ) {
319       std::cerr << "   Error during benchmark execution: " << ex.what() << "\n";
320       return EXIT_FAILURE;
321    }
322 
323    return EXIT_SUCCESS;
324 }
325 //*************************************************************************************************
326