Comment on page
This section only applies to versions 4.2 and later.
Beginning with version 4.2 of Simulate, cell initialisation now occurs asynchronously to the main simulation; that is, the simulation will continue to execute whilst cell workers are spawned and initialised in the background. In previous versions, the simulation would block whilst cell workers were initialised and entity handover was completed which in some cases could cause noticeable delays - particularly if additional machines were required to be spawned, or if user code loaded external libraries or data. This section explains the asynchronous behaviour and how to configure or disable it if required.
Cell initialisation - or more completely, the spawning of additional worker processes across one or more extant or new machines and the setting up of their initial state - can occur in the following situations during a simulation:
- A cell divides as a result of the load factor increasing beyond the split threshold
- An entity moves into a region of unmanaged space
- Two cells merge as a result of the load factor dropping below the merge threshold
Simulate meets demand for additional cells by maintaining a worker pool.
The Simulate engine worker pool and how it behaves in each of these scenarios is outlined in the remainder of this section.
Simulate Engine maintains a pool of worker processes on standby ready to be brought into the simulation when required. If the number of standby processes falls below a certain threshold, new workers are spawned asynchronously.
As part of the spawning process, the
user_stateobject will be created. You can initialise custom code in
user_state::initialise_cellproviding that the code does not require access to any cell-specfic information as the worker is not currently simulating an active cell.
Any resources created in
user_state::initialise_cellmust be cleaned up in
user_state::deinitialise_cellas the user_state object can be re-used with different workers.
/* If the ratio of available workers in the worker pool drops below
this value, we will try to spawn more workers when refilling the pool */
// Specify the maximum number of workers to spawn when refilling the worker pool
Cell division occurs when a worker reports an estimated load above the configured threshold (see previous section Simulation Lifecyle). New workers will be initialised asynchronously to replace the current overloaded one.
user_state::intialise_cell(...)will be called and you will have access to cell-specific area information, as the worker is now aware of the area it will be simulating. The
get_tick()function will return the tick at which the split operation started.
get_tick()may return a different value if called at the entry and exit of
intialise_celldepending on how far the simulation has progressed whilst cell initialisation is in progress. If you need to refer to the value of
get_tick()at different points in your custom initialisation code, it's recommended that you save it to a variable on entry.
Once the new worker(s) have completed initialisation, the are added to the simulation, entities are handed over from the originating cell, and the worker process for the originating cell will be returned to the worker pool after
As this process is executed asynchronously, the simulation does not pause whilst additional workers are initialised.
As with the Worker Pool, configuration is done within octree_params:
/* Threshold for splitting the worker cells as returned from
Cell merging occurs when the combined load of a group of workers falls below the threshold at which they are configured to merge. At this point, one worker process will be initialised to take over from the currently underutilised processes.
If there are no worker processes available, the specified merge threshold will be overridden and incrementally increase until it reaches the split threshold. This will cause more cells to merge and free some worker processes to cover new simulation areas.
The merge threshold is specified within octree_params:
/* Threshold for merging the worker cells as returned from
When an entity moves outside of the area currently managed by existing cells - i.e. outside of the entire simulated area - a new worker will be initialised to cover that area.
As the new workers are being set up, the entity will continue to be simulated in its current cell even though it is outside the cell boundary. If your user code is unable to handle this behaviour - for example, due to an external library or data dependency - asynchronous worker creation for new areas should be disabled (see below).
Note that if two or more entities move outside of their respective cell boundaries, they may not be aware of each other despite being close together as they are managed by separate worker processes until the new area cell is fully initialised.