Configuring a simulation

Once you've constructed the plugin configuration objects for your simulation, you can start putting them together in a simulation configuration object (scfg).

Constructing a simulation configuration

A basic simulation with a frontend and a backend can be constructed as follows.

dqcs_handle_t frontend_pcfg = ...;
dqcs_handle_t backend_pcfg = ...;
dqcs_handle_t scfg = dqcs_scfg_new();
dqcs_scfg_push_plugin(scfg, frontend_pcfg);
dqcs_scfg_push_plugin(scfg, backend_pcfg);

The order in which you push plugins doesn't matter, except for operators, which must be pushed in downstream order.

dqcs_scfg_new()

Constructs an empty simulation configuration.

dqcs_handle_t dqcs_scfg_new(void)

Before the configuration can be used, at least a frontend and a backend plugin configuration must be pushed into it. This can be done with dqcs_scfg_push_plugin(). Failing to do this will result in an error when you try to start the simulation.

The default settings correspond to the defaults of the dqcsim command line interface. Refer to its help for more information.

dqcs_scfg_push_plugin()

Appends a plugin to a simulation configuration.

dqcs_return_t dqcs_scfg_push_plugin(
    dqcs_handle_t scfg,
    dqcs_handle_t xcfg
)

Both plugin process and plugin thread configuration objects may be used. The handle is consumed by this function, and is thus invalidated, if and only if it is successful.

Frontend and backend plugins will automatically be inserted at the front and back of the pipeline when the simulation is created. Operators are inserted in front to back order. This function does not provide safeguards against multiple frontends/backends; such errors will only be reported when the simulation is started.

Note that it is not possible to observe or mutate a plugin configuration once it has been added to a simulator configuration handle. If you want to do this for some reason, you should maintain your own data structures, and only build the DQCsim structures from them when you're done.

Random seed

The random seed can be set and queried using the functions below. The default seed is generated using a hash of the most accurate system timestamp available.

dqcs_scfg_seed_set()

Configures the random seed that the simulation should use.

dqcs_return_t dqcs_scfg_seed_set(
    dqcs_handle_t scfg,
    uint64_t seed
)

Note that the seed is randomized by default.

dqcs_scfg_seed_get()

Returns the configured random seed.

uint64_t dqcs_scfg_seed_get(dqcs_handle_t scfg)

This function will return 0 when it fails, but this can unfortunately not be reliably distinguished from a seed that was set to 0.

Reproduction

DQCsim can output a reproduction file for the simulation when the simulation is complete. The recording logic for this system is on by default, since it is recommended to always output such a file. After all, you never know when something unexpected that you might want to reproduce might happen!

By default, the generated reproduction file will specify the plugin executable and script paths as they were generated or specified. However, depending on how you intend to reproduce the simulation later, you may want purely relative or purely absolute paths instead. This can be configured using the following functions.

dqcs_scfg_repro_path_style_set()

Sets the path style used when writing reproduction files.

dqcs_return_t dqcs_scfg_repro_path_style_set(
    dqcs_handle_t scfg,
    dqcs_path_style_t path_style
)
dqcs_scfg_repro_path_style_get()

Returns the path style used when writing reproduction files.

dqcs_path_style_t dqcs_scfg_repro_path_style_get(dqcs_handle_t scfg)

It is also possible to disable the reproduction system. The only benefit this has is to supress the warning message that's generated when a simulation cannot be reproduced, which is the case when plugin threads are used.

dqcs_scfg_repro_disable()

Disables the reproduction logging system.

dqcs_return_t dqcs_scfg_repro_disable(dqcs_handle_t scfg)

Calling this will disable the warnings printed when a simulation that cannot be reproduced is constructed.

Logging configuration

DQCsim has two main log message verbosity filters. The first is configured using dqcs_scfg_dqcsim_verbosity_*(). It controls the filtering of messages generated by the simulation management code, as opposed to the messages received from the various plugins. Like the plugin-specific filters, this defaults to passing all messages through.

dqcs_scfg_dqcsim_verbosity_set()

