Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Collect results and profiles

Collect results

Read per-agent data with a reduction and model-wide data from the environment; both are covered in reading and recording results. To record a trajectory, read after each tick and append a row.

Define each output schema's column names once, next to the function that formats a row, and derive the header from the same list. The macroeconomy example does this in examples/macroeconomy/output.rs: the headline, aggregate-trace, and firm-trace schemas each have a column list and a row builder in one place, and a test asserts that each header is a single line, has unique names, and has the same field count as its row.

A sketch:

const COLUMNS: &[&str] = &["tick", "mean", "variance"];

fn header() -> String {
    COLUMNS.join(",")
}

fn row(tick: u64, stats: &Welford) -> String {
    format!("{},{:.6},{:.6}", tick, stats.mean, stats.variance())
}

Deriving the header and the row from the same list keeps them aligned and lets a test check that the header and its row have the same number of fields.

Collect a profile

Requires the profiling feature.

Capture where a tick spends its time as a Chrome Trace:

syren::init("profile/run.json");
model.run(ticks)?;
syren::shutdown();

Open the JSON in chrome://tracing or Perfetto. The framework's stages and boundaries are already instrumented; add spans in your systems to attribute time to model phases. When the profiling feature is off, the spans compile away, so instrumentation costs nothing in a normal run.

See profiling and performance methodology.