123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 |
- //////////////////////////////////////////////////////////////////////////////
- // Copyright 2005-2008 Andreas Huber Doenni
- // Distributed under the Boost Software License, Version 1.0. (See accompany-
- // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- // #define CUSTOMIZE_MEMORY_MANAGEMENT
- // #define BOOST_STATECHART_USE_NATIVE_RTTI
- //////////////////////////////////////////////////////////////////////////////
- // This program measures event processing performance of the BitMachine
- // (see BitMachine example for more information) with a varying number of
- // states. Also, a varying number of transitions are replaced with in-state
- // reactions. This allows us to calculate how much time is spent for state-
- // entry and state-exit during a transition. All measurements are written to
- // comma-separated-values files, one file for each individual BitMachine.
- //////////////////////////////////////////////////////////////////////////////
- #include <boost/statechart/event.hpp>
- #include <boost/statechart/simple_state.hpp>
- #include <boost/statechart/state_machine.hpp>
- #include <boost/statechart/transition.hpp>
- #include <boost/statechart/in_state_reaction.hpp>
- #include <boost/mpl/list.hpp>
- #include <boost/mpl/front_inserter.hpp>
- #include <boost/mpl/transform_view.hpp>
- #include <boost/mpl/copy.hpp>
- #include <boost/mpl/range_c.hpp>
- #include <boost/mpl/integral_c.hpp>
- #include <boost/mpl/shift_left.hpp>
- #include <boost/mpl/bitxor.hpp>
- #include <boost/mpl/for_each.hpp>
- #include <boost/mpl/placeholders.hpp>
- #include <boost/mpl/if.hpp>
- #include <boost/mpl/less.hpp>
- #include <boost/mpl/aux_/lambda_support.hpp>
- #include <boost/intrusive_ptr.hpp>
- #include <boost/config.hpp>
- #include <boost/assert.hpp>
- #ifdef CUSTOMIZE_MEMORY_MANAGEMENT
- # ifdef BOOST_MSVC
- # pragma warning( push )
- # pragma warning( disable: 4127 ) // conditional expression is constant
- # pragma warning( disable: 4800 ) // forcing value to bool 'true' or 'false'
- # endif
- # define BOOST_NO_MT
- # include <boost/pool/pool_alloc.hpp>
- # ifdef BOOST_MSVC
- # pragma warning( pop )
- # endif
- #endif
- #include <vector>
- #include <ctime>
- #include <iostream>
- #include <fstream>
- #include <iomanip>
- #include <ios>
- #include <string>
- #include <algorithm>
- #ifdef BOOST_NO_STDC_NAMESPACE
- namespace std
- {
- using ::clock_t;
- using ::clock;
- }
- #endif
- #ifdef BOOST_INTEL
- # pragma warning( disable: 304 ) // access control not specified
- # pragma warning( disable: 444 ) // destructor for base is not virtual
- # pragma warning( disable: 981 ) // operands are evaluated in unspecified order
- #endif
- namespace sc = boost::statechart;
- namespace mpl = boost::mpl;
- //////////////////////////////////////////////////////////////////////////////
- typedef mpl::integral_c< unsigned int, 0 > uint0;
- typedef mpl::integral_c< unsigned int, 1 > uint1;
- typedef mpl::integral_c< unsigned int, 2 > uint2;
- typedef mpl::integral_c< unsigned int, 3 > uint3;
- typedef mpl::integral_c< unsigned int, 4 > uint4;
- typedef mpl::integral_c< unsigned int, 5 > uint5;
- typedef mpl::integral_c< unsigned int, 6 > uint6;
- typedef mpl::integral_c< unsigned int, 7 > uint7;
- typedef mpl::integral_c< unsigned int, 8 > uint8;
- typedef mpl::integral_c< unsigned int, 9 > uint9;
- //////////////////////////////////////////////////////////////////////////////
- template< class BitNo >
- struct EvFlipBit : sc::event< EvFlipBit< BitNo > > {};
- boost::intrusive_ptr< const sc::event_base > pFlipBitEvents[] =
- {
- new EvFlipBit< uint0 >,
- new EvFlipBit< uint1 >,
- new EvFlipBit< uint2 >,
- new EvFlipBit< uint3 >,
- new EvFlipBit< uint4 >,
- new EvFlipBit< uint5 >,
- new EvFlipBit< uint6 >,
- new EvFlipBit< uint7 >,
- new EvFlipBit< uint8 >,
- new EvFlipBit< uint9 >
- };
- //////////////////////////////////////////////////////////////////////////////
- template<
- class StateNo,
- class NoOfBits,
- class FirstTransitionBit >
- struct BitState;
- template< class NoOfBits, class FirstTransitionBit >
- struct BitMachine : sc::state_machine<
- BitMachine< NoOfBits, FirstTransitionBit >,
- BitState< uint0, NoOfBits, FirstTransitionBit >
- #ifdef CUSTOMIZE_MEMORY_MANAGEMENT
- , boost::fast_pool_allocator< int >
- #endif
- >
- {
- public:
- BitMachine() : inStateReactions_( 0 ), transitions_( 0 ) {}
- // GCC 3.4.2 doesn't seem to instantiate a function template despite the
- // fact that an address of the instantiation is passed as a non-type
- // template argument. This leads to linker errors when a function template
- // is defined instead of the overloads below.
- void InStateReaction( const EvFlipBit< uint0 > & )
- {
- ++inStateReactions_;
- }
- void InStateReaction( const EvFlipBit< uint1 > & )
- {
- ++inStateReactions_;
- }
- void InStateReaction( const EvFlipBit< uint2 > & )
- {
- ++inStateReactions_;
- }
- void InStateReaction( const EvFlipBit< uint3 > & )
- {
- ++inStateReactions_;
- }
- void InStateReaction( const EvFlipBit< uint4 > & )
- {
- ++inStateReactions_;
- }
- void InStateReaction( const EvFlipBit< uint5 > & )
- {
- ++inStateReactions_;
- }
- void InStateReaction( const EvFlipBit< uint6 > & )
- {
- ++inStateReactions_;
- }
- void InStateReaction( const EvFlipBit< uint7 > & )
- {
- ++inStateReactions_;
- }
- void InStateReaction( const EvFlipBit< uint8 > & )
- {
- ++inStateReactions_;
- }
- void InStateReaction( const EvFlipBit< uint9 > & )
- {
- ++inStateReactions_;
- }
- void Transition( const EvFlipBit< uint0 > & )
- {
- ++transitions_;
- }
- void Transition( const EvFlipBit< uint1 > & )
- {
- ++transitions_;
- }
- void Transition( const EvFlipBit< uint2 > & )
- {
- ++transitions_;
- }
- void Transition( const EvFlipBit< uint3 > & )
- {
- ++transitions_;
- }
- void Transition( const EvFlipBit< uint4 > & )
- {
- ++transitions_;
- }
- void Transition( const EvFlipBit< uint5 > & )
- {
- ++transitions_;
- }
- void Transition( const EvFlipBit< uint6 > & )
- {
- ++transitions_;
- }
- void Transition( const EvFlipBit< uint7 > & )
- {
- ++transitions_;
- }
- void Transition( const EvFlipBit< uint8 > & )
- {
- ++transitions_;
- }
- void Transition( const EvFlipBit< uint9 > & )
- {
- ++transitions_;
- }
- unsigned int GetNoOfInStateReactions() const
- {
- return inStateReactions_;
- }
- unsigned int GetNoOfTransitions() const
- {
- return transitions_;
- }
- private:
- unsigned int inStateReactions_;
- unsigned int transitions_;
- };
- //////////////////////////////////////////////////////////////////////////////
- template<
- class BitNo, class StateNo, class NoOfBits, class FirstTransitionBit >
- struct FlipTransition
- {
- private:
- typedef typename mpl::bitxor_<
- StateNo,
- mpl::shift_left< uint1, BitNo >
- >::type NextStateNo;
- public:
- typedef typename mpl::if_<
- mpl::less< BitNo, FirstTransitionBit >,
- sc::in_state_reaction<
- EvFlipBit< BitNo >,
- BitMachine< NoOfBits, FirstTransitionBit >,
- &BitMachine< NoOfBits, FirstTransitionBit >::InStateReaction >,
- sc::transition<
- EvFlipBit< BitNo >,
- BitState< NextStateNo, NoOfBits, FirstTransitionBit >,
- BitMachine< NoOfBits, FirstTransitionBit >,
- &BitMachine< NoOfBits, FirstTransitionBit >::Transition >
- >::type type;
- BOOST_MPL_AUX_LAMBDA_SUPPORT(
- 3, FlipTransition, (BitNo, StateNo, FirstTransitionBit) );
- };
- //////////////////////////////////////////////////////////////////////////////
- template<
- class StateNo,
- class NoOfBits,
- class FirstTransitionBit >
- struct BitState : sc::simple_state<
- BitState< StateNo, NoOfBits, FirstTransitionBit >,
- BitMachine< NoOfBits, FirstTransitionBit > >
- {
- typedef typename mpl::copy<
- typename mpl::transform_view<
- mpl::range_c< unsigned int, 0, NoOfBits::value >,
- FlipTransition<
- mpl::placeholders::_, StateNo, NoOfBits, FirstTransitionBit >
- >::type,
- mpl::front_inserter< mpl::list<> >
- >::type reactions;
- };
- // GCC 3.4.2 doesn't seem to instantiate a class template member function
- // despite the fact that an address of the function is passed as a non-type
- // template argument. This leads to linker errors when the class template
- // defining the functions is not explicitly instantiated.
- template struct BitMachine< uint1, uint0 >;
- template struct BitMachine< uint1, uint1 >;
- template struct BitMachine< uint2, uint0 >;
- template struct BitMachine< uint2, uint1 >;
- template struct BitMachine< uint2, uint2 >;
- template struct BitMachine< uint3, uint0 >;
- template struct BitMachine< uint3, uint1 >;
- template struct BitMachine< uint3, uint2 >;
- template struct BitMachine< uint3, uint3 >;
- template struct BitMachine< uint4, uint0 >;
- template struct BitMachine< uint4, uint1 >;
- template struct BitMachine< uint4, uint2 >;
- template struct BitMachine< uint4, uint3 >;
- template struct BitMachine< uint4, uint4 >;
- template struct BitMachine< uint5, uint0 >;
- template struct BitMachine< uint5, uint1 >;
- template struct BitMachine< uint5, uint2 >;
- template struct BitMachine< uint5, uint3 >;
- template struct BitMachine< uint5, uint4 >;
- template struct BitMachine< uint5, uint5 >;
- template struct BitMachine< uint6, uint0 >;
- template struct BitMachine< uint6, uint1 >;
- template struct BitMachine< uint6, uint2 >;
- template struct BitMachine< uint6, uint3 >;
- template struct BitMachine< uint6, uint4 >;
- template struct BitMachine< uint6, uint5 >;
- template struct BitMachine< uint6, uint6 >;
- template struct BitMachine< uint7, uint0 >;
- template struct BitMachine< uint7, uint1 >;
- template struct BitMachine< uint7, uint2 >;
- template struct BitMachine< uint7, uint3 >;
- template struct BitMachine< uint7, uint4 >;
- template struct BitMachine< uint7, uint5 >;
- template struct BitMachine< uint7, uint6 >;
- template struct BitMachine< uint7, uint7 >;
- ////////////////////////////////////////////////////////////////////////////
- struct PerfResult
- {
- PerfResult( double inStateRatio, double nanoSecondsPerReaction ) :
- inStateRatio_( inStateRatio ),
- nanoSecondsPerReaction_( nanoSecondsPerReaction )
- {
- }
- double inStateRatio_;
- double nanoSecondsPerReaction_;
- };
- template< class NoOfBits, class FirstTransitionBit >
- class PerformanceTester
- {
- public:
- ////////////////////////////////////////////////////////////////////////
- static PerfResult Test()
- {
- eventsSent_ = 0;
- BitMachine< NoOfBits, FirstTransitionBit > machine;
- machine.initiate();
- const std::clock_t startTime = std::clock();
- const unsigned int laps = eventsToSend_ / ( GetNoOfStates() - 1 );
- for ( unsigned int lap = 0; lap < laps; ++lap )
- {
- VisitAllStatesImpl( machine, NoOfBits::value - 1 );
- }
- const std::clock_t elapsedTime = std::clock() - startTime;
- BOOST_ASSERT( eventsSent_ == eventsToSend_ );
- BOOST_ASSERT(
- machine.GetNoOfInStateReactions() +
- machine.GetNoOfTransitions() == eventsSent_ );
- return PerfResult(
- static_cast< double >( machine.GetNoOfInStateReactions() ) /
- eventsSent_,
- static_cast< double >( elapsedTime ) /
- CLOCKS_PER_SEC * 1000.0 * 1000.0 * 1000.0 / eventsSent_ );
- }
- static unsigned int GetNoOfStates()
- {
- return 1 << NoOfBits::value;
- }
- static unsigned int GetNoOfReactions()
- {
- return GetNoOfStates() * NoOfBits::value;
- }
- private:
- ////////////////////////////////////////////////////////////////////////
- static void VisitAllStatesImpl(
- BitMachine< NoOfBits, FirstTransitionBit > & machine,
- unsigned int bit )
- {
- if ( bit > 0 )
- {
- PerformanceTester< NoOfBits, FirstTransitionBit >::
- VisitAllStatesImpl( machine, bit - 1 );
- }
- machine.process_event( *pFlipBitEvents[ bit ] );
- ++PerformanceTester< NoOfBits, FirstTransitionBit >::eventsSent_;
- if ( bit > 0 )
- {
- PerformanceTester< NoOfBits, FirstTransitionBit >::
- VisitAllStatesImpl( machine, bit - 1 );
- }
- }
- // common prime factors of 2^n-1 for n in [1,8]
- static const unsigned int eventsToSend_ = 3 * 3 * 5 * 7 * 17 * 31 * 127;
- static unsigned int eventsSent_;
- };
- template< class NoOfBits, class FirstTransitionBit >
- unsigned int PerformanceTester< NoOfBits, FirstTransitionBit >::eventsSent_;
- //////////////////////////////////////////////////////////////////////////////
- typedef std::vector< PerfResult > PerfResultList;
- template< class NoOfBits >
- struct PerfResultBackInserter
- {
- public:
- PerfResultBackInserter( PerfResultList & perfResultList ) :
- perfResultList_( perfResultList )
- {
- }
- template< class FirstTransitionBit >
- void operator()( const FirstTransitionBit & )
- {
- perfResultList_.push_back(
- PerformanceTester< NoOfBits, FirstTransitionBit >::Test() );
- }
- private:
- // avoids C4512 (assignment operator could not be generated)
- PerfResultBackInserter & operator=( const PerfResultBackInserter & );
- PerfResultList & perfResultList_;
- };
- template< class NoOfBits >
- std::vector< PerfResult > TestMachine()
- {
- PerfResultList result;
- mpl::for_each< mpl::range_c< unsigned int, 0, NoOfBits::value + 1 > >(
- PerfResultBackInserter< NoOfBits >( result ) );
- return result;
- }
- template< class NoOfBits >
- void TestAndWriteResults()
- {
- PerfResultList results = TestMachine< NoOfBits >();
- std::fstream output;
- output.exceptions(
- std::ios_base::badbit | std::ios_base::eofbit | std::ios_base::failbit );
- std::string prefix = std::string( BOOST_COMPILER ) + "__";
- std::replace( prefix.begin(), prefix.end(), ' ', '_' );
- output.open(
- ( prefix + std::string( 1, '0' + static_cast< char >( NoOfBits::value ) )
- + ".txt" ).c_str(),
- std::ios_base::out );
- for ( PerfResultList::const_iterator pResult = results.begin();
- pResult != results.end(); ++pResult )
- {
- output << std::fixed << std::setprecision( 0 ) <<
- std::setw( 8 ) << pResult->inStateRatio_ * 100 << ',' <<
- std::setw( 8 ) << pResult->nanoSecondsPerReaction_ << "\n";
- }
- }
- //////////////////////////////////////////////////////////////////////////////
- int main()
- {
- std::cout <<
- "Boost.Statechart in-state reaction vs. transition performance test\n\n";
- std::cout << "Press <CR> to start the test: ";
- {
- std::string input;
- std::getline( std::cin, input );
- }
- TestAndWriteResults< uint1 >();
- TestAndWriteResults< uint2 >();
- TestAndWriteResults< uint3 >();
- return 0;
- }
|