• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //////////////////////////////////////////////////////////////////////////////
2 // Copyright 2005-2008 Andreas Huber Doenni
3 // Distributed under the Boost Software License, Version 1.0. (See accompany-
4 // ing file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 //////////////////////////////////////////////////////////////////////////////
6 
7 
8 
9 //////////////////////////////////////////////////////////////////////////////
10 // #define CUSTOMIZE_MEMORY_MANAGEMENT
11 // #define BOOST_STATECHART_USE_NATIVE_RTTI
12 //////////////////////////////////////////////////////////////////////////////
13 // This program measures event processing performance of the BitMachine
14 // (see BitMachine example for more information) with a varying number of
15 // states. Also, a varying number of transitions are replaced with in-state
16 // reactions. This allows us to calculate how much time is spent for state-
17 // entry and state-exit during a transition. All measurements are written to
18 // comma-separated-values files, one file for each individual BitMachine.
19 //////////////////////////////////////////////////////////////////////////////
20 
21 
22 
23 #include <boost/statechart/event.hpp>
24 #include <boost/statechart/simple_state.hpp>
25 #include <boost/statechart/state_machine.hpp>
26 #include <boost/statechart/transition.hpp>
27 #include <boost/statechart/in_state_reaction.hpp>
28 
29 #include <boost/mpl/list.hpp>
30 #include <boost/mpl/front_inserter.hpp>
31 #include <boost/mpl/transform_view.hpp>
32 #include <boost/mpl/copy.hpp>
33 #include <boost/mpl/range_c.hpp>
34 #include <boost/mpl/integral_c.hpp>
35 #include <boost/mpl/shift_left.hpp>
36 #include <boost/mpl/bitxor.hpp>
37 #include <boost/mpl/for_each.hpp>
38 #include <boost/mpl/placeholders.hpp>
39 #include <boost/mpl/if.hpp>
40 #include <boost/mpl/less.hpp>
41 #include <boost/mpl/aux_/lambda_support.hpp>
42 
43 #include <boost/intrusive_ptr.hpp>
44 #include <boost/config.hpp>
45 #include <boost/assert.hpp>
46 
47 #ifdef CUSTOMIZE_MEMORY_MANAGEMENT
48 #  ifdef BOOST_MSVC
49 #    pragma warning( push )
50 #    pragma warning( disable: 4127 ) // conditional expression is constant
51 #    pragma warning( disable: 4800 ) // forcing value to bool 'true' or 'false'
52 #  endif
53 #  define BOOST_NO_MT
54 #  include <boost/pool/pool_alloc.hpp>
55 #  ifdef BOOST_MSVC
56 #    pragma warning( pop )
57 #  endif
58 #endif
59 
60 #include <vector>
61 #include <ctime>
62 #include <iostream>
63 #include <fstream>
64 #include <iomanip>
65 #include <ios>
66 #include <string>
67 #include <algorithm>
68 
69 #ifdef BOOST_NO_STDC_NAMESPACE
70 namespace std
71 {
72   using ::clock_t;
73   using ::clock;
74 }
75 #endif
76 
77 #ifdef BOOST_INTEL
78 #  pragma warning( disable: 304 ) // access control not specified
79 #  pragma warning( disable: 444 ) // destructor for base is not virtual
80 #  pragma warning( disable: 981 ) // operands are evaluated in unspecified order
81 #endif
82 
83 
84 
85 namespace sc = boost::statechart;
86 namespace mpl = boost::mpl;
87 
88 
89 
90 //////////////////////////////////////////////////////////////////////////////
91 typedef mpl::integral_c< unsigned int, 0 > uint0;
92 typedef mpl::integral_c< unsigned int, 1 > uint1;
93 typedef mpl::integral_c< unsigned int, 2 > uint2;
94 typedef mpl::integral_c< unsigned int, 3 > uint3;
95 typedef mpl::integral_c< unsigned int, 4 > uint4;
96 typedef mpl::integral_c< unsigned int, 5 > uint5;
97 typedef mpl::integral_c< unsigned int, 6 > uint6;
98 typedef mpl::integral_c< unsigned int, 7 > uint7;
99 typedef mpl::integral_c< unsigned int, 8 > uint8;
100 typedef mpl::integral_c< unsigned int, 9 > uint9;
101 
102 //////////////////////////////////////////////////////////////////////////////
103 template< class BitNo >
104 struct EvFlipBit : sc::event< EvFlipBit< BitNo > > {};
105 
106 boost::intrusive_ptr< const sc::event_base > pFlipBitEvents[] =
107 {
108   new EvFlipBit< uint0 >,
109   new EvFlipBit< uint1 >,
110   new EvFlipBit< uint2 >,
111   new EvFlipBit< uint3 >,
112   new EvFlipBit< uint4 >,
113   new EvFlipBit< uint5 >,
114   new EvFlipBit< uint6 >,
115   new EvFlipBit< uint7 >,
116   new EvFlipBit< uint8 >,
117   new EvFlipBit< uint9 >
118 };
119 
120 
121 //////////////////////////////////////////////////////////////////////////////
122 template<
123   class StateNo,
124   class NoOfBits,
125   class FirstTransitionBit >
126 struct BitState;
127 
128 template< class NoOfBits, class FirstTransitionBit >
129 struct BitMachine : sc::state_machine<
130   BitMachine< NoOfBits, FirstTransitionBit >,
131   BitState< uint0, NoOfBits, FirstTransitionBit >
132   #ifdef CUSTOMIZE_MEMORY_MANAGEMENT
133   , boost::fast_pool_allocator< int >
134   #endif
135 >
136 {
137   public:
BitMachineBitMachine138     BitMachine() : inStateReactions_( 0 ), transitions_( 0 ) {}
139 
140     // GCC 3.4.2 doesn't seem to instantiate a function template despite the
141     // fact that an address of the instantiation is passed as a non-type
142     // template argument. This leads to linker errors when a function template
143     // is defined instead of the overloads below.
InStateReactionBitMachine144     void InStateReaction( const EvFlipBit< uint0 > & )
145     {
146       ++inStateReactions_;
147     }
148 
InStateReactionBitMachine149     void InStateReaction( const EvFlipBit< uint1 > & )
150     {
151       ++inStateReactions_;
152     }
153 
InStateReactionBitMachine154     void InStateReaction( const EvFlipBit< uint2 > & )
155     {
156       ++inStateReactions_;
157     }
158 
InStateReactionBitMachine159     void InStateReaction( const EvFlipBit< uint3 > & )
160     {
161       ++inStateReactions_;
162     }
163 
InStateReactionBitMachine164     void InStateReaction( const EvFlipBit< uint4 > & )
165     {
166       ++inStateReactions_;
167     }
168 
InStateReactionBitMachine169     void InStateReaction( const EvFlipBit< uint5 > & )
170     {
171       ++inStateReactions_;
172     }
173 
InStateReactionBitMachine174     void InStateReaction( const EvFlipBit< uint6 > & )
175     {
176       ++inStateReactions_;
177     }
178 
InStateReactionBitMachine179     void InStateReaction( const EvFlipBit< uint7 > & )
180     {
181       ++inStateReactions_;
182     }
183 
InStateReactionBitMachine184     void InStateReaction( const EvFlipBit< uint8 > & )
185     {
186       ++inStateReactions_;
187     }
188 
InStateReactionBitMachine189     void InStateReaction( const EvFlipBit< uint9 > & )
190     {
191       ++inStateReactions_;
192     }
193 
TransitionBitMachine194     void Transition( const EvFlipBit< uint0 > & )
195     {
196       ++transitions_;
197     }
198 
TransitionBitMachine199     void Transition( const EvFlipBit< uint1 > & )
200     {
201       ++transitions_;
202     }
203 
TransitionBitMachine204     void Transition( const EvFlipBit< uint2 > & )
205     {
206       ++transitions_;
207     }
208 
TransitionBitMachine209     void Transition( const EvFlipBit< uint3 > & )
210     {
211       ++transitions_;
212     }
213 
TransitionBitMachine214     void Transition( const EvFlipBit< uint4 > & )
215     {
216       ++transitions_;
217     }
218 
TransitionBitMachine219     void Transition( const EvFlipBit< uint5 > & )
220     {
221       ++transitions_;
222     }
223 
TransitionBitMachine224     void Transition( const EvFlipBit< uint6 > & )
225     {
226       ++transitions_;
227     }
228 
TransitionBitMachine229     void Transition( const EvFlipBit< uint7 > & )
230     {
231       ++transitions_;
232     }
233 
TransitionBitMachine234     void Transition( const EvFlipBit< uint8 > & )
235     {
236       ++transitions_;
237     }
238 
TransitionBitMachine239     void Transition( const EvFlipBit< uint9 > & )
240     {
241       ++transitions_;
242     }
243 
GetNoOfInStateReactionsBitMachine244     unsigned int GetNoOfInStateReactions() const
245     {
246       return inStateReactions_;
247     }
248 
GetNoOfTransitionsBitMachine249     unsigned int GetNoOfTransitions() const
250     {
251       return transitions_;
252     }
253 
254   private:
255     unsigned int inStateReactions_;
256     unsigned int transitions_;
257 };
258 
259 //////////////////////////////////////////////////////////////////////////////
260 template<
261   class BitNo, class StateNo, class NoOfBits, class FirstTransitionBit >
262 struct FlipTransition
263 {
264   private:
265     typedef typename mpl::bitxor_<
266       StateNo,
267       mpl::shift_left< uint1, BitNo >
268     >::type NextStateNo;
269 
270   public:
271     typedef typename mpl::if_<
272       mpl::less< BitNo, FirstTransitionBit >,
273       sc::in_state_reaction<
274         EvFlipBit< BitNo >,
275         BitMachine< NoOfBits, FirstTransitionBit >,
276         &BitMachine< NoOfBits, FirstTransitionBit >::InStateReaction >,
277       sc::transition<
278         EvFlipBit< BitNo >,
279         BitState< NextStateNo, NoOfBits, FirstTransitionBit >,
280         BitMachine< NoOfBits, FirstTransitionBit >,
281         &BitMachine< NoOfBits, FirstTransitionBit >::Transition >
282     >::type type;
283 
284     BOOST_MPL_AUX_LAMBDA_SUPPORT(
285       3, FlipTransition, (BitNo, StateNo, FirstTransitionBit) );
286 };
287 
288 //////////////////////////////////////////////////////////////////////////////
289 template<
290   class StateNo,
291   class NoOfBits,
292   class FirstTransitionBit >
293 struct BitState : sc::simple_state<
294   BitState< StateNo, NoOfBits, FirstTransitionBit >,
295   BitMachine< NoOfBits, FirstTransitionBit > >
296 {
297   typedef typename mpl::copy<
298     typename mpl::transform_view<
299       mpl::range_c< unsigned int, 0, NoOfBits::value >,
300       FlipTransition<
301         mpl::placeholders::_, StateNo, NoOfBits, FirstTransitionBit >
302     >::type,
303     mpl::front_inserter< mpl::list<> >
304   >::type reactions;
305 };
306 
307 // GCC 3.4.2 doesn't seem to instantiate a class template member function
308 // despite the fact that an address of the function is passed as a non-type
309 // template argument. This leads to linker errors when the class template
310 // defining the functions is not explicitly instantiated.
311 template struct BitMachine< uint1, uint0 >;
312 template struct BitMachine< uint1, uint1 >;
313 
314 template struct BitMachine< uint2, uint0 >;
315 template struct BitMachine< uint2, uint1 >;
316 template struct BitMachine< uint2, uint2 >;
317 
318 template struct BitMachine< uint3, uint0 >;
319 template struct BitMachine< uint3, uint1 >;
320 template struct BitMachine< uint3, uint2 >;
321 template struct BitMachine< uint3, uint3 >;
322 
323 template struct BitMachine< uint4, uint0 >;
324 template struct BitMachine< uint4, uint1 >;
325 template struct BitMachine< uint4, uint2 >;
326 template struct BitMachine< uint4, uint3 >;
327 template struct BitMachine< uint4, uint4 >;
328 
329 template struct BitMachine< uint5, uint0 >;
330 template struct BitMachine< uint5, uint1 >;
331 template struct BitMachine< uint5, uint2 >;
332 template struct BitMachine< uint5, uint3 >;
333 template struct BitMachine< uint5, uint4 >;
334 template struct BitMachine< uint5, uint5 >;
335 
336 template struct BitMachine< uint6, uint0 >;
337 template struct BitMachine< uint6, uint1 >;
338 template struct BitMachine< uint6, uint2 >;
339 template struct BitMachine< uint6, uint3 >;
340 template struct BitMachine< uint6, uint4 >;
341 template struct BitMachine< uint6, uint5 >;
342 template struct BitMachine< uint6, uint6 >;
343 
344 template struct BitMachine< uint7, uint0 >;
345 template struct BitMachine< uint7, uint1 >;
346 template struct BitMachine< uint7, uint2 >;
347 template struct BitMachine< uint7, uint3 >;
348 template struct BitMachine< uint7, uint4 >;
349 template struct BitMachine< uint7, uint5 >;
350 template struct BitMachine< uint7, uint6 >;
351 template struct BitMachine< uint7, uint7 >;
352 
353 
354 ////////////////////////////////////////////////////////////////////////////
355 struct PerfResult
356 {
PerfResultPerfResult357   PerfResult( double inStateRatio, double nanoSecondsPerReaction ) :
358     inStateRatio_( inStateRatio ),
359     nanoSecondsPerReaction_( nanoSecondsPerReaction )
360   {
361   }
362 
363   double inStateRatio_;
364   double nanoSecondsPerReaction_;
365 };
366 
367 template< class NoOfBits, class FirstTransitionBit >
368 class PerformanceTester
369 {
370   public:
371     ////////////////////////////////////////////////////////////////////////
Test()372     static PerfResult Test()
373     {
374       eventsSent_ = 0;
375       BitMachine< NoOfBits, FirstTransitionBit > machine;
376       machine.initiate();
377       const std::clock_t startTime = std::clock();
378 
379       const unsigned int laps = eventsToSend_ / ( GetNoOfStates() - 1 );
380 
381       for ( unsigned int lap = 0; lap < laps; ++lap )
382       {
383         VisitAllStatesImpl( machine, NoOfBits::value - 1 );
384       }
385 
386       const std::clock_t elapsedTime = std::clock() - startTime;
387 
388       BOOST_ASSERT( eventsSent_ == eventsToSend_ );
389       BOOST_ASSERT(
390         machine.GetNoOfInStateReactions() +
391         machine.GetNoOfTransitions() == eventsSent_ );
392 
393       return PerfResult(
394         static_cast< double >( machine.GetNoOfInStateReactions() ) /
395           eventsSent_,
396         static_cast< double >( elapsedTime ) /
397           CLOCKS_PER_SEC * 1000.0 * 1000.0 * 1000.0 / eventsSent_ );
398     }
399 
GetNoOfStates()400     static unsigned int GetNoOfStates()
401     {
402       return 1 << NoOfBits::value;
403     }
404 
GetNoOfReactions()405     static unsigned int GetNoOfReactions()
406     {
407       return GetNoOfStates() * NoOfBits::value;
408     }
409 
410   private:
411     ////////////////////////////////////////////////////////////////////////
VisitAllStatesImpl(BitMachine<NoOfBits,FirstTransitionBit> & machine,unsigned int bit)412     static void VisitAllStatesImpl(
413       BitMachine< NoOfBits, FirstTransitionBit > & machine,
414       unsigned int bit )
415     {
416       if ( bit > 0 )
417       {
418         PerformanceTester< NoOfBits, FirstTransitionBit >::
419           VisitAllStatesImpl( machine, bit - 1 );
420       }
421 
422       machine.process_event( *pFlipBitEvents[ bit ] );
423       ++PerformanceTester< NoOfBits, FirstTransitionBit >::eventsSent_;
424 
425       if ( bit > 0 )
426       {
427         PerformanceTester< NoOfBits, FirstTransitionBit >::
428           VisitAllStatesImpl( machine, bit - 1 );
429       }
430     }
431 
432     // common prime factors of 2^n-1 for n in [1,8]
433     static const unsigned int eventsToSend_ = 3 * 3 * 5 * 7 * 17 * 31 * 127;
434     static unsigned int eventsSent_;
435 };
436 
437 template< class NoOfBits, class FirstTransitionBit >
438 unsigned int PerformanceTester< NoOfBits, FirstTransitionBit >::eventsSent_;
439 
440 
441 //////////////////////////////////////////////////////////////////////////////
442 typedef std::vector< PerfResult > PerfResultList;
443 
444 template< class NoOfBits >
445 struct PerfResultBackInserter
446 {
447   public:
PerfResultBackInserterPerfResultBackInserter448     PerfResultBackInserter( PerfResultList & perfResultList ) :
449       perfResultList_( perfResultList )
450     {
451     }
452 
453     template< class FirstTransitionBit >
operator ()PerfResultBackInserter454     void operator()( const FirstTransitionBit & )
455     {
456       perfResultList_.push_back(
457         PerformanceTester< NoOfBits, FirstTransitionBit >::Test() );
458     }
459 
460   private:
461     // avoids C4512 (assignment operator could not be generated)
462     PerfResultBackInserter & operator=( const PerfResultBackInserter & );
463 
464     PerfResultList & perfResultList_;
465 };
466 
467 template< class NoOfBits >
TestMachine()468 std::vector< PerfResult > TestMachine()
469 {
470   PerfResultList result;
471 
472   mpl::for_each< mpl::range_c< unsigned int, 0, NoOfBits::value + 1 > >(
473     PerfResultBackInserter< NoOfBits >( result ) );
474 
475   return result;
476 }
477 
478 template< class NoOfBits >
TestAndWriteResults()479 void TestAndWriteResults()
480 {
481   PerfResultList results = TestMachine< NoOfBits >();
482 
483   std::fstream output;
484   output.exceptions(
485     std::ios_base::badbit | std::ios_base::eofbit | std::ios_base::failbit );
486 
487   std::string prefix = std::string( BOOST_COMPILER ) + "__";
488   std::replace( prefix.begin(), prefix.end(), ' ', '_' );
489 
490   output.open(
491     ( prefix + std::string( 1, '0' + static_cast< char >( NoOfBits::value ) )
492       + ".txt" ).c_str(),
493     std::ios_base::out );
494 
495   for ( PerfResultList::const_iterator pResult = results.begin();
496     pResult != results.end(); ++pResult )
497   {
498     output << std::fixed << std::setprecision( 0 ) <<
499       std::setw( 8 ) << pResult->inStateRatio_ * 100 << ',' <<
500       std::setw( 8 ) << pResult->nanoSecondsPerReaction_ << "\n";
501   }
502 }
503 
504 
505 //////////////////////////////////////////////////////////////////////////////
main()506 int main()
507 {
508   std::cout <<
509     "Boost.Statechart in-state reaction vs. transition performance test\n\n";
510   std::cout << "Press <CR> to start the test: ";
511 
512   {
513     std::string input;
514     std::getline( std::cin, input );
515   }
516 
517   TestAndWriteResults< uint1 >();
518   TestAndWriteResults< uint2 >();
519   TestAndWriteResults< uint3 >();
520 
521   return 0;
522 }
523