How to carefully handle the library

Introduction

As Said before some compiler options will make the use of the library risky. Here are some explainations. The library do not use pre-allocated buffer to store data instead of many others. The reason is that we want the user to be able to optimize the library to suit the best his needs. On some cases specially on embedded system, every byte count so we do not want to waste any space.

Memory management

Here is how it work:

How to make the work manually

To avoid automatic dynamic reallocation you should allocate the required space manually before allocating new states. Better than words, here is an example:
    StateMachine* stateMachine = allocStateMachine("MyStateMachine", "[Pref]");
    State * S_1, *S_2, *MS_3, *S_3_1, *S_3_2;
    allocateSpaceForStates(stateMachine, 3, stateMachine);
    S_1 = allocateState(stateMachine, "FirstState", stateMachine);
    S_2 = allocateState(stateMachine, "SecondState", stateMachine);
    MS_3 = allocateState(stateMachine, "ThirdState", stateMachine);
    allocateSpaceForStates(MS_3, 2);
    S_3_1 = allocateState(MS_3, "FirstSubState", stateMachine);
    S_3_2 = allocateState(MS_3, "SecondSubState", stateMachine);
    freeStateMachine(stateMachine);
This code is correct. If you want to check if the code you wrote is correct or not, simply set the REALLOC_DBG flag. See The debug section for more information.

For exemple this code:

#include "StateMachine.h"
int main(int argc, char** argv)
{
    StateMachine* stateMachine = allocStateMachine("MyStateMachine", "[Pref]");
    State * S_1, *S_2, *MS_3, *S_3_1, *S_3_2;
    setDbgParam(stateMachine, REALLOC_DBG);
    allocateSpaceForStates(stateMachine, 3);
    S_1 = allocateState(stateMachine, "FirstState", stateMachine);
    S_2 = allocateState(stateMachine, "SecondState", stateMachine);
    MS_3 = allocateState(stateMachine, "ThirdState", stateMachine);
    allocateSpaceForStates(MS_3, 2);
    S_3_1 = allocateState(MS_3, "FirstSubState", stateMachine);
    S_3_2 = allocateState(MS_3, "SecondSubState", stateMachine);
    freeStateMachine(stateMachine);
}
Will generate the following output:
[Pref] Reallocating space for state machine MyStateMachine from 0 to 3
[Pref] In state machine MyStateMachine, reallocating space for state ThirdState from 0 to 2
Lets now changing:
    allocateSpaceForStates(stateMachine, 3);
by
    allocateSpaceForStates(stateMachine, 2);
Note the 2 instead of the 3. Then you will have:
[Pref] Reallocating space for state machine MyStateMachine from 0 to 2
[Pref] Reallocating space for state machine MyStateMachine from 2 to 12
[Pref] In state machine MyStateMachine, reallocating space for state ThirdState from 0 to 2
You can notice that the system had reallocated the space from 2 to 12 automatically. It so mean that 2 was not enough.
Note:
This doesn't mean that the system need at least 12 unit of space but you now know that the real need is between 3 and 12 included.

Transition allocation.

The way you should manage transition allocation is basically the same as for the child states. Use the function void allocateSpaceForTransitions(State* state, int nbTransition) to allocate the space before you call any of the transition creation functions. If you are using the library with the DEACTIVATE_CHECKING option on, you have to allocate the space manually and to avoid to insert multiple transitions with the same ID. If you try to insert different transitions with the same ID the library will react in different way depending which options are on. Now if you really want to optimize the speed during startup you should learn some rules. In this case lets have a look on the following sections.

Advanced theory on transition allocation.

As optimisation really makes sense when MAX_RUNTIME_SPEED is activated we will consider in this section that this option is on.

In this section we will consider the following simple state machine:

SM_4.png

State Machine 4

Now if we want to write the corresponding easiest code we will have:
    StateMachine* stateMachine;
    State* MS_1, *MS1_1, *S1_2, *S11_1, *S11_2, *S2;
    
    stateMachine = allocStateMachine("myOptimizedStateMachine", "[OSM]");
    setDbgParam(stateMachine, REALLOC_DBG);
    MS_1 = allocateState(stateMachine, "MS_1", stateMachine);
    S2 = allocateState(stateMachine, "S2", stateMachine);  
    MS1_1 = allocateState(MS_1, "MS1_1", stateMachine);
    S1_2 = allocateState(MS_1, "S1_2", stateMachine);
    S11_1 = allocateState(MS1_1, "S11_1", stateMachine);
    S11_2 = allocateState(MS1_1, "S11_2", stateMachine);
    
    addTransition(MS1_1, S11_2, 4, 0);
    addTransition(S11_1, MS1_1, 3, 0);
    addTransition(MS1_1, S2, 2, 0);
    addTransition(S11_1, S1_2, 1, 0);
    addTransition(S11_2, S1_2, 1, 0);
    addTransition(S1_2, MS_1, 1, 0);
    addTransition(S2, MS_1, 1, 0);
