RE: [boost] ANN: review of FSM library starts

I think the library should be accepted in boost. Comments below.
-----Original Message----- From: boost-bounces@lists.boost.org [mailto:boost-bounces@lists.boost.org] On Behalf Of Pavel Vozenilek Sent: Monday, February 21, 2005 11:31 AM To: boost@lists.boost.org Subject: [boost] ANN: review of FSM library starts
[snip]
* What is your evaluation of the documentation? How easy (or hard) it is to understand library features? What can be improved?
The tutorial is good. The few times I've needed the reference, it has been sufficient.
* What is your evaluation of the design? What features are supported better by alternative FSMs? What could be added (or removed) from the library?
Three appealing features of boost::fsm for me are: - No code generation - Hierarchical. - State local data ('state is an object'). In my application (5 state machines, each with 8 - 40 states), I was able to use the fsm to manage the lifetime of objects local to the state (and any inner states). To me, it seems natural that states have the option of 'owning' information. Managing the lifetime and access rights of some 50+ variables used by a state machine would be unpleasant. I think that custom_reactions that act like guards should be discouraged, as they effectively hide part of the state chart in the implementation. When I read a particular fsm, I want to be able to clearly see all possible transitions and actions without having to search through any decision logic code to fill in the gaps. We should be able to specify guards as part of the state definition. Something like this: struct StState: fsm::simple_state<StState,StOuter, mpl::list < fsm::guard2<EvEvent, fsm::switch<StRes0,StRes0ActCtxt,&StRes0ActCtxt::Action0>, fsm::switch<StRes1,StRes1ActCtxt,&StRes1ActCtxt::Action1> >
;
I guess this might make the cpp code look like this: fsm::guard2::result StState::guard2(const EvEvent& ev) { if(cond) return fsm::guard2::result<0>(); else return fsm::guard2::result<1>(); } I haven't thought about the implementation too much admittedly. Having this would be a big help in automatically generating UML state charts.
* The library documentation contains few not yet solved issues (name, separating the library into two parts, exception handling). What is you opinion here?
I have no opinion on the possibility of splitting the library in two. I've avoided using the exception handling feature of boost::fsm, but the description in the documentation looks fairly sensible.
* What is your evaluation of the implementation? Are there parts of code too obscure or duplicating exiting Boost functionality? Can something be factored out to standalone library or among general utilities?
Implementation appears concise. No real concerns here. I was able to add a new type of reaction (in_state_transition - trivial though it is) with no problems.
* Are there performance bottlenecks? Does the library design fit requirements of real-time systems? How is it useable for embedded systems? Is the documentation clear on performance tradeoffs?
The library produces large binaries. It does however, appear to scale reasonably well (anecdotally, it seems about linear with the number of states). The in memory footprint is of the same order of magnitude as the binary size. My application is fairly soft real time, and runs on an embedded 486-like system, with a few hundred individual state machines and a few hundred events delivered per second. In this case, the performance of boost::fsm is acceptable, and does not threaten any timing constraints of the system.
* What is your evaluation of the potential usefulness of the library? Can you compare this FSM to other implementations?
The library has already been useful, and I see myself using the library again. I believe that boost::fsm is a good solution for many non trivial compile time fsms.
* Did you try to use the library? With what compiler? Did you have any problems? Do you have tips for better support of older compilers? What are possible portability problems?
I've been using an older version of the library with gcc-3.2.3
* How much effort did you put into your evaluation? A glance? A quick reading? In-depth study?
I've spent quite a few hours developing using boost::fsm, and about half an hour catching up the on the latest documentation.
* Are you knowledgeable about the problem domain?
Not overly. I've built state machines with switch(), and have had to build a flat dynamic fsm framework (and use it) in the past.
And finally, every reviewer should answer this question:
* 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 Simon Gittins ########################################################################## This e-mail is for the use of the intended recipient(s) only. If you have received this e-mail in error, please notify the sender immediately and then delete it. If you are not the intended recipient, you must not use, disclose or distribute this e-mail without the author's prior permission. We have taken precautions to minimise the risk of transmitting software viruses, but we advise you to carry out your own virus checks on any attachment to this message. We cannot accept liability for any loss or damage caused by software viruses. ##########################################################################

