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