Runtime configuration

Documentation objective

This document explains how to specify runtime configuration values for Aether Engine simulations.


In order to improve iteration speed, it is useful to be able to specify run-time configuration to simulations rather than requiring a full recompile. Distribution of run-time configuration to Aether Engine processes consists of two steps:

  1. Receiving configuration values in the manager process through a mechanism similar to command-line parameters.

  2. Making these parameters available to Aether Engine workers and global state processes as C++ data structures.

Passing options to the manager

Parameters to simulations are defined in the user.cfg file found in the root folder of each demo. Currently two keys are defined:

  • user_bin_args_user_defined

    • user-defined arguments that may be passed to the simulation.
  • log_level

    • specifies the logging level that will be used by Aether. Acceptable values are trace, debug, info, warn, error and fatal. Messages at the specified level or above will be logged.

A user.cfg for a demo might look like the following:

user_bin_args_user_defined = "--elasticity 10 --population-density 12"
log_level = "info"

Aether Engine is not responsible for the parsing of user-defined arguments so alternative arguments formats are possible:

user_bin_args_user_defined = "SCENE=tower ELASTICITY=10"

Parsing arguments in the manager

Accessing user-defined arguments in the manager can be done after initialisation of the process. A call to argument_parse is used to process the contents of argv (which should not be accessed directly) into the aether::arguments type.

int main(int argc, char *argv[]) {
// Initialization of Hadean libraries and logging
const char *process_name = "AE_Manager";
prctl(PR_SET_NAME, process_name);
aether::log::init(process_name, static_cast<uint64_t>(hadean::get_pid()));
AETHER_LOG(INFO)("Initialisation complete");
// Parse arguments supplied to this process
aether::arguments arguments;
arguments.workers = 96;
// Set other default arguments here
argument_parse(argc, argv, &arguments);
// Access the user-defined arguments
const std::vector<std::string> user_args = arguments.user_args;

Passing configuration options to other Aether processes

To pass run-time information to Aether Engine workers and the global state, this information must be encoded as a C++ data type. This type must be serializable using Aether Engine's serialization framework. As an example, we will use a trivially copyable type to carry configuration data as this avoids us have to write the serialization code.

#include <aether/common/serde_derive.hh>
// Contains the run-time configuration
struct demo_parameters {
double elasticity;
size_t world_size;
// Derive serializer and deserializer for trivially copyable type

To provide this argument to Aether Engine workers, we pass it to the build_entity_simulation_manager function after the first two parameters. Any number of additional parameters can be provided, and they will be forwarded to the constructor of the user-defined state class (user_cell_state_impl in this example). Note that the first argument to the constructor of the user-defined state class will be an instance of aether::cell_state, followed by the forwarded arguments.

Similarly, parameters can also be forwarded to the constructor of the global state process (example_global_state in this example):

const demo_parameters params = args_to_params(arguments.user_args);
auto static_args = arguments.to_octree_params<octree_traits>();
// The global state will be constructed with a call to
// example_global_state(const demo_parameters&)
// The manager will be constructed with a call to
// user_cell_state_impl(const aether_cell_state&, const demo_parameters&)
auto manager = aether::build_entity_simulation_manager<user_cell_state_impl>(
arguments.workers, static_args, params