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: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=NAMEor a#[input(trigger)]port. - Sync — waits for a complete aligned set of trigger inputs within a
sync_window_ms=Nwindow. - 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.
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 existingprocess_groups: block uses those declared groups.
Use --single-process to force the monolith instead:
graph levelsshows the derived levels and trigger edges.graph profilemeasures a live graph and writes a cost snapshot.graph partition --dry-runpreviews 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.
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.