Hi Simon Thanks for your review!
I think that custom_reactions that act like guards should be discouraged, as they effectively hide part of the state chart in the implementation.
That is true if you define the react function outside the state subtype. However, it is often possible to define it right inside the state subtype body where it can be seen by anyone browsing the states.
When I read a particular fsm, I want to be able to clearly see all possible transitions and actions without having to search through any decision logic code to fill in the gaps.
Given that you implement the react function inline, I think that custom_reactions are easier to understand than any special guard reaction.
We should be able to specify guards as part of the state definition. Something like this:
struct StState: fsm::simple_state<StState,StOuter, mpl::list < fsm::guard2<EvEvent, fsm::switch<StRes0,StRes0ActCtxt,&StRes0ActCtxt::Action0>, fsm::switch<StRes1,StRes1ActCtxt,&StRes1ActCtxt::Action1>
;
I guess this might make the cpp code look like this:
fsm::guard2::result StState::guard2(const EvEvent& ev) { if(cond) return fsm::guard2::result<0>(); else return fsm::guard2::result<1>(); }
The equivalent with a custom reaction would look as follows: struct StState : fsm::simple_state< StState, StOuter, fsm::custom_reaction< EvEvent > > { fsm::result react( const EvEvent & evt ) { if ( cond ) return transit< StRes0 >( &StRes0ActCtxt::Action0, evt ); else return transit< StRes1 >( &StRes1ActCtxt::Action1, evt ); } }; For a human, IMHO this is easier to read.
I haven't thought about the implementation too much admittedly. Having this would be a big help in automatically generating UML state charts.
Agreed. It is much easier to implement a tool that only needs to look at the state declarations than one that additionally also needs to analyze code inside functions. For this reason I think I will eventually add a construct similar to the one you suggested. But, since such a tool does not yet exist (to my knowledge), this is of fairly low priority at the moment.
* Are there performance bottlenecks? Does the library design fit requirements of real-time systems? How is it useable for embedded systems? Is the documentation clear on performance tradeoffs?
The library produces large binaries.
The produced binaries certainly will never be small. Out of curiosity, do you have any numbers (number of states -> size of executable)?
It does however, appear to scale reasonably well (anecdotally, it seems about linear with the number of states). The in memory footprint is of the same order of magnitude as the binary size.
I guess that is for the hundreds of machine objects you mention below? A single machine object of even a very complex FSM should not use more than 1KB (not counting state-local variables).
My application is fairly soft real time, and runs on an embedded 486-like system, with a few hundred individual state machines and a few hundred events delivered per second. In this case, the performance of boost::fsm is acceptable, and does not threaten any timing constraints of the system.
Thanks again & Best Regards, -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.

"Andreas Huber" wrote:
The library produces large binaries.
The produced binaries certainly will never be small. Out of curiosity, do you have any numbers (number of states -> size of executable)?
GCC is known to produce huge executables in debug mode. For example a Spirit grammar made it to 45MB (and order of magnitude smaller in release mode). /Pavel

Hi Pavel
The produced binaries certainly will never be small. Out of curiosity, do you have any numbers (number of states -> size of executable)? GCC is known to produce huge executables in debug mode.
I noticed that also, but I guess Simon meant the release mode executables. The situation is much better in release mode, at least on Windows: Compiling the boost::fsm examples with GCC invariably results in executables ~200KB bigger than compiled with MSVC7.1. I'm not sure why this offset exists, maybe one could get rid of it by specifying different command-line switches. Regards, -- Andreas Huber When replying by private email, please remove the words spam and trap from the address shown in the header.
participants (3)
-
Andreas Huber
-
Pavel Vozenilek
-
Simon Gittins