Skip to content

entt-dev/FSM

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Clone

if using git 2.13+

git clone --recurse-submodules -j8 https://github.com/entt-dev/FSM.git

Linux Build

Debug Build

cd build
cmake ..
make -j 4

Release Build

cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j 4

For testing and benchmarking

make test
make bench

Goals

Most FSM implementations operate on a per-agent basis. At least for me, that meant running the FSM pipeline for every agent (in parallel). This would approximately look something like this:

for agent in agents:
  state = getState(agent)
  testForNewState(state)
  if state.changed():
    performTransition(agent)

However even if the agents are sorted by state, this will probably lead to a lot of random-access across the ECS registry. To take full advantage of the ECS layout, one can instead operate on a per-state basis. This could then become more like:

for state in states:
  testForNewStates(state)
  performTransitionsForChangedStates(states)

The cpu likes it when we do things over and over, so the closer we are to running the same test function on the same state component, the higher performance we should expect. If sets of states are guaranteed to be mutually exclusive to one-another, so that an agent cannot be in two states of the same set, then that means we can parallelize the transition testing of each state.

Release Benchmarks

  • Around 777us for 10,000 agent test-case on 8-core machine when running OMP_NUM_THREADS=1 agents
  • Around 537us for 10,000 agent test-case on 8-core machine when running OMP_NUM_THREADS=1 states

So yes, maybe like 30% speed-up on read-heavy operations when running by grouped states vs. switch case on every agent. I suppose this is a good thing when considering that much of the FSM is inspecting other data and not necessarily writing.

Thread safety

Useful rules to keep in mind.

Rule 1: When updating the registry during the FSM process, only the agent being tested can be updated. An agent having its state updated cannot update other states at the same time. This is up to the developer to enforce. Only the EntityState component should really ever need to be updated. The function objects that are being run however can theoretically be stateful since they're not interacting with anything else.

Rule 2: No signals should be emitted during the parallel sections.

Assigning / removing state component tags needs to occur on a single thread if the tags are being used in may different groups. If the assigning and removing tags becomes significant, then it may start making more sense reverting back to views. It's something the user will have to decide, since this is dependent on the frequency of state changes and the frequency of entity construction/destruction.

TODO

  • Demonstrate forcing state transitions.

Releases

No releases published

Packages

No packages published