1 #include <iostream>
2 #include <fstream>
3 #include <string>
4 #include <stdlib.h>
5 #include <iomanip>
6
7 #include <boost/numeric/ublas/vector.hpp>
8 #include <boost/numeric/ublas/vector_proxy.hpp>
9 #include <boost/numeric/ublas/matrix.hpp>
10 #include <boost/numeric/ublas/matrix_proxy.hpp>
11 #include <boost/numeric/ublas/io.hpp>
12 #include <boost/timer.hpp>
13
14 namespace numerics = boost::numeric::ublas ;
15
16 template < typename T >
eq(const T & a,const T & b,double abstol)17 bool eq (const T& a, const T& b, double abstol)
18 {
19 return std::abs(a-b)<abstol;
20 }
21
22 template < typename T >
23 struct is_equal
24 {
is_equalis_equal25 is_equal (double tol) : abstol(tol) {}
operator ()is_equal26 bool operator()(const T& a, const T&b) { return eq(a,b,abstol);}
27 double abstol;
28 };
29
30 template < typename T >
random_initialise(T & v)31 void random_initialise(T& v)
32 { v = 10.0 * rand()/(RAND_MAX+1.0) ; }
33
34 template < typename T >
random_initialise_vector(numerics::vector<T> & v)35 void random_initialise_vector(numerics::vector< T >& v)
36 {
37 size_t size = v.size();
38 for(size_t i = 0 ; i < size ; ++i ) random_initialise( v[i] ) ;
39 }
40
41 template < typename T, typename Orientation >
random_initialise_matrix(numerics::matrix<T,Orientation> & m)42 void random_initialise_matrix(numerics::matrix< T, Orientation >& m)
43 {
44 size_t size1 = m.size1();
45 size_t size2 = m.size2();
46 for(size_t i = 0 ; i < size1 ; ++i )
47 for(size_t j = 0 ; j < size2 ; ++j )
48 random_initialise( m(i,j) ) ;
49 }
50
51 template < typename T >
52 struct assign_multiplier
53 {
operator ()assign_multiplier54 T operator()() const
55 { return 1.0000002 ; } // otherwise the accumulated result of the range will result in 0.0 or over/under-flow
56 };
57
58 template < typename T >
59 struct assign_multiplier< std::complex< T > >
60 {
operator ()assign_multiplier61 std::complex< T > operator()() const
62 { return std::complex< T >( cos(0.5),sin(0.5) ) + ( assign_multiplier< T >().operator() - 1.0 ) ; }
63 };
64
65 template<class T>
flops(int multiplies,int plus,int runs,double elapsed)66 double flops(int multiplies, int plus, int runs, double elapsed)
67 { return ( multiplies * boost::numeric::ublas::type_traits<T>::multiplies_complexity + plus * boost::numeric::ublas::type_traits<T>::plus_complexity ) * runs / (1024 * 1024 * elapsed) ; }
68
69 template<class T>
70 struct peak_c_plus {
71 typedef T value_type;
72
operator ()peak_c_plus73 void operator () (int runs) const {
74 try {
75 static T s (0);
76 boost::timer t;
77 for (int i = 0; i < runs; ++ i) {
78 s += T (0);
79 }
80 std::cerr << flops<value_type>(0, 1, runs, t.elapsed ()) << " Mflops\n";
81 }
82 catch (std::exception &e) {
83 std::cerr << e.what () << std::endl;
84 }
85 catch (...) {
86 std::cerr << "unknown exception" << std::endl;
87 }
88 }
89 };
90
91 template<class T>
92 struct peak_c_multiplies {
93 typedef T value_type;
94
operator ()peak_c_multiplies95 void operator () (int runs) const {
96 try {
97 static T s (1);
98 boost::timer t;
99 for (int i = 0; i < runs; ++ i) {
100 s *= T (1);
101 }
102 std::cerr << flops<value_type>(0, 1, runs, t.elapsed ()) << " Mflops\n";
103 }
104 catch (std::exception &e) {
105 std::cerr << e.what () << std::endl;
106 }
107 catch (...) {
108 std::cerr << "unknown exception" << std::endl;
109 }
110 }
111 };
112
113 template<class T>
114 struct peak
115 {
operator ()peak116 void operator () (int runs)
117 {
118 std::cerr << "plus :";
119 peak_c_plus<T> () (runs);
120 std::cerr << "multiplies :";
121 peak_c_multiplies<T> () (runs);
122 }
123 };
124
125 template < typename value_type >
check(value_type a,value_type b)126 void check(value_type a, value_type b)
127 {
128 if ( ! eq< value_type >( a, b, 1e-5 ) ) {
129 std::cerr << "\n\nregression test failure : results are not identical" << std::endl;
130 std::cerr << a << " != " << b << std::endl;
131 exit( 1 );
132 }
133 }
134
135 template < typename Iterator0, typename Iterator1 >
check(Iterator0 begin0,Iterator0 end0,Iterator1 begin1)136 void check(Iterator0 begin0, Iterator0 end0, Iterator1 begin1)
137 {
138 Iterator0 it0 = begin0 ;
139 Iterator1 end1 = begin1 + std::distance(begin0,end0);
140 for(bool fail = false ; it0 != end0 || fail ; ++it0 ) ; // fail = ! ( *it0 < std::numeric_limits< typename Iterator0::value_type >::max() );
141
142 Iterator1 it1 = begin1 ;
143 for(bool fail = false ; it1 != end1 || fail ; ++it1 ) ; // fail = ! ( *it1 < std::numeric_limits< typename Iterator0::value_type >::max() ) ;
144
145 if ( it0 != end0 || it1 != end1 ) {
146 std::cerr << "\n\nregression test failure : results overflowed" << std::endl;
147 std::copy( begin0, end0, std::ostream_iterator< typename Iterator0::value_type >( std::cerr, " " ) ); std::cerr << std::endl;
148 std::copy( begin1, end1, std::ostream_iterator< typename Iterator1::value_type >( std::cerr, " " ) ); std::cerr << std::endl;
149 exit(1);
150 }
151
152 if ( ! std::equal( begin0, end0, begin1, is_equal< typename Iterator0::value_type >( std::abs( *begin0 ) * 1e-5 ) ) ) {
153 std::cerr << "\n\nregression test failure : results are not identical" << std::endl;
154 std::cerr << std::setprecision( 20 ) ;
155 std::copy( begin0, end0, std::ostream_iterator< typename Iterator0::value_type >( std::cerr, " " ) ); std::cerr << std::endl;
156 std::copy( begin1, end1, std::ostream_iterator< typename Iterator1::value_type >( std::cerr, " " ) ); std::cerr << std::endl;
157 exit( 1 );
158 }
159 }
160
161 template < typename value_type >
check(numerics::matrix<value_type> & a,numerics::matrix<value_type> & b)162 void check(numerics::matrix< value_type > &a, numerics::matrix< value_type > &b)
163 {
164 bool ret = true ;
165 size_t num_rows = a.size1() ;
166 size_t num_cols = a.size2() ;
167
168 for(size_t i = 0 ; i < num_rows && ret ; ++i )
169 for(size_t j = 0 ; j < num_cols && ret ; ++j )
170 ret = eq< value_type >( a(i,j), b(i,j), 1e-5 );
171
172 if ( ! ret ) {
173 std::cerr << "\n\nregression test failure : matrices not identical" << std::endl;
174 exit( 1 );
175 }
176 }
177
178 template < typename T >
report(std::ostream & os,int runs,int runs_i,int size_i,double time)179 void report(std::ostream& os, int runs, int runs_i, int size_i, double time)
180 {
181 double normed_time = runs * time / ( runs_i * size_i ) ;
182 double mflops = flops<T>(size_i,0,runs_i,time) ;
183 std::cerr << std::setw(12) << normed_time << std::setw(12) << mflops ;
184 os << std::setw(12) << normed_time << std::setw(12) << mflops ;
185 }
186
187 template < typename FunctorType >
loop(std::ostream & os,int start,int step,int stop,int runs,FunctorType functor)188 void loop(std::ostream& os, int start, int step, int stop, int runs, FunctorType functor)
189 {
190 for(int size_i = start ; size_i <= stop ; size_i = std::max( static_cast< int >( size_i * (1 + 1.0 / step ) ), size_i + 1 ) ) {
191 int runs_i = 10 * runs / size_i ;
192
193 std::cerr << size_i << "\t";
194 os << size_i << "\t";
195
196 functor.operator()( os, stop, size_i, runs, runs_i ) ;
197
198 std::cerr << std::endl;
199 os << std::endl;
200 }
201 }
202
203 template < typename FunctorType, typename CallFunctor >
loop(std::ostream & os,int start,int step,int stop,int runs,FunctorType functor,CallFunctor ublas_call)204 void loop(std::ostream& os, int start, int step, int stop, int runs, FunctorType functor, CallFunctor ublas_call)
205 {
206 for(int size_i = start ; size_i <= stop ; size_i = std::max( static_cast< int >( size_i * (1 + 1.0 / step ) ), size_i + 1 ) ) {
207 int runs_i = 10 * runs / size_i ;
208
209 std::cerr << size_i << "\t";
210 os << size_i << "\t";
211
212 functor.operator()( os, stop, size_i, runs, runs_i, ublas_call ) ;
213
214 std::cerr << std::endl;
215 os << std::endl;
216 }
217 }
218