Performance.cpp 14 KB

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