Skip to main content
Cerulion reads your graph file’s topology and each node’s trigger policy before a run; the graph determines execution order rather than the OS scheduler. That gives you a user-visible execution plan: which nodes share a level, which topics trigger the next level, and which process group owns each level band.

See the order your graph derives

Levelization follows the graph’s triggering edges. A camera publishes an image, the detector fires when that image arrives, and a downstream node runs after the detector’s output reaches its trigger input. Figure: Triggering topic edges carry a camera frame through the graph in a derived order. Run the read-only inspection command from your workspace:
The command prints the graph identity, the levelization source, a node and level count, one line per level with each node’s trigger policy, and triggering topic edges leaving each level:
The graph file supplies the prefix: value; if it is omitted, Cerulion derives it from the hostname, so robot1 and the topic names in this sample are illustrative. If the graph contains process_groups:, the report also prints the number of groups, each group’s rank, its owned level band, its node members, and a partition verdict.

Trigger policies choose when nodes fire

Level order tells you where a node sits. Its trigger policy tells Cerulion when that node fires:
  • Period — fires every N milliseconds, configured with #[cerulion_node(period_ms = N)] or --policy period_ms=N.
  • Data — fires when data arrives on its trigger input, configured with data_trigger=NAME or a #[input(trigger)] port.
  • Sync — waits for a complete aligned set of trigger inputs within a sync_window_ms=N window.
  • External — represents a self-triggering ingress or driver node, such as a device file descriptor or blocking source. The node supplies an external_source() implementation.
Trigger policy belongs to the node type, not the graph YAML. The graph supplies the wiring that connects the policy’s inputs and outputs. See trigger policies for the complete grammar.

Multi-process is the Unix default

Under the real clock on Unix, an unpartitioned graph derives a process partition by default. Cerulion runs one worker process per derived group in barrier lockstep. When a cost snapshot is available, the partition is cost-aware; otherwise, the baseline is process-per-node. A graph with an existing process_groups: block uses those declared groups. Use --single-process to force the monolith instead:
Use the graph tools to inspect or prepare the layout:
  • graph levels shows the derived levels and trigger edges.
  • graph profile measures a live graph and writes a cost snapshot.
  • graph partition --dry-run previews the process groups without rewriting the graph YAML.

Choose the clock for the job

graph run uses the real clock by default. It is the live, event-driven path: the runtime wakes when a publish arrives. Use the virtual clock for deterministic graph run executions and benchmarking. It uses a deterministic clock with a 1 ms poll loop rather than waiting on live time. Bag resimulation does not use this selection: --resim all runs on the recording’s own clock. The external clock is accepted by the CLI but inert today: it starts at 0 and does not advance, so time-based triggers never fire. It parses as --time-source external; no external time feeder is wired yet.
An external trigger policy and --time-source external are different controls. The policy describes a node’s ingress source; the time-source flag selects the clock for the graph run.

Why this makes replay byte-comparable

The graph supplies the same topology, trigger policies, and execution order each time. A recorded run can re-execute your nodes against its bag with --resim all --verify; verification compares every produced frame byte-for-byte with the recording. That is why you can use the real clock for a live robot, the virtual clock for deterministic graph run executions and benchmarking, and the recording’s own clock for byte-comparable resimulation without changing the graph’s execution contract. For the complete workflow, see record and replay a run.

Next steps

Wire and run a graph

Stage node instances, wire inputs, validate, and run.

Run across processes

Declare process groups, inspect partitions, and choose the monolith when needed.

Record and replay

Record a run and verify a byte-comparable re-execution.