Skip to main content

Configuration Guide

Parameter System

ParameterSet

Define parameters with automatic registration and YAML support:

struct CPUParams : public ParameterSet {
Param<uint32_t> fetch_width{this, "fetch_width", 4, "Fetch width per cycle"};
Param<uint32_t> rob_size{this, "rob_size", 128, "Reorder buffer size"};
Param<bool> enable_smt{this, "enable_smt", false, "Enable SMT"};
Param<double> frequency{this, "frequency", 3.0, "Frequency in GHz"};
};

Param Template

template<typename T>
class Param : public ParamBase {
public:
Param(ParameterSet* owner, const std::string& name,
T default_value, const std::string& description = "");

operator const T&() const; // Implicit read
const T& value() const; // Explicit read
Param& operator=(const T& v); // Assignment
};

Usage

void MyUnit::tick() {
uint32_t width = params_->fetch_width; // Implicit conversion

if (params_->enable_smt.value()) {
// SMT logic
}
}

Factory System

AutoRegisteredUnit

Automatic factory registration via CRTP:

class MyUnit : public AutoRegisteredUnit<MyUnit> {
public:
using ParameterSet = MyUnitParams;
static constexpr const char* unit_type_name = "MyUnit";
static constexpr const char* unit_description = "My unit";

// CHRONON_UNIT_CONSTRUCTOR generates factory constructor
CHRONON_UNIT_CONSTRUCTOR(MyUnit, ParameterSet,
params->width, params->depth)
(uint32_t width = 4, uint32_t depth = 8)
: AutoRegisteredUnit("my_unit")
, width_(width), depth_(depth) {}
};

Usage

// Direct C++ instantiation
auto* unit = sim.createUnit<MyUnit>(8, 16);
auto* unit2 = sim.createUnit<MyUnit>(); // Defaults

// YAML factory instantiation (automatic)
// type: MyUnit, params: {width: 8, depth: 16}

SimulationApp

Unified entry point with CLI support:

#include "chronon/Chronon.hpp"

int main(int argc, char* argv[]) {
return chronon::SimulationApp("CPU Simulator")
.setDefaultConfig("config.yaml")
.setConfigSearchPaths({".", "../configs"})
.setVersion("1.0.0")
.onPostBuild([](auto& result) {
// Custom setup after build
})
.run(argc, argv);
}

CLI Options

OptionDescription
[config.yaml]Configuration file
-c, --config <path>Configuration file
-p, --param KEY=VALUEOverride YAML value
-o, --output-dir <path>Override output directory
-n, --run-cycles <N>Override run cycles
-t, --threads <N>Override thread count
--epoch-size <N>Override simulation epoch size in cycles
--no-observeDisable observation
-v, --verboseVerbose output

Examples

./my_sim config.yaml
./my_sim --threads=4 --run-cycles=1000000
./my_sim -p simulation.num_workers=4
./my_sim -p simulation.observation.logging.debug.enabled=false
./my_sim -p simulation.timeline_trace.enabled=true \
-p simulation.timeline_trace.file=out/chronon_timeline.json

YAML Configuration

Basic Structure

simulation:
name: my_simulation
num_workers: 4
enable_parallel: true # Enable parallel execution (requires num_workers > 1)
enable_lookahead: true # Enable lookahead scheduling for parallel epochs
run_cycles: 1000000

unit:
fetch:
type: FetchUnit
params:
fetch_width: 4
port:
out_inst:
to: decode.in_inst
delay: 1

decode:
type: DecodeUnit
params:
decode_width: 4

Observation Configuration

Chronon uses a unified logging model where each event type (debug, info, warn, error, trace) is an independent "channel" with its own enable/format settings. Categories and temporal filters are shared across all channels.

simulation:
observation:
enabled: true
output_dir: "out"
queue_capacity: 262144

counters:
enabled: true
csv_output: true
dump_on_shutdown: true

logging:
enabled: true

# Per-channel configuration
debug:
enabled: true
format: text # text | binary | both
info:
enabled: true
format: text
warn:
enabled: true
format: text
error:
enabled: true
format: text
trace:
enabled: true
format: binary # Binary output for traces
compression:
enabled: true
algorithm: "zstd"
level: 3
block_size: 65536
embed_schema: true
generate_index: true