Configures the logging verbosity for DQCsim's own messages.

dqcs_return_t dqcs_scfg_dqcsim_verbosity_set(
    dqcs_handle_t scfg,
    dqcs_loglevel_t level
)
dqcs_scfg_dqcsim_verbosity_get()

Returns the configured verbosity for DQCsim's own messages.

dqcs_loglevel_t dqcs_scfg_dqcsim_verbosity_get(dqcs_handle_t scfg)

The second filter controls the minimum verbosity that a message must have for it to be written to stderr. This filter defaults to info.

dqcs_scfg_stderr_verbosity_set()

Configures the stderr sink verbosity for a simulation.

dqcs_return_t dqcs_scfg_stderr_verbosity_set(
    dqcs_handle_t scfg,
    dqcs_loglevel_t level
)

That is, the minimum loglevel that a messages needs to have for it to be printed to stderr.

dqcs_scfg_stderr_verbosity_get()

Returns the configured stderr sink verbosity for a simulation.

dqcs_loglevel_t dqcs_scfg_stderr_verbosity_get(dqcs_handle_t scfg)

That is, the minimum loglevel that a messages needs to have for it to be printed to stderr.

It's also possible to have DQCsim pipe all the log messages it receives to a file, optionally with its own verbosity filter. This is configured using dqcs_scfg_tee().

dqcs_scfg_tee()

Configures DQCsim to also output its log messages to a file.

dqcs_return_t dqcs_scfg_tee(
    dqcs_handle_t scfg,
    dqcs_loglevel_t verbosity,
    const char *filename
)

verbosity configures the verbosity level for the file only.

Finally, you can have DQCsim call a callback function whenever it receives a log message. This can be used to tie DQCsim's logging system into whatever different logging system that the host process uses.

dqcs_scfg_log_callback()

Configures DQCsim to also output its log messages to callback function.

dqcs_return_t dqcs_scfg_log_callback(
    dqcs_handle_t scfg,
    dqcs_loglevel_t verbosity,
    void (*callback)(
        void *user_data,
        const char *message,
        const char *logger,
        dqcs_loglevel_t level,
        const char *module,
        const char *file,
        uint32_t line,
        uint64_t time_s,
        uint32_t time_ns,
        uint32_t pid,
        uint64_t tid
    ),
    void (*user_free)(void *user_data),
    void *user_data
)

verbosity specifies the minimum importance of a message required for the callback to be called.

callback is the callback function to install. It is always called with the user_data pointer to make calling stuff like class member functions or closures possible. The user_free function, if non-null, will be called when the callback is uninstalled in any way. If callback is null, any current callback is uninstalled instead. For consistency, if user_free is non-null while callback is null, user_free is called immediately, under the assumption that the caller has allocated resources unbeknownst that the callback it's trying to install is null.

NOTE: both callback and user_free may be called from a thread spawned by the simulator. Calling any API calls from the callback is therefore undefined behavior!

The callback takes the following arguments:

  • void*: user defined data.
  • const char*: log message string, excluding metadata.
  • const char*: name assigned to the logger that was used to produce the message (= "dqcsim" or a plugin name).
  • dqcs_loglevel_t: the verbosity level that the message was logged with.
  • const char*: string representing the source of the log message, or NULL when no source is known.
  • const char*: string containing the filename of the source that generated the message, or NULL when no source is known.
  • uint32_t: line number within the aforementioned file, or 0 if not known.
  • uint64_t: Time in seconds since the Unix epoch.
  • uint32_t: Additional time in nanoseconds since the aforementioned.
  • uint32_t: PID of the generating process.
  • uint64_t: TID of the generating thread.

If an internal log record is particularly malformed and cannot be coerced into the above (nul bytes in the strings, invalid timestamp, whatever) the message is silently ignored.

The primary use of this callback is to pipe DQCsim's messages to an external logging framework. When you do this, you probably also want to call dqcs_scfg_stderr_verbosity_set(handle, DQCS_LOG_OFF) to prevent DQCsim from writing the messages to stderr itself.