📄 performance.cpp
字号:
//////////////////////////////////////////////////////////////////////////////// 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_NAMESPACEnamespace 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#endifnamespace 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;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -