sequence_efficiency.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. /*=============================================================================
  2. Copyright (c) 2001-2011 Joel de Guzman
  3. Distributed under the Boost Software License, Version 1.0. (See accompanying
  4. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. ==============================================================================*/
  6. #include "measure.hpp"
  7. #define FUSION_MAX_LIST_SIZE 30
  8. #define FUSION_MAX_VECTOR_SIZE 30
  9. #include <boost/fusion/algorithm/iteration/accumulate.hpp>
  10. #include <boost/fusion/container/vector.hpp>
  11. #include <boost/fusion/container/list.hpp>
  12. #include <boost/type_traits/remove_reference.hpp>
  13. #include <boost/lexical_cast.hpp>
  14. #include <boost/preprocessor/stringize.hpp>
  15. #include <boost/preprocessor/enum.hpp>
  16. #include <iostream>
  17. #ifdef _MSC_VER
  18. // inline aggressively
  19. # pragma inline_recursion(on) // turn on inline recursion
  20. # pragma inline_depth(255) // max inline depth
  21. #endif
  22. // About the tests:
  23. //
  24. // The tests below compare various fusion sequences to see how abstraction
  25. // affects prformance.
  26. //
  27. // We have 3 sequence sizes for each fusion sequence we're going to test.
  28. //
  29. // small = 3 elements
  30. // medium = 10 elements
  31. // big = 30 elements
  32. //
  33. // The sequences are initialized with values 0..N-1 from numeric strings
  34. // parsed by boost::lexical_cast to make sure that the compiler is not
  35. // optimizing by replacing the computation with constant results computed
  36. // at compile time.
  37. //
  38. // These sequences will be subjected to our accumulator which calls
  39. // fusion::accumulate:
  40. //
  41. // this->sum += boost::fusion::accumulate(seq, 0, poly_add());
  42. //
  43. // where poly_add simply sums the current value with the content of
  44. // the sequence element. This accumulator will be called many times
  45. // through the "hammer" test (see measure.hpp).
  46. //
  47. // The tests are compared against a base using a plain_accumulator
  48. // which does a simple addition:
  49. //
  50. // this->sum += x;
  51. namespace
  52. {
  53. struct poly_add
  54. {
  55. template<typename Sig>
  56. struct result;
  57. template<typename Lhs, typename Rhs>
  58. struct result<poly_add(Lhs, Rhs)>
  59. : boost::remove_reference<Lhs>
  60. {};
  61. template<typename Lhs, typename Rhs>
  62. Lhs operator()(const Lhs& lhs, const Rhs& rhs) const
  63. {
  64. return lhs + rhs;
  65. }
  66. };
  67. // Our Accumulator function
  68. template <typename T>
  69. struct accumulator
  70. {
  71. accumulator()
  72. : sum()
  73. {}
  74. template <typename Sequence>
  75. void operator()(Sequence const& seq)
  76. {
  77. this->sum += boost::fusion::accumulate(seq, 0, poly_add());
  78. }
  79. T sum;
  80. };
  81. // Plain Accumulator function
  82. template <typename T>
  83. struct plain_accumulator
  84. {
  85. plain_accumulator()
  86. : sum()
  87. {}
  88. template <typename X>
  89. void operator()(X const& x)
  90. {
  91. this->sum += x;
  92. }
  93. T sum;
  94. };
  95. template <typename T>
  96. void check(T const& seq, char const* info)
  97. {
  98. test::measure<accumulator<int> >(seq, 1);
  99. std::cout << info << test::live_code << std::endl;
  100. }
  101. template <typename T>
  102. void measure(T const& seq, char const* info, long const repeats, double base)
  103. {
  104. double t = test::measure<accumulator<int> >(seq, repeats);
  105. std::cout
  106. << info
  107. << t
  108. << " (" << int((t/base)*100) << "%)"
  109. << std::endl;
  110. }
  111. template <typename T>
  112. void test_assembler(T const& seq)
  113. {
  114. test::live_code = boost::fusion::accumulate(seq, 0, poly_add());
  115. }
  116. }
  117. // We'll initialize the sequences from numeric strings that
  118. // pass through boost::lexical_cast to make sure that the
  119. // compiler is not optimizing by replacing the computation
  120. // with constant results computed at compile time.
  121. #define INIT(z, n, text) boost::lexical_cast<int>(BOOST_PP_STRINGIZE(n))
  122. int main()
  123. {
  124. using namespace boost::fusion;
  125. std::cout.setf(std::ios::scientific);
  126. vector<
  127. int, int, int
  128. >
  129. vsmall(BOOST_PP_ENUM(3, INIT, _));
  130. list<
  131. int, int, int
  132. >
  133. lsmall(BOOST_PP_ENUM(3, INIT, _));
  134. vector<
  135. int, int, int, int, int, int, int, int, int, int
  136. >
  137. vmedium(BOOST_PP_ENUM(10, INIT, _));
  138. list<
  139. int, int, int, int, int, int, int, int, int, int
  140. >
  141. lmedium(BOOST_PP_ENUM(10, INIT, _));
  142. vector<
  143. int, int, int, int, int, int, int, int, int, int
  144. , int, int, int, int, int, int, int, int, int, int
  145. , int, int, int, int, int, int, int, int, int, int
  146. >
  147. vbig(BOOST_PP_ENUM(30, INIT, _));
  148. list<
  149. int, int, int, int, int, int, int, int, int, int
  150. , int, int, int, int, int, int, int, int, int, int
  151. , int, int, int, int, int, int, int, int, int, int
  152. >
  153. lbig(BOOST_PP_ENUM(30, INIT, _));
  154. // first decide how many repetitions to measure
  155. long repeats = 100;
  156. double measured = 0;
  157. while (measured < 2.0 && repeats <= 10000000)
  158. {
  159. repeats *= 10;
  160. boost::timer time;
  161. test::hammer<plain_accumulator<int> >(0, repeats);
  162. test::hammer<accumulator<int> >(vsmall, repeats);
  163. test::hammer<accumulator<int> >(lsmall, repeats);
  164. test::hammer<accumulator<int> >(vmedium, repeats);
  165. test::hammer<accumulator<int> >(lmedium, repeats);
  166. test::hammer<accumulator<int> >(vbig, repeats);
  167. test::hammer<accumulator<int> >(lbig, repeats);
  168. measured = time.elapsed();
  169. }
  170. test::measure<plain_accumulator<int> >(1, 1);
  171. std::cout
  172. << "base accumulated result: "
  173. << test::live_code
  174. << std::endl;
  175. double base_time = test::measure<plain_accumulator<int> >(1, repeats);
  176. std::cout
  177. << "base time: "
  178. << base_time;
  179. std::cout
  180. << std::endl
  181. << "-------------------------------------------------------------------"
  182. << std::endl;
  183. check(vsmall, "small vector accumulated result: ");
  184. check(lsmall, "small list accumulated result: ");
  185. check(vmedium, "medium vector accumulated result: ");
  186. check(lmedium, "medium list accumulated result: ");
  187. check(vbig, "big vector accumulated result: ");
  188. check(lbig, "big list accumulated result: ");
  189. std::cout
  190. << "-------------------------------------------------------------------"
  191. << std::endl;
  192. measure(vsmall, "small vector time: ", repeats, base_time);
  193. measure(lsmall, "small list time: ", repeats, base_time);
  194. measure(vmedium, "medium vector time: ", repeats, base_time);
  195. measure(lmedium, "medium list time: ", repeats, base_time);
  196. measure(vbig, "big vector time: ", repeats, base_time);
  197. measure(lbig, "big list time: ", repeats, base_time);
  198. std::cout
  199. << "-------------------------------------------------------------------"
  200. << std::endl;
  201. // Let's see how this looks in assembler
  202. test_assembler(vmedium);
  203. // This is ultimately responsible for preventing all the test code
  204. // from being optimized away. Change this to return 0 and you
  205. // unplug the whole test's life support system.
  206. return test::live_code != 0;
  207. }