1 //=================================================================================================
2 /*!
3 //  \file src/main/Complex5.cpp
4 //  \brief Source file for the benchmark for the complex expression D = ( A * B ) + C
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/DynamicMatrix.h>
47 #include <blaze/math/Infinity.h>
48 #include <blaze/util/algorithms/Max.h>
49 #include <blaze/util/Random.h>
50 #include <blaze/util/Timing.h>
51 #include <blazemark/armadillo/Complex5.h>
52 #include <blazemark/blaze/Complex5.h>
53 #include <blazemark/blaze/init/DynamicMatrix.h>
54 #include <blazemark/blitz/Complex5.h>
55 #include <blazemark/boost/Complex5.h>
56 #include <blazemark/classic/Complex5.h>
57 #include <blazemark/eigen/Complex5.h>
58 #include <blazemark/flens/Complex5.h>
59 #include <blazemark/gmm/Complex5.h>
60 #include <blazemark/mtl/Complex5.h>
61 #include <blazemark/system/Armadillo.h>
62 #include <blazemark/system/Blitz.h>
63 #include <blazemark/system/Boost.h>
64 #include <blazemark/system/Config.h>
65 #include <blazemark/system/Eigen.h>
66 #include <blazemark/system/FLENS.h>
67 #include <blazemark/system/GMM.h>
68 #include <blazemark/system/MTL.h>
69 #include <blazemark/system/Types.h>
70 #include <blazemark/util/Benchmarks.h>
71 #include <blazemark/util/DynamicDenseRun.h>
72 #include <blazemark/util/Parser.h>
73 
74 #ifdef BLAZE_USE_HPX_THREADS
75 #  include <hpx/hpx_main.hpp>
76 #endif
77 
78 
79 //*************************************************************************************************
80 // Using declarations
81 //*************************************************************************************************
82 
83 using blazemark::Benchmarks;
84 using blazemark::DynamicDenseRun;
85 using blazemark::Parser;
86 
87 
88 
89 
90 //=================================================================================================
91 //
92 //  TYPE DEFINITIONS
93 //
94 //=================================================================================================
95 
96 //*************************************************************************************************
97 /*!\brief Type of a benchmark run.
98 //
99 // This type definition specifies the type of a single benchmark run for the complex
100 // expression D = ( A * B ) + C.
101 */
102 using Run = DynamicDenseRun;
103 //*************************************************************************************************
104 
105 
106 
107 
108 //=================================================================================================
109 //
110 //  UTILITY FUNCTIONS
111 //
112 //=================================================================================================
113 
114 //*************************************************************************************************
115 /*!\brief Estimating the necessary number of steps for each benchmark.
116 //
117 // \param run The parameters for the benchmark run.
118 // \return void
119 //
120 // This function estimates the necessary number of steps for the given benchmark based on the
121 // performance of the Blaze library.
122 */
estimateSteps(Run & run)123 void estimateSteps( Run& run )
124 {
125    using blazemark::element_t;
126    using blaze::columnMajor;
127 
128    ::blaze::setSeed( ::blazemark::seed );
129 
130    const size_t N( run.getSize() );
131 
132    blaze::DynamicMatrix<element_t,columnMajor> A( N, N ), B( N, N ), C( N, N ), D( N, N );
133    blaze::timing::WcTimer timer;
134    double wct( 0.0 );
135    size_t steps( 1UL );
136 
137    blazemark::blaze::init( A );
138    blazemark::blaze::init( B );
139    blazemark::blaze::init( C );
140 
141    while( true ) {
142       timer.start();
143       for( size_t i=0UL; i<steps; ++i ) {
144          D = ( A * B ) + C;
145       }
146       timer.end();
147       wct = timer.last();
148       if( wct >= 0.2 ) break;
149       steps *= 2UL;
150    }
151 
152    if( D.rows() != N )
153       std::cerr << " Line " << __LINE__ << ": ERROR detected!!!\n";
154 
155    const size_t estimatedSteps( ( blazemark::runtime * steps ) / timer.last() );
156    run.setSteps( blaze::max( 1UL, estimatedSteps ) );
157 }
158 //*************************************************************************************************
159 
160 
161 //*************************************************************************************************
162 /*!\brief Estimating the necessary number of floating point operations.
163 //
164 // \param run The parameters for the benchmark run.
165 // \return void
166 //
167 // This function estimates the number of floating point operations required for a single
168 // computation of the (composite) arithmetic operation.
169 */
estimateFlops(Run & run)170 void estimateFlops( Run& run )
171 {
172    const size_t N( run.getSize() );
173 
174    run.setFlops( 2UL*N*N*N );
175 }
176 //*************************************************************************************************
177 
178 
179 
180 
181 //=================================================================================================
182 //
183 //  BENCHMARK FUNCTIONS
184 //
185 //=================================================================================================
186 
187 //*************************************************************************************************
188 /*!\brief Complex expression D = ( A * B ) + C benchmark function.
189 //
190 // \param runs The specified benchmark runs.
191 // \param benchmarks The selection of benchmarks.
192 // \return void
193 */
complex5(std::vector<Run> & runs,Benchmarks benchmarks)194 void complex5( std::vector<Run>& runs, Benchmarks benchmarks )
195 {
196    std::cout << std::left;
197 
198    std::sort( runs.begin(), runs.end() );
199 
200    size_t slowSize( blaze::inf );
201    for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run )
202    {
203       estimateFlops( *run );
204 
205       if( run->getSteps() == 0UL ) {
206          if( run->getSize() < slowSize ) {
207             estimateSteps( *run );
208             if( run->getSteps() == 1UL )
209                slowSize = run->getSize();
210          }
211          else run->setSteps( 1UL );
212       }
213    }
214 
215    if( benchmarks.runClassic ) {
216       std::cout << "   Classic operator overloading [MFlop/s]:\n";
217       for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run ) {
218          const size_t N    ( run->getSize()  );
219          const size_t steps( run->getSteps() );
220          run->setClassicResult( blazemark::classic::complex5( N, steps ) );
221          const double mflops( run->getFlops() * steps / run->getClassicResult() / 1E6 );
222          std::cout << "     " << std::setw(12) << N << mflops << std::endl;
223       }
224    }
225 
226    if( benchmarks.runBlaze ) {
227       std::cout << "   Blaze [MFlop/s]:\n";
228       for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run ) {
229          const size_t N    ( run->getSize()  );
230          const size_t steps( run->getSteps() );
231          run->setBlazeResult( blazemark::blaze::complex5( N, steps ) );
232          const double mflops( run->getFlops() * steps / run->getBlazeResult() / 1E6 );
233          std::cout << "     " << std::setw(12) << N << mflops << std::endl;
234       }
235    }
236 
237 #if BLAZEMARK_BOOST_MODE
238    if( benchmarks.runBoost ) {
239       std::cout << "   Boost uBLAS [MFlop/s]:\n";
240       for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run ) {
241          const size_t N    ( run->getSize()  );
242          const size_t steps( run->getSteps() );
243          run->setBoostResult( blazemark::boost::complex5( N, steps ) );
244          const double mflops( run->getFlops() * steps / run->getBoostResult() / 1E6 );
245          std::cout << "     " << std::setw(12) << N << mflops << std::endl;
246       }
247    }
248 #endif
249 
250 #if BLAZEMARK_BLITZ_MODE
251    if( benchmarks.runBlitz ) {
252       std::cout << "   Blitz++ [MFlop/s]:\n";
253       for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run ) {
254          const size_t N    ( run->getSize()  );
255          const size_t steps( run->getSteps() );
256          run->setBlitzResult( blazemark::blitz::complex5( N, steps ) );
257          const double mflops( run->getFlops() * steps / run->getBlitzResult() / 1E6 );
258          std::cout << "     " << std::setw(12) << N << mflops << std::endl;
259       }
260    }
261 #endif
262 
263 #if BLAZEMARK_GMM_MODE
264    if( benchmarks.runGMM ) {
265       std::cout << "   GMM++ [MFlop/s]:\n";
266       for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run ) {
267          const size_t N    ( run->getSize()  );
268          const size_t steps( run->getSteps() );
269          run->setGMMResult( blazemark::gmm::complex5( N, steps ) );
270          const double mflops( run->getFlops() * steps / run->getGMMResult() / 1E6 );
271          std::cout << "     " << std::setw(12) << N << mflops << std::endl;
272       }
273    }
274 #endif
275 
276 #if BLAZEMARK_ARMADILLO_MODE
277    if( benchmarks.runArmadillo ) {
278       std::cout << "   Armadillo [MFlop/s]:\n";
279       for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run ) {
280          const size_t N    ( run->getSize()  );
281          const size_t steps( run->getSteps() );
282          run->setArmadilloResult( blazemark::armadillo::complex5( N, steps ) );
283          const double mflops( run->getFlops() * steps / run->getArmadilloResult() / 1E6 );
284          std::cout << "     " << std::setw(12) << N << mflops << std::endl;
285       }
286    }
287 #endif
288 
289 #if BLAZEMARK_FLENS_MODE
290    if( benchmarks.runFLENS ) {
291       std::cout << "   FLENS [MFlop/s]:\n";
292       for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run ) {
293          const size_t N    ( run->getSize()  );
294          const size_t steps( run->getSteps() );
295          run->setFLENSResult( blazemark::flens::complex5( N, steps ) );
296          const double mflops( run->getFlops() * steps / run->getFLENSResult() / 1E6 );
297          std::cout << "     " << std::setw(12) << N << mflops << std::endl;
298       }
299    }
300 #endif
301 
302 #if BLAZEMARK_MTL_MODE
303    if( benchmarks.runMTL ) {
304       std::cout << "   MTL [MFlop/s]:\n";
305       for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run ) {
306          const size_t N    ( run->getSize()  );
307          const size_t steps( run->getSteps() );
308          run->setMTLResult( blazemark::mtl::complex5( N, steps ) );
309          const double mflops( run->getFlops() * steps / run->getMTLResult() / 1E6 );
310          std::cout << "     " << std::setw(12) << N << mflops << std::endl;
311       }
312    }
313 #endif
314 
315 #if BLAZEMARK_EIGEN_MODE
316    if( benchmarks.runEigen ) {
317       std::cout << "   Eigen [MFlop/s]:\n";
318       for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run ) {
319          const size_t N    ( run->getSize()  );
320          const size_t steps( run->getSteps() );
321          run->setEigenResult( blazemark::eigen::complex5( N, steps ) );
322          const double mflops( run->getFlops() * steps / run->getEigenResult() / 1E6 );
323          std::cout << "     " << std::setw(12) << N << mflops << std::endl;
324       }
325    }
326 #endif
327 
328    for( std::vector<Run>::iterator run=runs.begin(); run!=runs.end(); ++run ) {
329       std::cout << *run;
330    }
331 }
332 //*************************************************************************************************
333 
334 
335 
336 
337 //=================================================================================================
338 //
339 //  MAIN FUNCTION
340 //
341 //=================================================================================================
342 
343 //*************************************************************************************************
344 /*!\brief The main function for the benchmark for the complex expression D = ( A * B ) + C.
345 //
346 // \param argc The total number of command line arguments.
347 // \param argv The array of command line arguments.
348 // \return void
349 */
main(int argc,char ** argv)350 int main( int argc, char** argv )
351 {
352    std::cout << "\n Complex Expression: D = ( A * B ) + C:\n";
353 
354    Benchmarks benchmarks;
355 
356    try {
357       parseCommandLineArguments( argc, argv, benchmarks );
358    }
359    catch( std::exception& ex ) {
360       std::cerr << "   " << ex.what() << "\n";
361       return EXIT_FAILURE;
362    }
363 
364    const std::string installPath( INSTALL_PATH );
365    const std::string parameterFile( installPath + "/params/complex5.prm" );
366    Parser<Run> parser;
367    std::vector<Run> runs;
368 
369    try {
370       parser.parse( parameterFile.c_str(), runs );
371    }
372    catch( std::exception& ex ) {
373       std::cerr << "   Error during parameter extraction: " << ex.what() << "\n";
374       return EXIT_FAILURE;
375    }
376 
377    try {
378       complex5( runs, benchmarks );
379    }
380    catch( std::exception& ex ) {
381       std::cerr << "   Error during benchmark execution: " << ex.what() << "\n";
382       return EXIT_FAILURE;
383    }
384 
385    return EXIT_SUCCESS;
386 }
387 //*************************************************************************************************
388