diff options
Diffstat (limited to 'src/boost/libs/statechart/example/Performance/Performance.cpp')
-rw-r--r-- | src/boost/libs/statechart/example/Performance/Performance.cpp | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/src/boost/libs/statechart/example/Performance/Performance.cpp b/src/boost/libs/statechart/example/Performance/Performance.cpp new file mode 100644 index 000000000..7b127ce26 --- /dev/null +++ b/src/boost/libs/statechart/example/Performance/Performance.cpp @@ -0,0 +1,522 @@ +////////////////////////////////////////////////////////////////////////////// +// 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; +} |