Lets run the state machine and see what happen:
[OSM] Reallocating space for state machine myOptimizedStateMachine from 0 to 10
[OSM] In state machine myOptimizedStateMachine, reallocating space for state MS_1 from 0 to 10
[OSM] In state machine myOptimizedStateMachine, reallocating space for state MS1_1 from 0 to 10
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state MS1_1 from 0 to 10
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state MS1_1 from 0 to 10
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S11_1 from 0 to 10
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S11_2 from 0 to 10
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S11_1 from 10 to 20
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state S11_1 from 0 to 10
[OSM] In State machine myOptimizedStateMachine, for state S11_1, system have to relocate secondary transitions to insert the new one.
[OSM] In State machine myOptimizedStateMachine, for state MS1_1, system have to relocate transitions to insert the newly allocated one.
[OSM] In State machine myOptimizedStateMachine, for state MS1_1, system have to relocate secondary transitions to insert the new one.
[OSM] In State machine myOptimizedStateMachine, for state S11_1, system have to relocate secondary transitions to insert the new one.
[OSM] In State machine myOptimizedStateMachine, for state S11_2, system have to relocate secondary transitions to insert the new one.
[OSM] In State machine myOptimizedStateMachine, for state S11_1, system have to relocate transitions to insert the newly allocated one.
[OSM] In State machine myOptimizedStateMachine, for state S11_1, system have to relocate secondary transitions to insert the new one.
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S11_2 from 10 to 20
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state S11_2 from 0 to 10
[OSM] In State machine myOptimizedStateMachine, for state S11_2, system have to relocate secondary transitions to insert the new one.
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S1_2 from 0 to 10
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state S1_2 from 0 to 10
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S2 from 0 to 10
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state S2 from 0 to 10
Indeed, this everything but good :) First we will apply want we learned in the first section: manual allocation of space for child states.
    StateMachine* stateMachine;
    State* MS_1, *MS1_1, *S1_2, *S11_1, *S11_2, *S2;
    
    stateMachine = allocStateMachine("myOptimizedStateMachine", "[OSM]");
    setDbgParam(stateMachine, REALLOC_DBG);
    allocateSpaceForStates(stateMachine, 2);   //<<<<<<<Added line
    MS_1 = allocateState(stateMachine, "MS_1", stateMachine);
    S2 = allocateState(stateMachine, "S2", stateMachine);  
    allocateSpaceForStates(MS_1, 2);           //<<<<<<<Added line
    MS1_1 = allocateState(MS_1, "MS1_1", stateMachine);
    S1_2 = allocateState(MS_1, "S1_2", stateMachine);
    allocateSpaceForStates(MS1_1, 2);          //<<<<<<<Added line
    S11_1 = allocateState(MS1_1, "S11_1", stateMachine);
    S11_2 = allocateState(MS1_1, "S11_2", stateMachine);
    
    addTransition(MS1_1, S11_2, 4, 0);
    addTransition(S11_1, MS1_1, 3, 0);
    addTransition(MS1_1, S2, 2, 0);
    addTransition(S11_1, S1_2, 1, 0);
    addTransition(S11_2, S1_2, 1, 0);
    addTransition(S1_2, MS_1, 1, 0);
    addTransition(S2, MS_1, 1, 0);
This if you test this code you will see that the only change is that lines such as:
[OSM] In state machine myOptimizedStateMachine, reallocating space for state MS_1 from 0 to 10
Are now:
[OSM] In state machine myOptimizedStateMachine, reallocating space for state MS_1 from 0 to 2
So lets try to allocate space for the transitions:
    StateMachine* stateMachine;
    State* MS_1, *MS1_1, *S1_2, *S11_1, *S11_2, *S2;
    
    stateMachine = allocStateMachine("myOptimizedStateMachine", "[OSM]");
    setDbgParam(stateMachine, REALLOC_DBG);
    allocateSpaceForStates(stateMachine, 2);
    MS_1 = allocateState(stateMachine, "MS_1", stateMachine);
    S2 = allocateState(stateMachine, "S2", stateMachine);  
    allocateSpaceForStates(MS_1, 2);
    MS1_1 = allocateState(MS_1, "MS1_1", stateMachine);
    S1_2 = allocateState(MS_1, "S1_2", stateMachine);
    allocateSpaceForStates(MS1_1, 2);
    S11_1 = allocateState(MS1_1, "S11_1", stateMachine);
    S11_2 = allocateState(MS1_1, "S11_2", stateMachine);
    
    allocateSpaceForTransitions(S11_1, 2);      //<<<<<<<Added line
    allocateSpaceForTransitions(S11_2, 1);      //<<<<<<<Added line
    allocateSpaceForTransitions(S1_2, 1);       //<<<<<<<Added line
    allocateSpaceForTransitions(S2, 1);         //<<<<<<<Added line
    allocateSpaceForTransitions(MS1_1, 2);      //<<<<<<<Added line
    
    addTransition(MS1_1, S11_2, 4, 0);
    addTransition(S11_1, MS1_1, 3, 0);
    addTransition(MS1_1, S2, 2, 0);
    addTransition(S11_1, S1_2, 1, 0);
    addTransition(S11_2, S1_2, 1, 0);
    addTransition(S1_2, MS_1, 1, 0);
    addTransition(S2, MS_1, 1, 0);
