1 /*=============================================================================
2     Copyright (c) 2001-2011 Joel de Guzman
3     Copyright (c) 2005-2006 Dan Marsden
4 
5     Distributed under the Boost Software License, Version 1.0. (See accompanying
6     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 ==============================================================================*/
8 #include <boost/array.hpp>
9 #include <boost/timer.hpp>
10 
11 #include <boost/fusion/algorithm/iteration/accumulate.hpp>
12 #include <boost/fusion/algorithm/transformation/transform.hpp>
13 #include <boost/fusion/container/vector.hpp>
14 #include <boost/fusion/algorithm/transformation/zip.hpp>
15 #include <boost/fusion/sequence/intrinsic/at.hpp>
16 #include <boost/fusion/adapted/array.hpp>
17 #include <boost/fusion/sequence/intrinsic/at.hpp>
18 
19 #include <boost/type_traits/remove_reference.hpp>
20 
21 #include <algorithm>
22 #include <numeric>
23 #include <functional>
24 #include <iostream>
25 #include <cmath>
26 #include <limits>
27 
28 #ifdef _MSC_VER
29 // inline aggressively
30 # pragma inline_recursion(on) // turn on inline recursion
31 # pragma inline_depth(255)    // max inline depth
32 #endif
33 
34 int const REPEAT_COUNT = 10;
35 
36 double const duration = 0.5;
37 
38 namespace
39 {
40     struct poly_add
41     {
42         template<typename Sig>
43         struct result;
44 
45         template<typename Lhs, typename Rhs>
46         struct result<poly_add(Lhs, Rhs)>
47             : boost::remove_reference<Lhs>
48         {};
49 
50         template<typename Lhs, typename Rhs>
51         Lhs operator()(const Lhs& lhs, const Rhs& rhs) const
52         {
53             return lhs + rhs;
54         }
55     };
56 
57     struct poly_mult
58     {
59         template<typename Sig>
60         struct result;
61 
62         template<typename Lhs, typename Rhs>
63         struct result<poly_mult(Lhs, Rhs)>
64             : boost::remove_reference<Lhs>
65         {};
66 
67         template<typename Lhs, typename Rhs>
68         Lhs operator()(const Lhs& lhs, const Rhs& rhs) const
69         {
70             return lhs * rhs;
71         }
72     };
73 
74     template<int N>
time_for_std_inner_product(int & j)75     double time_for_std_inner_product(int& j)
76     {
77         boost::timer tim;
78         int i = 0;
79         long long iter = 65536;
80         long long counter, repeats;
81         double result = (std::numeric_limits<double>::max)();
82         double runtime = 0;
83         double run;
84         boost::array<int, N> arr1;
85         boost::array<int, N> arr2;
86         std::generate(arr1.begin(), arr1.end(), rand);
87         std::generate(arr2.begin(), arr2.end(), rand);
88         do
89         {
90             tim.restart();
91             for(counter = 0; counter < iter; ++counter)
92             {
93                 i = std::inner_product(arr1.begin(), arr1.end(), arr2.begin(), 0);
94                 static_cast<void>(i);
95             }
96             runtime = tim.elapsed();
97             iter *= 2;
98         } while(runtime < duration);
99         iter /= 2;
100 
101         // repeat test and report least value for consistency:
102         for(repeats = 0; repeats < REPEAT_COUNT; ++repeats)
103         {
104             tim.restart();
105             for(counter = 0; counter < iter; ++counter)
106             {
107                 i = std::inner_product(arr1.begin(), arr1.end(), arr2.begin(), 0);
108                 j += i;
109             }
110             run = tim.elapsed();
111             result = (std::min)(run, result);
112         }
113         std::cout << i << std::endl;
114         return result / iter;
115     }
116 
117     struct poly_combine
118     {
119         template<typename Sig>
120         struct result;
121 
122         template<typename Lhs, typename Rhs>
123         struct result<poly_combine(Lhs, Rhs)>
124             : boost::remove_reference<Lhs>
125         {};
126 
127         template<typename Lhs, typename Rhs>
128         typename result<poly_combine(Lhs,Rhs)>::type
operator ()__anon1ac946e90111::poly_combine129         operator()(const Lhs& lhs, const Rhs& rhs) const
130         {
131             return lhs + boost::fusion::at_c<0>(rhs) * boost::fusion::at_c<1>(rhs);
132         }
133     };
134 
135     template<int N>
time_for_fusion_inner_product2(int & j)136     double time_for_fusion_inner_product2(int& j)
137     {
138         boost::timer tim;
139         int i = 0;
140         long long iter = 65536;
141         long long counter, repeats;
142         double result = (std::numeric_limits<double>::max)();
143         double runtime = 0;
144         double run;
145         boost::array<int, N> arr1;
146         boost::array<int, N> arr2;
147         std::generate(arr1.begin(), arr1.end(), rand);
148         std::generate(arr2.begin(), arr2.end(), rand);
149         do
150         {
151             tim.restart();
152             for(counter = 0; counter < iter; ++counter)
153             {
154                 i = boost::fusion::accumulate(
155                     boost::fusion::zip(arr1, arr2), 0, poly_combine());
156                 static_cast<void>(i);
157             }
158             runtime = tim.elapsed();
159             iter *= 2;
160         } while(runtime < duration);
161         iter /= 2;
162 
163         std::cout << iter << " iterations" << std::endl;
164 
165         // repeat test and report least value for consistency:
166         for(repeats = 0; repeats < REPEAT_COUNT; ++repeats)
167         {
168             tim.restart();
169             for(counter = 0; counter < iter; ++counter)
170             {
171                 i = boost::fusion::accumulate(
172                     boost::fusion::zip(arr1, arr2), 0, poly_combine());
173                 j += i;
174             }
175             run = tim.elapsed();
176             result = (std::min)(run, result);
177         }
178         std::cout << i << std::endl;
179         return result / iter;
180     }
181 }
182 
main()183 int main()
184 {
185     int total = 0;
186     int res;
187 
188     std::cout << "short inner_product std test " << time_for_std_inner_product<8>(res) << std::endl;
189     total += res;
190     std::cout << "short inner_product fusion 2 test " << time_for_fusion_inner_product2<8>(res) << std::endl;
191     total += res;
192 
193     std::cout << "medium inner_product std test " << time_for_std_inner_product<64>(res) << std::endl;
194     total += res;
195     std::cout << "medium inner_product fusion 2 test " << time_for_fusion_inner_product2<64>(res) << std::endl;
196     total += res;
197 
198 #if 0 // Leads to ICE with MSVC 8.0
199     std::cout << "long inner_product std test " << time_for_std_inner_product<128>(res) << std::endl;
200     total += res;
201     std::cout << "long inner_product fusion 2 test " << time_for_fusion_inner_product2<128>(res) << std::endl;
202     total += res;
203 #endif
204 
205     return total;
206 }
207