# Shared temporal filters (apply to all channels)
temporal:
- range: [0, 100000]

# Shared category patterns (apply to all channels)
categories:
- pattern: "icache_*"
temporal:
- range: [0, 50000]
- pattern: "branch_pred"
format: text # Override: route this category to text for all channels
temporal:
- periodic:
window: 1000
period: 10000
- pattern: "flush"

Output Format

Each channel (debug, info, warn, error, trace) can independently route its events to text, binary, or both outputs:

FormatOutput FileDescription
textevents.logHuman-readable text output
binaryevents.ctraceCompact binary format (FlatBuffers + zstd)
bothBoth filesWrite to both text and binary outputs

Files are only created if at least one channel uses that format.

Per-Category Format Overrides

Categories can override the output format for specific channels:

categories:
- pattern: "verif"
format: text # Shorthand: override all channels to text
trace_format: binary # Override: trace channel stays binary
- pattern: "branch_pred"
debug_format: both # Override: debug events for this category go to both

Priority: channel-specific (trace_format) > shorthand (format) > channel default.

Scheduler Timeline Trace

The scheduler timeline is separate from observation logging and counters. It records Chronon scheduler streams, unit tick slices, cross-thread spin waits, epoch spans, and MPSC arbitration slices into Chrome Trace / Perfetto JSON. Worker lane names are zero-based (stream 0, stream 1, ...), while the JSON tid values are 1-based to avoid Perfetto's special handling of tid=0. Each duration event also carries args.stream, the original zero-based logical stream id. The scheduler lane is a separate non-worker row for epoch, rebalance, and MPSC arbitration spans.

simulation:
timeline_trace:
enabled: false
file: chronon_timeline.json
max_events: 1000000
start_cycle: 0
end_cycle: 2000
trace_units: true
trace_waits: true
trace_epochs: true
trace_arbitration: true
min_duration_ns: 0
FieldDescription
enabledEnable timeline collection. Disabled by default.
fileOutput JSON path.
max_eventsEvent cap; additional events are reported as dropped.
start_cycle, end_cycleInclusive start and exclusive end cycle capture window.
trace_unitsRecord each unit tick as a duration slice.
trace_waitsRecord spin waits on predecessor cluster progress atomics.
trace_epochsRecord progress-epoch spans on the scheduler lane.
trace_arbitrationRecord MPSC arbitration spans on the scheduler lane.
min_duration_nsDrop events below this duration.

See Scheduler Timeline Trace for event semantics and Perfetto usage.

Temporal Filters

TypeFormatDescription
Rangerange: [start, end]Enable within cycle range
Periodicperiodic: {window, period, offset}Enable first window cycles every period

Category Patterns

PatternMatches
"*"All categories
"icache_*"icache_hit, icache_miss, etc.
"*_miss"icache_miss, dcache_miss, etc.
"branch"Exact match

Per-Unit Overrides

simulation:
observation:
unit_overrides:
fetch:
logging:
debug:
enabled: true # Enable debug for fetch only
trace:
enabled: true
categories:
- pattern: "*" # Trace all categories for this unit

Runtime Overrides

./my_sim config.yaml \
-p simulation.num_workers=4 \
-p simulation.observation.logging.debug.enabled=false

Type conversion:

  • true, false → boolean
  • All digits → integer
  • Digits with . → double
  • Otherwise → string

Lifecycle Phases

Tree nodes progress through phases:

BUILDING → CONFIGURING → BINDING → FINALIZED
PhaseAllowed Operations
BUILDINGAdd children, modify params
CONFIGURINGModify params, create resources
BINDINGBind ports
FINALIZEDRead-only, run simulation

TreeNode Hierarchy

Path-based addressing with dot notation:

root
├── cpu → "cpu"
│ ├── core0 → "cpu.core0"
│ │ ├── fetch → "cpu.core0.fetch"
│ │ └── decode → "cpu.core0.decode"
│ └── core1 → "cpu.core1"
└── memory → "memory"
node->getChild("cpu.core0.fetch") // Traverses hierarchy