So we obtain:
[OSM] Reallocating space for state machine myOptimizedStateMachine from 0 to 2
[OSM] In state machine myOptimizedStateMachine, reallocating space for state MS_1 from 0 to 2
[OSM] In state machine myOptimizedStateMachine, reallocating space for state MS1_1 from 0 to 2
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S11_1 from 0 to 2
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state S11_1 from 0 to 2
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S11_2 from 0 to 1
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state S11_2 from 0 to 1
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S1_2 from 0 to 1
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state S1_2 from 0 to 1
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S2 from 0 to 1
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state S2 from 0 to 1
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state MS1_1 from 0 to 2
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state MS1_1 from 0 to 2
[OSM] In State machine myOptimizedStateMachine, for state S11_1, system have to relocate secondary transitions to insert the new one.
[OSM] In State machine myOptimizedStateMachine, for state MS1_1, system have to relocate transitions to insert the newly allocated one.
[OSM] In State machine myOptimizedStateMachine, for state MS1_1, system have to relocate secondary transitions to insert the new one.
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S11_1 from 2 to 12
[OSM] In State machine myOptimizedStateMachine, for state S11_1, system have to relocate secondary transitions to insert the new one.
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S11_2 from 1 to 11
[OSM] In State machine myOptimizedStateMachine, for state S11_2, system have to relocate secondary transitions to insert the new one.
[OSM] In State machine myOptimizedStateMachine, for state S11_1, system have to relocate transitions to insert the newly allocated one.
[OSM] In State machine myOptimizedStateMachine, for state S11_1, system have to relocate secondary transitions to insert the new one.
[OSM] In State machine myOptimizedStateMachine, for state S11_2, system have to relocate secondary transitions to insert the new one.
We can clearly see the effect of the lines we added "[OSM] Reallocating space for transitions in state S11_1 from 0 to 2" but we can also notice that the system had reallocated the space later : "[OSM] Reallocating secondary space for transitions in state S11_1 from 2 to 12" So what the real space is not two? The answer is: not completely :)! You might have noticed the keyword 'secondary' in the second sentence. This is in fact a special list managed directly by the system on which you have no means to directly interact with. The system knows perfectly (except if a bug appears) how to handle this list. But as it is nothing more than a program, it can't forecast teh changes you will make in the future so sometimes it have to do some extra work. As it is a lazy but submited program it do the work but complain about it. If you are fed up with this complains you might want to find way to tell the program how to do its work faster.

Simply allocate the space for transition starting with highest level states (states with minimum depth).

So we had this:

    allocateSpaceForTransitions(S11_1, 2);
    allocateSpaceForTransitions(S11_2, 1);
    allocateSpaceForTransitions(S1_2, 1);
    allocateSpaceForTransitions(S2, 1);
    allocateSpaceForTransitions(MS1_1, 2);
And now we write this:
    allocateSpaceForTransitions(MS1_1, 2);
    allocateSpaceForTransitions(S2, 1);
    allocateSpaceForTransitions(S1_2, 1);
    allocateSpaceForTransitions(S11_2, 1);
    allocateSpaceForTransitions(S11_1, 2);
