
Hello Boost! This is my review for the MSM library: * What is your evaluation of the design? I've used MSM quite a while. I've already used MSM 1.x and also the new 2.0 since a few weeks. In this time I've written some own state machines, played with the samples contained with MSM 1.x/2.0 and also made some comparisons with the Boost.Statechart library. I've run the state machines I've build on standard desktop PCs as well as on embedded systems (MIPS with ~300 MHz and ARM with ~50 MHz). On all platforms MSM made a good picture and always worked as expected. I'm not a guru in UML state charts but I've tried to use as much features of MSM as I could. * What is your evaluation of the implementation? I've looked into the main parts of the source code of MSM 1.x and a little bit of MSM 2.0. I've welcome the front- and back-end at 2.0 and the omission of the CRTP pattern (CRTP = The Curiously Recurring Template Pattern). My experience in template metaprogramming is quite limited but as I've tortured myself with CRTP a long time I knew that it's handling is quite hard sometimes. The font- and back-end at 2.0 improved the readability of MSM very much. Or should I say it improves the readability of some parts of the MSMs source code!? Because the source code of MSM 2.0 is very hard to read and understand at some places. But it's wonderful to see that metaprogramming stuff working ;-) * What is your evaluation of the documentation? I think that the documentation could be better than it is at the moment. For my taste "one" big documentation isn't nice to read. In Boost there are existing more nicely documentations like Boost.Proto or Boost.Spirit. It's a matter of taste but I think it could be an improvemet for Boost if all libraries documentations has (nearly) the same visual style. But this shouldn't be discussed here at this review. * What is your evaluation of the potential usefulness of the library? I think MSM is very useful for every professional C++ developer. Especially for state machines on embedded systems MSM could be a real improvement with it's O(1) complexity. I've made a comparison of MSM against Boost.Statechart and a state machine generated with IBM's Rational Rhapsody tool. The state machine for this comparison was the simple CD player example delivered with MSM. The results of this comparison and the source code - expected the libraries to build the Rhapsody example - I've attached to this mail. The conclusion at this test was that MSM is about 5 times faster than a state machine generated with IBMs Rational Rhapsody and a state machine with Rhapsody is 4 times faster than a state machine generated with Boost.Statechart. This was very surprisingly for my because I've thought that Boost.Statechart is much faster than the generated state machine with Rhapsody. In contrast to Boost.Statechart, MSM was approximately 20 times faster. Like I've said before I'v used the simple CD player example. A more complex state machine could lead to more interesting results of MSM, Boost.Statechart and Rhapsody. But this need some extra time that I don't have at moment. Another very important fact is that MSM uses very much compiler ressources. The problem here is that state machines with too much states and/or transitions could lead to the situation that the compiler runs out of memory and the state machine couldn't be build. I think this is only a problem of time. Further compiler versions could be more cooperative with MSM than today compilers. I think MSM is perfectly for small and medium static state machines and Boost.Statechart is good for dynamic and very big state machines. But this is only a thesis from myself and I think this should be evaluated in more detail. But this shouldn't be part of this review. A very big improvement for me is the eUML "language" at MSM 2.0. It's takes getting used to use it but I think it's such a cool think that I don't know how I've written state machines before without eUML :-) Ok, a little bit hamed but I think writing state machines with eUML could be such a big improvement for every application. * Did you try to use the library? With what compiler? Did you have any problems? I've used the library for several tests. I've used MSVC 9 and GCC 4.3/4.4. I've detected no problems with MSM. The only "problem" was that mistypes could lead to compiler errors with pages of (useless) informations. But this isn't a problem of MSM. This is more a problem of template metaprogramming. * How much effort did you put into your evaluation? A glance? A quick reading? In-depth study? I've used MSM 1.x quite a long time. For this review I tried to use the new 2.0 and some of the new features (like eUML). I've already tried to use MSM on embedded systems like on MIPS and ARM platform. I've already tried to make a in-depth study but the MSM source code is very hard to understand. * Are you knowledgeable about the problem domain? I'm not a guru in UML state machines but I know the basics and used state machines quite a long time. * Do you think the library should be accepted as a Boost library? Be sure to say this explicitly so that your other comments don't obscure your overall opinion. Yes. I think MSM is an enrichment for Boost. MSM beates IBMs Rational Rhapsody! And the best, it's free, it's metaprogramming and it's Boost :-) Writing state machines make so much fun with MSM and the knowledge that it's O(1) is the best a software developer could wish. Best regards Franz // MsmSimple.cpp : Defines the entry point for the console application. // #include <boost/msm/back/state_machine.hpp> #include <boost/msm/front/state_machine_def.hpp> namespace msm = boost::msm; namespace mpl = boost::mpl; #include <iostream> #ifdef WIN32 #include "windows.h" #else #include <sys/time.h> #endif namespace test_fsm // Concrete FSM implementation { // events struct play {}; struct end_pause {}; struct stop {}; struct pause {}; struct open_close {}; struct cd_detected{}; // Concrete FSM implementation struct player_ : public msm::front::state_machine_def<player_> { // no need for exception handling or message queue typedef int no_exception_thrown; typedef int no_message_queue; // The list of FSM states struct Empty : public msm::front::state<> { // optional entry/exit methods template <class Event,class FSM> void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Empty" << std::endl;*/} template <class Event,class FSM> void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Empty" << std::endl;*/} }; struct Open : public msm::front::state<> { template <class Event,class FSM> void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Open" << std::endl;*/} template <class Event,class FSM> void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Open" << std::endl;*/} }; struct Stopped : public msm::front::state<> { template <class Event,class FSM> void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Stopped" << std::endl;*/} template <class Event,class FSM> void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Stopped" << std::endl;*/} }; struct Playing : public msm::front::state<> { template <class Event,class FSM> void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Playing" << std::endl;*/} template <class Event,class FSM> void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Playing" << std::endl;*/} }; struct Paused : public msm::front::state<> { template <class Event,class FSM> void on_entry(Event const&,FSM& ) {/*std::cout << "entering: Paused" << std::endl;*/} template <class Event,class FSM> void on_exit(Event const&,FSM& ) {/*std::cout << "leaving: Paused" << std::endl;*/} }; // the initial state of the player SM. Must be defined typedef Empty initial_state; // transition actions void start_playback(play const&) { } void open_drawer(open_close const&) { } void close_drawer(open_close const&) { } void store_cd_info(cd_detected const& cd) { } void stop_playback(stop const&) { } void pause_playback(pause const&) { } void resume_playback(end_pause const&) { } void stop_and_open(open_close const&) { } void stopped_again(stop const&) {} // guard conditions typedef player_ p; // makes transition table cleaner // Transition table for player struct transition_table : mpl::vector< // Start Event Next Action Guard // +---------+-------------+---------+---------------------+----------------------+ a_row < Stopped , play , Playing , &p::start_playback >, a_row < Stopped , open_close , Open , &p::open_drawer >, a_row < Stopped , stop , Stopped , &p::stopped_again >, // +---------+-------------+---------+---------------------+----------------------+ a_row < Open , open_close , Empty , &p::close_drawer >, // +---------+-------------+---------+---------------------+----------------------+ a_row < Empty , open_close , Open , &p::open_drawer >, a_row < Empty , cd_detected , Stopped , &p::store_cd_info >, // +---------+-------------+---------+---------------------+----------------------+ a_row < Playing , stop , Stopped , &p::stop_playback >, a_row < Playing , pause , Paused , &p::pause_playback >, a_row < Playing , open_close , Open , &p::stop_and_open >, // +---------+-------------+---------+---------------------+----------------------+ a_row < Paused , end_pause , Playing , &p::resume_playback >, a_row < Paused , stop , Stopped , &p::stop_playback >, a_row < Paused , open_close , Open , &p::stop_and_open > // +---------+-------------+---------+---------------------+----------------------+ > {}; // Replaces the default no-transition response. template <class FSM,class Event> void no_transition(Event const& e, FSM&,int state) { std::cout << "no transition from state " << state << " on event " << typeid(e).name() << std::endl; } }; typedef msm::back::state_machine<player_> player; // // Testing utilities. // static char const* const state_names[] = { "Stopped", "Open", "Empty", "Playing", "Paused" }; void pstate(player const& p) { std::cout << " -> " << state_names[p.current_state()[0]] << std::endl; } } #ifndef WIN32 long mtime(struct timeval& tv1,struct timeval& tv2) { return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec)); } #endif int main() { // for timing #ifdef WIN32 LARGE_INTEGER res; ::QueryPerformanceFrequency(&res); LARGE_INTEGER li,li2; #else struct timeval tv1,tv2; gettimeofday(&tv1,NULL); #endif test_fsm::player p2; p2.start(); // for timing #ifdef WIN32 ::QueryPerformanceCounter(&li); #else gettimeofday(&tv1,NULL); #endif for (int i=0;i</*100*//*1000000*/10000000;++i) { p2.process_event(test_fsm::open_close()); p2.process_event(test_fsm::open_close()); p2.process_event(test_fsm::cd_detected()); p2.process_event(test_fsm::play()); p2.process_event(test_fsm::pause()); // go back to Playing p2.process_event(test_fsm::end_pause()); p2.process_event(test_fsm::pause()); p2.process_event(test_fsm::stop()); // event leading to the same state p2.process_event(test_fsm::stop()); p2.process_event(test_fsm::open_close()); p2.process_event(test_fsm::open_close()); } #ifdef WIN32 ::QueryPerformanceCounter(&li2); #else gettimeofday(&tv2,NULL); #endif #ifdef WIN32 std::cout << "msm took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl; #else std::cout << "msm took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl; #endif return 0; } #include <boost/statechart/event.hpp> #include <boost/statechart/state_machine.hpp> #include <boost/statechart/simple_state.hpp> #include <boost/statechart/transition.hpp> #include "boost/mpl/list.hpp" #include <vector> #include <iostream> #ifdef WIN32 #include "windows.h" #else #include <sys/time.h> #endif namespace sc = boost::statechart; namespace mpl = boost::mpl; namespace test_sc { //events struct play : sc::event< play > {}; struct end_pause : sc::event< end_pause > {}; struct stop : sc::event< stop > {}; struct pause : sc::event< pause > {}; struct open_close : sc::event< open_close > {}; struct cd_detected : sc::event< cd_detected > {}; struct Empty; struct Open; struct Stopped; struct Playing; struct Paused; // SM struct player : sc::state_machine< player, Empty > { void open_drawer(open_close const&) { /*std::cout << "player::open_drawer\n";*/ } void store_cd_info(cd_detected const& cd) {/*std::cout << "player::store_cd_info\n";*/ } void close_drawer(open_close const&) { /*std::cout << "player::close_drawer\n";*/ } void start_playback(play const&) { /*std::cout << "player::start_playback\n";*/ } void stopped_again(stop const&) {/*std::cout << "player::stopped_again\n";*/} void stop_playback(stop const&) { /*std::cout << "player::stop_playback\n";*/ } void pause_playback(pause const&) { /*std::cout << "player::pause_playback\n"; */} void stop_and_open(open_close const&) { /*std::cout << "player::stop_and_open\n";*/ } void resume_playback(end_pause const&) { /*std::cout << "player::resume_playback\n";*/ } }; struct Empty : sc::simple_state< Empty, player > { Empty() { /*std::cout << "entering Empty" << std::endl;*/ } // entry ~Empty() { /*std::cout << "leaving Empty" << std::endl;*/ } // exit typedef mpl::list< sc::transition< open_close, Open, player, &player::open_drawer >, sc::transition< cd_detected, Stopped, player, &player::store_cd_info > > reactions; }; struct Open : sc::simple_state< Open, player > { Open() { /*std::cout << "entering Open" << std::endl;*/ } // entry ~Open() { /*std::cout << "leaving Open" << std::endl;*/ } // exit typedef sc::transition< open_close, Empty, player, &player::close_drawer > reactions; }; struct Stopped : sc::simple_state< Stopped, player > { Stopped() { /*std::cout << "entering Stopped" << std::endl;*/ } // entry ~Stopped() { /*std::cout << "leaving Stopped" << std::endl;*/ } // exit typedef mpl::list< sc::transition< play, Playing, player, &player::start_playback >, sc::transition< open_close, Open, player, &player::open_drawer >, sc::transition< stop, Stopped, player, &player::stopped_again > > reactions; }; struct Playing : sc::simple_state< Playing, player > { Playing() { /*std::cout << "entering Playing" << std::endl;*/ } // entry ~Playing() { /*std::cout << "leaving Playing" << std::endl;*/ } // exit typedef mpl::list< sc::transition< stop, Stopped, player, &player::stop_playback >, sc::transition< pause, Paused, player, &player::pause_playback >, sc::transition< open_close, Open, player, &player::stop_and_open > > reactions; }; struct Paused : sc::simple_state< Paused, player > { Paused() { /*std::cout << "entering Paused" << std::endl;*/ } // entry ~Paused() { /*std::cout << "leaving Paused" << std::endl;*/ } // exit typedef mpl::list< sc::transition< end_pause, Playing, player, &player::resume_playback >, sc::transition< stop, Stopped, player, &player::stop_playback >, sc::transition< open_close, Open, player, &player::stop_and_open > > reactions; }; } #ifndef WIN32 long mtime(struct timeval& tv1,struct timeval& tv2) { return (tv2.tv_sec-tv1.tv_sec) *1000000 + ((tv2.tv_usec-tv1.tv_usec)); } #endif int main() { test_sc::player p; p.initiate(); // for timing #ifdef WIN32 LARGE_INTEGER res; ::QueryPerformanceFrequency(&res); LARGE_INTEGER li,li2; ::QueryPerformanceCounter(&li); #else struct timeval tv1,tv2; gettimeofday(&tv1,NULL); #endif for (int i=0;i</*100*//*1000000*/10000000;++i) { p.process_event(test_sc::open_close()); p.process_event(test_sc::open_close()); p.process_event(test_sc::cd_detected()); p.process_event(test_sc::play()); p.process_event(test_sc::pause()); // go back to Playing p.process_event(test_sc::end_pause()); p.process_event(test_sc::pause()); p.process_event(test_sc::stop()); // event leading to the same state p.process_event(test_sc::stop()); p.process_event(test_sc::open_close()); p.process_event(test_sc::open_close()); } #ifdef WIN32 ::QueryPerformanceCounter(&li2); #else gettimeofday(&tv2,NULL); #endif #ifdef WIN32 std::cout << "sc took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl; #else std::cout << "sc took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl; #endif return 0; } // player.cpp : Defines the entry point for the console application. // #ifdef WIN32 #include "windows.h" #else #include <sys/time.h> #endif #include "Player.h" int main() { // for timing #ifdef WIN32 LARGE_INTEGER res; ::QueryPerformanceFrequency(&res); LARGE_INTEGER li,li2; #else struct timeval tv1,tv2; gettimeofday(&tv1,NULL); #endif Player p; p.startBehavior(); // for timing #ifdef WIN32 ::QueryPerformanceCounter(&li); #else gettimeofday(&tv1,NULL); #endif for (int i=0;i</*100*//*1000000*/10000000;++i) { open_close oc1; p.handleEvent(&oc1); open_close oc2; p.handleEvent(&oc2); cd_detected cd; p.handleEvent(&cd); play pl; p.handleEvent(&pl); pause pa1; p.handleEvent(&pa1); // go back to Playing end_pause ep; p.handleEvent(&ep); pause pa2; p.handleEvent(&pa2); stop st1; p.handleEvent(&st1); // event leading to the same state stop st2; p.handleEvent(&st2); open_close oc3; p.handleEvent(&oc3); open_close oc4; p.handleEvent(&oc4); } #ifdef WIN32 ::QueryPerformanceCounter(&li2); #else gettimeofday(&tv2,NULL); #endif #ifdef WIN32 std::cout << "rhapsody took in s:" << (double)(li2.QuadPart-li.QuadPart)/res.QuadPart <<"\n" <<std::endl; #else std::cout << "rhapsody took in us:" << mtime(tv1,tv2) <<"\n" <<std::endl; #endif //p.handleEvent(new open_close); return 0; } /******************************************************************** Rhapsody : 7.5 Login : Component : DefaultComponent Configuration : DefaultConfig Model Element : Default //! Generated Date : Wed, 2, Dec 2009 File Path : DefaultComponent\DefaultConfig\Default.cpp *********************************************************************/ //## auto_generated #include "Default.h" //## auto_generated #include "Player.h" //## package Default //## event cd_detected() cd_detected::cd_detected() { setId(cd_detected_Default_id); } bool cd_detected::isTypeOf(short id) const { return (cd_detected_Default_id==id); } //## event stop() stop::stop() { setId(stop_Default_id); } bool stop::isTypeOf(short id) const { return (stop_Default_id==id); } //## event play() play::play() { setId(play_Default_id); } bool play::isTypeOf(short id) const { return (play_Default_id==id); } //## event pause() pause::pause() { setId(pause_Default_id); } bool pause::isTypeOf(short id) const { return (pause_Default_id==id); } //## event end_pause() end_pause::end_pause() { setId(end_pause_Default_id); } bool end_pause::isTypeOf(short id) const { return (end_pause_Default_id==id); } //## event open_close() open_close::open_close() { setId(open_close_Default_id); } bool open_close::isTypeOf(short id) const { return (open_close_Default_id==id); } /********************************************************************* File Path : DefaultComponent\DefaultConfig\Default.cpp *********************************************************************/ /********************************************************************* Rhapsody : 7.5 Login : Component : DefaultComponent Configuration : DefaultConfig Model Element : Default //! Generated Date : Wed, 2, Dec 2009 File Path : DefaultComponent\DefaultConfig\Default.h *********************************************************************/ #ifndef Default_H #define Default_H //## auto_generated #include <oxf\oxf.h> //## auto_generated #include <oxf\event.h> //## auto_generated class Player; //#[ ignore #define cd_detected_Default_id 18601 #define stop_Default_id 18602 #define play_Default_id 18603 #define pause_Default_id 18604 #define end_pause_Default_id 18605 #define open_close_Default_id 18606 //#] //## package Default //## event cd_detected() class cd_detected : public OMEvent { //// Constructors and destructors //// public : //## auto_generated cd_detected(); //// Framework operations //// //## statechart_method bool isTypeOf(short id) const; }; //## event stop() class stop : public OMEvent { //// Constructors and destructors //// public : //## auto_generated stop(); //// Framework operations //// //## statechart_method bool isTypeOf(short id) const; }; //## event play() class play : public OMEvent { //// Constructors and destructors //// public : //## auto_generated play(); //// Framework operations //// //## statechart_method bool isTypeOf(short id) const; }; //## event pause() class pause : public OMEvent { //// Constructors and destructors //// public : //## auto_generated pause(); //// Framework operations //// //## statechart_method bool isTypeOf(short id) const; }; //## event end_pause() class end_pause : public OMEvent { //// Constructors and destructors //// public : //## auto_generated end_pause(); //// Framework operations //// //## statechart_method bool isTypeOf(short id) const; }; //## event open_close() class open_close : public OMEvent { //// Constructors and destructors //// public : //## auto_generated open_close(); //// Framework operations //// //## statechart_method bool isTypeOf(short id) const; }; #endif /********************************************************************* File Path : DefaultComponent\DefaultConfig\Default.h *********************************************************************/ /******************************************************************** Rhapsody : 7.5 Login : Component : DefaultComponent Configuration : DefaultConfig Model Element : Player //! Generated Date : Tue, 1, Dec 2009 File Path : DefaultComponent\DefaultConfig\Player.cpp *********************************************************************/ //## auto_generated #include <oxf\omthread.h> //## auto_generated #include "Player.h" //## package Default //## class Player Player::Player(IOxfActive* theActiveContext) { setActiveContext(theActiveContext, false); initStatechart(); } Player::~Player() { } bool Player::startBehavior() { bool done = false; done = OMReactive::startBehavior(); return done; } void Player::initStatechart() { rootState_subState = OMNonState; rootState_active = OMNonState; } void Player::rootState_entDef() { { rootState_subState = Empty; rootState_active = Empty; } } IOxfReactive::TakeEventStatus Player::rootState_processEvent() { IOxfReactive::TakeEventStatus res = eventNotConsumed; switch (rootState_active) { case Empty: { if(IS_EVENT_TYPE_OF(open_close_Default_id)) { //#[ transition 12 //open_drawer; //#] rootState_subState = Open; rootState_active = Open; res = eventConsumed; } else if(IS_EVENT_TYPE_OF(cd_detected_Default_id)) { //#[ transition 1 //store_cd_info; //#] rootState_subState = Stopped; rootState_active = Stopped; res = eventConsumed; } } break; case Open: { if(IS_EVENT_TYPE_OF(open_close_Default_id)) { //#[ transition 11 //close_drawer; //#] rootState_subState = Empty; rootState_active = Empty; res = eventConsumed; } } break; case Stopped: { if(IS_EVENT_TYPE_OF(open_close_Default_id)) { //#[ transition 9 //open_drawer; //#] rootState_subState = Open; rootState_active = Open; res = eventConsumed; } else if(IS_EVENT_TYPE_OF(stop_Default_id)) { //#[ transition 2 //stopped_again; //#] rootState_subState = Stopped; rootState_active = Stopped; res = eventConsumed; } else if(IS_EVENT_TYPE_OF(play_Default_id)) { //#[ transition 3 //start_playback; //#] rootState_subState = Playing; rootState_active = Playing; res = eventConsumed; } } break; case Paused: { if(IS_EVENT_TYPE_OF(open_close_Default_id)) { //#[ transition 8 //stop_and_open; //#] rootState_subState = Open; rootState_active = Open; res = eventConsumed; } else if(IS_EVENT_TYPE_OF(stop_Default_id)) { //#[ transition 7 //stop_playback; //#] rootState_subState = Stopped; rootState_active = Stopped; res = eventConsumed; } else if(IS_EVENT_TYPE_OF(end_pause_Default_id)) { //#[ transition 6 //resume_playback; //#] rootState_subState = Playing; rootState_active = Playing; res = eventConsumed; } } break; case Playing: { if(IS_EVENT_TYPE_OF(open_close_Default_id)) { //#[ transition 10 //stop_and_open; //#] rootState_subState = Open; rootState_active = Open; res = eventConsumed; } else if(IS_EVENT_TYPE_OF(stop_Default_id)) { //#[ transition 4 //stop_playback; //#] rootState_subState = Stopped; rootState_active = Stopped; res = eventConsumed; } else if(IS_EVENT_TYPE_OF(pause_Default_id)) { //#[ transition 5 //pause_playback; //#] rootState_subState = Paused; rootState_active = Paused; res = eventConsumed; } } break; default: break; } return res; } /********************************************************************* File Path : DefaultComponent\DefaultConfig\Player.cpp *********************************************************************/ /********************************************************************* Rhapsody : 7.5 Login : Component : DefaultComponent Configuration : DefaultConfig Model Element : Player //! Generated Date : Tue, 1, Dec 2009 File Path : DefaultComponent\DefaultConfig\Player.h *********************************************************************/ #ifndef Player_H #define Player_H //## auto_generated #include <oxf\oxf.h> //## auto_generated #include "Default.h" //## auto_generated #include <oxf\omreactive.h> //## auto_generated #include <oxf\state.h> //## auto_generated #include <oxf\event.h> //## package Default //## class Player class Player : public OMReactive { //// Constructors and destructors //// public : //## auto_generated Player(IOxfActive* theActiveContext = 0); //## auto_generated ~Player(); //// Additional operations //// //## auto_generated virtual bool startBehavior(); protected : //## auto_generated void initStatechart(); //// Framework operations //// public : // rootState: //## statechart_method inline bool rootState_IN() const; //## statechart_method virtual void rootState_entDef(); //## statechart_method virtual IOxfReactive::TakeEventStatus rootState_processEvent(); // Stopped: //## statechart_method inline bool Stopped_IN() const; // Playing: //## statechart_method inline bool Playing_IN() const; // Paused: //## statechart_method inline bool Paused_IN() const; // Open: //## statechart_method inline bool Open_IN() const; // Empty: //## statechart_method inline bool Empty_IN() const; //// Framework //// protected : //#[ ignore enum Player_Enum { OMNonState = 0, Stopped = 1, Playing = 2, Paused = 3, Open = 4, Empty = 5 }; int rootState_subState; int rootState_active; //#] }; inline bool Player::rootState_IN() const { return true; } inline bool Player::Stopped_IN() const { return rootState_subState == Stopped; } inline bool Player::Playing_IN() const { return rootState_subState == Playing; } inline bool Player::Paused_IN() const { return rootState_subState == Paused; } inline bool Player::Open_IN() const { return rootState_subState == Open; } inline bool Player::Empty_IN() const { return rootState_subState == Empty; } #endif /********************************************************************* File Path : DefaultComponent\DefaultConfig\Player.h *********************************************************************/ CD-Player example Each test was executed several times. The times are accumulated and divided by the amount of executed test runs to build an median value. ============================================================================== 100 loops of 11 transitions (10 runs) sc took in s:0.00039614 sc took in s:0.000461721 sc took in s:0.000461721 sc took in s:0.000553632 sc took in s:0.000485257 sc took in s:0.000415276 sc took in s:0.000773003 sc took in s:0.000579124 sc took in s:0.000709448 sc took in s:0.00036513 --> ~ 0.000520045 s msm took in s:1.04762e-005 msm took in s:8.93968e-006 msm took in s:8.24127e-006 msm took in s:8.31111e-006 msm took in s:9.91746e-006 msm took in s:2.31873e-005 msm took in s:2.22095e-005 msm took in s:8.38095e-006 msm took in s:1.66222e-005 msm took in s:2.08825e-005 --> ~ 1.37E-05 s rhapsody took in s:4.5746e-005 rhapsody took in s:5.28e-005 rhapsody took in s:8.73714e-005 rhapsody took in s:8.73016e-005 rhapsody took in s:5.27302e-005 rhapsody took in s:6.19492e-005 rhapsody took in s:5.27302e-005 rhapsody took in s:6.92825e-005 rhapsody took in s:4.59556e-005 rhapsody took in s:5.27302e-005 --> ~ 6.09E-05 s Result for 100 * 11 transitions: SC 0.5200 ms Rhapsody 0.0609 ms MSM 0.0137 ms ============================================================================== 1000000 loops of 11 transitions (3 runs) sc took in s:1.93943 sc took in s:1.93943 sc took in s:1.99496 --> ~ 1.95794 s msm took in s:0.0741568 msm took in s:0.0988071 msm took in s:0.0772959 --> ~ 0.08341 s rhapsody took in s:0.453220 rhapsody took in s:0.541500 rhapsody took in s:0.474185 --> ~ 0.48964 s Result for 1000000 * 11 transitions: SC 1.95794 s Rhapsody 0.48964 s MSM 0.08341 s ============================================================================== 10000000 loops of 11 transitions (3 runs) sc took in s:19.5358 sc took in s:19.6668 sc took in s:19.7063 --> ~ 19.6363 s msm took in s:1.059320 msm took in s:0.792874 msm took in s:0.870431 --> ~ 0.90754 s rhapsody took in s:4.95632 rhapsody took in s:5.02131 rhapsody took in s:4.87564 --> ~ 4.95109 s Result for 10000000 * 11 transitions: SC 19.63630 s Rhapsody 4.95109 s MSM 0.90754 s
participants (1)
-
Franz Alt