1 //=================================================================================================
2 /*!
3 //  \file src/main/DVecSVecOuter.cpp
4 //  \brief Source file for the dense vector/sparse vector outer product 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/CompressedMatrix.h>
47 #include <blaze/math/CompressedVector.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/DVecSVecOuter.h>
54 #include <blazemark/blaze/init/CompressedVector.h>
55 #include <blazemark/blaze/init/DynamicVector.h>
56 #include <blazemark/boost/DVecSVecOuter.h>
57 #include <blazemark/system/Boost.h>
58 #include <blazemark/system/Config.h>
59 #include <blazemark/system/Types.h>
60 #include <blazemark/util/Benchmarks.h>
61 #include <blazemark/util/DynamicSparseRun.h>
62 #include <blazemark/util/Parser.h>
63 
64 #ifdef BLAZE_USE_HPX_THREADS
65 #  include <hpx/hpx_main.hpp>
66 #endif
67 
68 
69 //*************************************************************************************************
70 // Using declarations
71 //*************************************************************************************************
72 
73 using blazemark::Benchmarks;
74 using blazemark::DynamicSparseRun;
75 using blazemark::Parser;
76 
77 
78 
79 
80 //=================================================================================================
81 //
82 //  TYPE DEFINITIONS
83 //
84 //=================================================================================================
85 
86 //*************************************************************************************************
87 /*!\brief Type of a benchmark run.
88 //
89 // This type definition specifies the type of a single benchmark run for the dense vector/sparse
90 // vector outer product benchmark.
91 */
92 using Run = DynamicSparseRun;
93 //*************************************************************************************************
94 
95 
96 
97 
98 //=================================================================================================
99 //
100 //  UTILITY FUNCTIONS
101 //
102 //=================================================================================================
103 
104 //*************************************************************************************************
105 /*!\brief Estimating the necessary number of steps for each benchmark.
106 //
107 // \param run The parameters for the benchmark run.
108 // \return void
109 //
110 // This function estimates the necessary number of steps for the given benchmark based on the
111 // performance of the Blaze library.
112 */
estimateSteps(Run & run)113 void estimateSteps( Run& run )
114 {
115    using blazemark::element_t;
116    using blaze::rowVector;
117    using blaze::columnVector;
118    using blaze::rowMajor;
119 
120    ::blaze::setSeed( ::blazemark::seed );
121 
122    const size_t N( run.getSize() );
123    const size_t F( run.getNonZeros() );
124 
125    blaze::DynamicVector<element_t,columnVector> a( N );
126    blaze::CompressedVector<element_t,rowVector> b( N, F );
127    blaze::CompressedMatrix<element_t,rowMajor> A( N, N );
128    blaze::timing::WcTimer timer;
129    double wct( 0.0 );
130    size_t steps( 1UL );
131 
132    blazemark::blaze::init( a );
133    blazemark::blaze::init( b, F );
134 
135    while( true ) {
136       timer.start();
137       for( size_t i=0UL; i<steps; ++i ) {
138          A = a * b;
139       }
140       timer.end();
141       wct = timer.last();
142       if( wct >= 0.2 ) break;
143       steps *= 2UL;
144    }
145 
146    if( A.rows() != N )
147       std::cerr << " Line " << __LINE__ << ": ERROR detected!!!\n";
148 
149    const size_t estimatedSteps( ( blazemark::runtime * steps ) / timer.last() );
150    run.setSteps( blaze::max( 1UL, estimatedSteps ) );
151 }
152 //*************************************************************************************************
153 
154 
155 //*************************************************************************************************
156 /*!\brief Estimating the necessary number of floating point operations.
157 //
158 // \param run The parameters for the benchmark run.
159 // \return void
160 //
161 // This function estimates the number of floating point operations required for a single
162 // computation of the (composite) arithmetic operation.
163 */
estimateFlops(Run & run)164 void estimateFlops( Run& run )
165 {
166    const size_t N( run.getSize()     );
167    const size_t F( run.getNonZeros() );
168 
169    run.setFlops( N*F );
170 }
171 //*************************************************************************************************
172 
173 
174 
175 
176 //=================================================================================================
177 //
178 //  BENCHMARK FUNCTIONS
179 //
180 //=================================================================================================
181 
182 //*************************************************************************************************
183 /*!\brief Dense vector/sparse vector outer product benchmark function.
184 //
185 // \param runs The specified benchmark runs.
186 // \param benchmarks The selection of benchmarks.
187 // \return void
188 */
dvecsvecouter(std::vector<Run> & runs,Benchmarks benchmarks)189 void dvecsvecouter( std::vector<Run>& runs, Benchmarks benchmarks )
190 {
191    std::cout << std::left;
192 
193    std::sort( runs.begin(), runs.end() );
194 
195    size_t slowSize( blaze::inf );
196    for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run )
197    {
198       estimateFlops( *run );
199 
200       if( run->getSteps() == 0UL ) {
201          if( run->getSize() < slowSize ) {
202             estimateSteps( *run );
203             if( run->getSteps() == 1UL )
204                slowSize = run->getSize();
205          }
206          else run->setSteps( 1UL );
207       }
208    }
209 
210    if( benchmarks.runBlaze ) {
211       std::vector<Run>::iterator run=runs.begin();
212       while( run != runs.end() ) {
213          const float fill( run->getFillingDegree() );
214          std::cout << "   Blaze (" << fill << "% filled) [MFlop/s]:\n";
215          for( ; run!=runs.end(); ++run ) {
216             if( run->getFillingDegree() != fill ) break;
217             const size_t N    ( run->getSize()     );
218             const size_t F    ( run->getNonZeros() );
219             const size_t steps( run->getSteps()    );
220             run->setBlazeResult( blazemark::blaze::dvecsvecouter( N, F, steps ) );
221             const double mflops( run->getFlops() * steps / run->getBlazeResult() / 1E6 );
222             std::cout << "     " << std::setw(12) << N << mflops << std::endl;
223          }
224       }
225    }
226 
227 #if BLAZEMARK_BOOST_MODE
228    if( benchmarks.runBoost ) {
229       std::vector<Run>::iterator run=runs.begin();
230       while( run != runs.end() ) {
231          const float fill( run->getFillingDegree() );
232          std::cout << "   Boost uBLAS (" << fill << "% filled) [MFlop/s]:\n";
233          for( ; run!=runs.end(); ++run ) {
234             if( run->getFillingDegree() != fill ) break;
235             const size_t N    ( run->getSize()     );
236             const size_t F    ( run->getNonZeros() );
237             const size_t steps( run->getSteps()    );
238             run->setBoostResult( blazemark::boost::dvecsvecouter( N, F, steps ) );
239             const double mflops( run->getFlops() * steps / run->getBoostResult() / 1E6 );
240             std::cout << "     " << std::setw(12) << N << mflops << std::endl;
241          }
242       }
243    }
244 #endif
245 
246    for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run ) {
247       std::cout << *run;
248    }
249 }
250 //*************************************************************************************************
251 
252 
253 
254 
255 //=================================================================================================
256 //
257 //  MAIN FUNCTION
258 //
259 //=================================================================================================
260 
261 //*************************************************************************************************
262 /*!\brief The main function for the dense vector/sparse vector outer product benchmark.
263 //
264 // \param argc The total number of command line arguments.
265 // \param argv The array of command line arguments.
266 // \return void
267 */
main(int argc,char ** argv)268 int main( int argc, char** argv )
269 {
270    std::cout << "\n Dense Vector/Sparse Vector Outer Product:\n";
271 
272    Benchmarks benchmarks;
273 
274    try {
275       parseCommandLineArguments( argc, argv, benchmarks );
276    }
277    catch( std::exception& ex ) {
278       std::cerr << "   " << ex.what() << "\n";
279       return EXIT_FAILURE;
280    }
281 
282    const std::string installPath( INSTALL_PATH );
283    const std::string parameterFile( installPath + "/params/dvecsvecouter.prm" );
284    Parser<Run> parser;
285    std::vector<Run> runs;
286 
287    try {
288       parser.parse( parameterFile.c_str(), runs );
289    }
290    catch( std::exception& ex ) {
291       std::cerr << "   Error during parameter extraction: " << ex.what() << "\n";
292       return EXIT_FAILURE;
293    }
294 
295    try {
296       dvecsvecouter( runs, benchmarks );
297    }
298    catch( std::exception& ex ) {
299       std::cerr << "   Error during benchmark execution: " << ex.what() << "\n";
300       return EXIT_FAILURE;
301    }
302 
303    return EXIT_SUCCESS;
304 }
305 //*************************************************************************************************
306