Lets see the effect:
[OSM] Reallocating space for state machine myOptimizedStateMachine from 0 to 2
[OSM] In state machine myOptimizedStateMachine, reallocating space for state MS_1 from 0 to 2
[OSM] In state machine myOptimizedStateMachine, reallocating space for state MS1_1 from 0 to 2
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state MS1_1 from 0 to 2
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state MS1_1 from 0 to 2
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S2 from 0 to 1
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state S2 from 0 to 1
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S1_2 from 0 to 1
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state S1_2 from 0 to 1
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S11_2 from 0 to 3
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state S11_2 from 0 to 1
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S11_1 from 0 to 4
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state S11_1 from 0 to 2
[OSM] In State machine myOptimizedStateMachine, for state S11_1, system have to relocate secondary transitions to insert the new one.
[OSM] In State machine myOptimizedStateMachine, for state MS1_1, system have to relocate transitions to insert the newly allocated one.
[OSM] In State machine myOptimizedStateMachine, for state MS1_1, system have to relocate secondary transitions to insert the new one.
[OSM] In State machine myOptimizedStateMachine, for state S11_1, system have to relocate secondary transitions to insert the new one.
[OSM] In State machine myOptimizedStateMachine, for state S11_2, system have to relocate secondary transitions to insert the new one.
[OSM] In State machine myOptimizedStateMachine, for state S11_1, system have to relocate transitions to insert the newly allocated one.
[OSM] In State machine myOptimizedStateMachine, for state S11_1, system have to relocate secondary transitions to insert the new one.
[OSM] In State machine myOptimizedStateMachine, for state S11_2, system have to relocate secondary transitions to insert the new one.
Perfect, the program stopped to complain about memory space reallocation in the secondary list, however it still complains about weird transition relocation. The problem is that optimized runtime performances require sorted lists and so, the system keeps the lists sorted. To do so, it sometimes have to move some data from a position to another. These are high time-consuming operations so we need to avoid. To avoid these operation just add transitions starting with transition with minimum event ID:
    addTransition(S11_1, S1_2, 1, 0);       //Event #1 first
    addTransition(S11_2, S1_2, 1, 0);
    addTransition(S1_2, MS_1, 1, 0);
    addTransition(S2, MS_1, 1, 0);
    addTransition(MS1_1, S2, 2, 0);         //Then event #2
    addTransition(S11_1, MS1_1, 3, 0);      //Event #3
    addTransition(MS1_1, S11_2, 4, 0);      //And finally event #4
We now have:
[OSM] Reallocating space for state machine myOptimizedStateMachine from 0 to 2
[OSM] In state machine myOptimizedStateMachine, reallocating space for state MS_1 from 0 to 2
[OSM] In state machine myOptimizedStateMachine, reallocating space for state MS1_1 from 0 to 2
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state MS1_1 from 0 to 2
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state MS1_1 from 0 to 2
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S2 from 0 to 1
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state S2 from 0 to 1
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S1_2 from 0 to 1
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state S1_2 from 0 to 1
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S11_2 from 0 to 3
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state S11_2 from 0 to 1
[OSM] In state machine myOptimizedStateMachine, reallocating space for global transitions for state S11_1 from 0 to 4
[OSM] In state machine myOptimizedStateMachine, reallocating space for transitions for state S11_1 from 0 to 2
Which is the best allocation we can make :) The complete code is now:
    StateMachine* stateMachine;
    State* MS_1, *MS1_1, *S1_2, *S11_1, *S11_2, *S2;
    
    stateMachine = allocStateMachine("myOptimizedStateMachine", "[OSM]");
    setDbgParam(stateMachine, REALLOC_DBG);
    allocateSpaceForStates(stateMachine, 2);
    MS_1 = allocateState(stateMachine, "MS_1", stateMachine);
    S2 = allocateState(stateMachine, "S2", stateMachine);  
    allocateSpaceForStates(MS_1, 2);
    MS1_1 = allocateState(MS_1, "MS1_1", stateMachine);
    S1_2 = allocateState(MS_1, "S1_2", stateMachine);
    allocateSpaceForStates(MS1_1, 2);
    S11_1 = allocateState(MS1_1, "S11_1", stateMachine);
    S11_2 = allocateState(MS1_1, "S11_2", stateMachine);
    
    allocateSpaceForTransitions(MS1_1, 2);
    allocateSpaceForTransitions(S2, 1);
    allocateSpaceForTransitions(S1_2, 1);
    allocateSpaceForTransitions(S11_2, 1);
    allocateSpaceForTransitions(S11_1, 2);
    
    addTransition(S11_1, S1_2, 1, 0);
    addTransition(S11_2, S1_2, 1, 0);
    addTransition(S1_2, MS_1, 1, 0);
    addTransition(S2, MS_1, 1, 0);
    addTransition(MS1_1, S2, 2, 0);
    addTransition(S11_1, MS1_1, 3, 0);
    addTransition(MS1_1, S11_2, 4, 0);

Next: How to build the library.

Previous: How to put the debug system in good use.


Generated on Sat Sep 18 15:39:57 2010 for Easy C State Machine by  doxygen 1.5.8