123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- /*=============================================================================
- Copyright (c) 2001-2011 Joel de Guzman
- Distributed under the Boost Software License, Version 1.0. (See accompanying
- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- ==============================================================================*/
- #include "measure.hpp"
- #define FUSION_MAX_LIST_SIZE 30
- #define FUSION_MAX_VECTOR_SIZE 30
- #include <boost/fusion/algorithm/iteration/accumulate.hpp>
- #include <boost/fusion/container/vector.hpp>
- #include <boost/fusion/container/list.hpp>
- #include <boost/type_traits/remove_reference.hpp>
- #include <boost/lexical_cast.hpp>
- #include <boost/preprocessor/stringize.hpp>
- #include <boost/preprocessor/enum.hpp>
- #include <iostream>
- #ifdef _MSC_VER
- // inline aggressively
- # pragma inline_recursion(on) // turn on inline recursion
- # pragma inline_depth(255) // max inline depth
- #endif
- // About the tests:
- //
- // The tests below compare various fusion sequences to see how abstraction
- // affects prformance.
- //
- // We have 3 sequence sizes for each fusion sequence we're going to test.
- //
- // small = 3 elements
- // medium = 10 elements
- // big = 30 elements
- //
- // The sequences are initialized with values 0..N-1 from numeric strings
- // parsed by boost::lexical_cast to make sure that the compiler is not
- // optimizing by replacing the computation with constant results computed
- // at compile time.
- //
- // These sequences will be subjected to our accumulator which calls
- // fusion::accumulate:
- //
- // this->sum += boost::fusion::accumulate(seq, 0, poly_add());
- //
- // where poly_add simply sums the current value with the content of
- // the sequence element. This accumulator will be called many times
- // through the "hammer" test (see measure.hpp).
- //
- // The tests are compared against a base using a plain_accumulator
- // which does a simple addition:
- //
- // this->sum += x;
- namespace
- {
- struct poly_add
- {
- template<typename Sig>
- struct result;
- template<typename Lhs, typename Rhs>
- struct result<poly_add(Lhs, Rhs)>
- : boost::remove_reference<Lhs>
- {};
- template<typename Lhs, typename Rhs>
- Lhs operator()(const Lhs& lhs, const Rhs& rhs) const
- {
- return lhs + rhs;
- }
- };
- // Our Accumulator function
- template <typename T>
- struct accumulator
- {
- accumulator()
- : sum()
- {}
-
- template <typename Sequence>
- void operator()(Sequence const& seq)
- {
- this->sum += boost::fusion::accumulate(seq, 0, poly_add());
- }
-
- T sum;
- };
- // Plain Accumulator function
- template <typename T>
- struct plain_accumulator
- {
- plain_accumulator()
- : sum()
- {}
-
- template <typename X>
- void operator()(X const& x)
- {
- this->sum += x;
- }
-
- T sum;
- };
-
- template <typename T>
- void check(T const& seq, char const* info)
- {
- test::measure<accumulator<int> >(seq, 1);
- std::cout << info << test::live_code << std::endl;
- }
- template <typename T>
- void measure(T const& seq, char const* info, long const repeats, double base)
- {
- double t = test::measure<accumulator<int> >(seq, repeats);
- std::cout
- << info
- << t
- << " (" << int((t/base)*100) << "%)"
- << std::endl;
- }
- template <typename T>
- void test_assembler(T const& seq)
- {
- test::live_code = boost::fusion::accumulate(seq, 0, poly_add());
- }
- }
- // We'll initialize the sequences from numeric strings that
- // pass through boost::lexical_cast to make sure that the
- // compiler is not optimizing by replacing the computation
- // with constant results computed at compile time.
- #define INIT(z, n, text) boost::lexical_cast<int>(BOOST_PP_STRINGIZE(n))
- int main()
- {
- using namespace boost::fusion;
- std::cout.setf(std::ios::scientific);
- vector<
- int, int, int
- >
- vsmall(BOOST_PP_ENUM(3, INIT, _));
- list<
- int, int, int
- >
- lsmall(BOOST_PP_ENUM(3, INIT, _));
- vector<
- int, int, int, int, int, int, int, int, int, int
- >
- vmedium(BOOST_PP_ENUM(10, INIT, _));
- list<
- int, int, int, int, int, int, int, int, int, int
- >
- lmedium(BOOST_PP_ENUM(10, INIT, _));
- vector<
- int, int, int, int, int, int, int, int, int, int
- , int, int, int, int, int, int, int, int, int, int
- , int, int, int, int, int, int, int, int, int, int
- >
- vbig(BOOST_PP_ENUM(30, INIT, _));
- list<
- int, int, int, int, int, int, int, int, int, int
- , int, int, int, int, int, int, int, int, int, int
- , int, int, int, int, int, int, int, int, int, int
- >
- lbig(BOOST_PP_ENUM(30, INIT, _));
- // first decide how many repetitions to measure
- long repeats = 100;
- double measured = 0;
- while (measured < 2.0 && repeats <= 10000000)
- {
- repeats *= 10;
-
- boost::timer time;
- test::hammer<plain_accumulator<int> >(0, repeats);
- test::hammer<accumulator<int> >(vsmall, repeats);
- test::hammer<accumulator<int> >(lsmall, repeats);
- test::hammer<accumulator<int> >(vmedium, repeats);
- test::hammer<accumulator<int> >(lmedium, repeats);
- test::hammer<accumulator<int> >(vbig, repeats);
- test::hammer<accumulator<int> >(lbig, repeats);
- measured = time.elapsed();
- }
- test::measure<plain_accumulator<int> >(1, 1);
- std::cout
- << "base accumulated result: "
- << test::live_code
- << std::endl;
- double base_time = test::measure<plain_accumulator<int> >(1, repeats);
- std::cout
- << "base time: "
- << base_time;
- std::cout
- << std::endl
- << "-------------------------------------------------------------------"
- << std::endl;
- check(vsmall, "small vector accumulated result: ");
- check(lsmall, "small list accumulated result: ");
- check(vmedium, "medium vector accumulated result: ");
- check(lmedium, "medium list accumulated result: ");
- check(vbig, "big vector accumulated result: ");
- check(lbig, "big list accumulated result: ");
- std::cout
- << "-------------------------------------------------------------------"
- << std::endl;
- measure(vsmall, "small vector time: ", repeats, base_time);
- measure(lsmall, "small list time: ", repeats, base_time);
- measure(vmedium, "medium vector time: ", repeats, base_time);
- measure(lmedium, "medium list time: ", repeats, base_time);
- measure(vbig, "big vector time: ", repeats, base_time);
- measure(lbig, "big list time: ", repeats, base_time);
- std::cout
- << "-------------------------------------------------------------------"
- << std::endl;
- // Let's see how this looks in assembler
- test_assembler(vmedium);
- // This is ultimately responsible for preventing all the test code
- // from being optimized away. Change this to return 0 and you
- // unplug the whole test's life support system.
- return test::live_code != 0;
- }
|