summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/statechart/example/Performance/Performance.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/statechart/example/Performance/Performance.cpp')
-rw-r--r--src/boost/libs/statechart/example/Performance/Performance.cpp522
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;
+}