Logging
| Variable | Meaning |
|---|---|
RUST_LOG | Standard log filter, for example RUST_LOG=cerulion=info,iceoryx2=warn. A new workspace’s .cargo/config.toml sets a sane default. |
IOX2_LOG_LEVEL | The transport’s own log filter. New workspaces default it to error so framework chatter does not drown out your logs. |
tracing::info! from your tick() goes to stderr while the host’s own logs go to stdout. The filter is RUST_LOG as captured when the graph started, an empty value means info, and RUST_LOG=off silences node-side logs entirely.
Do not install a global
tracing subscriber inside node code — the framework installs one before your node runs, and a second install panics and fails the node load. Control output with RUST_LOG instead.Networking
| Variable | Meaning |
|---|---|
CERULION_NETWORK=off | Run local-only: no gateway process, nothing crosses the machine boundary. Honored by every entry point, and equivalent to --network off. |
CERULION_NETD_LISTEN | The locators the robot’s shared network plane binds, for example tcp/0.0.0.0:7683. Set it on a robot that must be discoverable where LAN multicast is blocked; without it the plane binds nothing and the machine advertises nothing. Setting it also makes the plane standing: it comes up when the machine’s network daemon starts, so topics registered at runtime — the topics a ROS 2 process publishes, for instance — are advertised on the network without a graph ever running, and the daemon stops only on SIGINT/SIGTERM instead of self-exiting once nothing has demanded a topic for the idle grace. |
CERULION_NETD_NETWORK=off | Force the machine’s shared network plane strictly local-only, whatever CERULION_NETD_LISTEN says. Scoped to the daemon, so it never changes what a graph run on the same machine does. |
CERULION_GATEWAY_PORT | Override the well-known gateway port (7683). Parsed strictly. |
CERULION_ROBOT_IDENTITY | The robot name announced on the network. Defaults to the hostname. |
CERULION_PEERS | Extra peer locators to try when discovering robots. |
Recording and capture
| Variable | Meaning |
|---|---|
CERULION_FLASHBACK=off | Turn the Flashback capture plane off, so no run holds a rolling window. |
CERULION_FLASHBACK_DIR | Where captures land. Defaults to <workspace>/recordings/flashbacks/. |
CERULION_RECORD_DISCOVERY=off | With graph run --record, record only the graph’s declared topics instead of also discovering other live producers. |
CERULION_RECORD_DISCOVERY_SETTLE_MS | How long bag creation waits for late producers to appear. |
Visualization
| Variable | Meaning |
|---|---|
CERULION_VIZD_SOCK | Path of the control socket the visualization daemon listens on. Set it on both the daemon and its clients to run a scene at a non-default location. |
ROS 2 on Cerulion transport
Read bycerulion ros2 run / cerulion ros2 launch and by graph run for a graph’s ros2: entries — every path stages the same child environment.
| Variable | Meaning |
|---|---|
CERULION_LIB_DIR | The directory holding librmw_cerulion.so, instead of the directory of the cerulion binary. It is prepended to the ROS 2 child’s LD_LIBRARY_PATH, and a minimal ament prefix linking the library is staged under ~/.cerulion/ros2/ (or the directory is used as-is when it already is an install’s lib/) and prepended to AMENT_PREFIX_PATH. A missing library is exit 69 with the remediation, never a silent fall-through to the stock RMW. Set but empty is an error. |
CERULION_RMW_EVENT_WAIT | Read inside the ROS 2 process itself, by the Cerulion RMW layer. A waiting executor blocks on the transport’s own wake channels, so a publish wakes it in microseconds; off restores the earlier behavior, where the wait probed for new messages every 100 microseconds instead. on, empty, or unset is the default, and any other value warns once and keeps the event-driven wait. |
CERULION_RMW_SLICE_CEILING | Read inside the ROS 2 process itself: per-type payload ceilings for the shared-memory slots its publishers create, as a comma-separated <pkg/Type>:<bytes> list — for example sensor_msgs/Image:33554432,my_pkg/Big:268435456. Without it, a variable-length ROS 2 type takes the same per-type budget Cerulion gives one of its own outputs of that schema, and a type Cerulion does not know takes 128 MiB. An override wins outright, so it can widen or narrow. Names must be exactly pkg/Type: never pkg::Type (the : separates the name from the bytes) and never the rosidl pkg/msg/Type. Bytes must be an integer from 32 to 4294967295. A malformed entry warns and is skipped while the entries around it still apply; duplicate entries for one type warn and the last one wins. The value is read once per process, at the first publisher creation. The ceiling is the real slot size, so a message larger than it fails to publish loudly instead of reserving a blanket slot. An entry naming a fixed-size type is ignored with a warning — those are always sized exactly at their wire size. |
CERULION_ROS2_PRELOAD | Preload control for the ROS 2 child. Unset — the default — auto-injects libcerulion_heaphook.so into LD_PRELOAD when it exists beside librmw_cerulion.so, logging one line naming what it injected. With the hook injected, a ROS 2 publisher whose message type carries an unbounded numeric sequence — sensor_msgs/Image.data, sensor_msgs/PointCloud2.data, sensor_msgs/LaserScan.ranges — can loan messages, so filling that field writes into the shared-memory slot the message publishes from instead of a heap buffer that is copied. Bounded sequences, bool[], and fields declared with a default value are copied at publish as before. off or none disables preload injection entirely, and those fields go back to being copied. Any other value is a path to a .so that is added, not substituted: LD_PRELOAD becomes <your library>:<the hook, when present>:<whatever was already there>. A path that does not exist is exit 69; an empty value is an error. Injection is never silently dropped. |
CERULION_RMW_ADOPT_TAKE | Read inside the ROS 2 process itself. 1 arms adopt-take for every subscription whose type is forgeable: a plain take serves the shared-memory bytes in place, and the application’s own free() of each sequence releases the sample. 0 or unset disarms; any other value warns once and disarms. A child staged by cerulion ros2 run or ros2 launch never has it set — those verbs refuse the flag with exit 69 and refuse this variable with exit 2 — so set it on a node you launch directly, with libcerulion_heaphook.so preloaded. Armed with the hook inactive, adopt-take stays off with one warning rather than quietly copying. Linux with glibc only. |
CERULION_RMW_ADOPT_TAKE_BUDGET | Read inside the ROS 2 process itself: a positive integer capping how many samples one subscription may hold adopted at once. Unset uses the built-in borrow budget; anything that is not a positive integer warns and uses the default. A take past the budget is a refusal, not a copy — rmw_take returns success with nothing taken and the frame stays queued — so a caller holding messages faster than it frees them sees empty takes rather than degraded ones. Freeing any one adopted message lets the next take through. |
CERULION_ROS2_MIGRATE_TOOL | Path to the cerulion-ros2-migrate-clang engine binary that cerulion ros2 migrate shells out to. Without it the verb looks beside the cerulion binary and then on PATH; finding it nowhere is exit 69 with build instructions, never a silently inert analysis. |
CERULION_HEAPHOOK_DEBUG | Read by the preloaded libcerulion_heaphook.so itself (Linux with glibc). Set it to any non-empty value other than 0 and the library writes one line to stderr as it loads, confirming that it loaded and that it took effect. Unset, empty, or 0 prints nothing. It is a diagnostic: a stock ROS 2 process installs no Cerulion log subscriber, so this line is how you confirm the preload actually reached the child. If another allocator — jemalloc, tcmalloc, or a sanitizer — is preloaded ahead of it, the library says so on stderr as it loads whether or not this variable is set, and stays out of the way. |
Live-run tuning
These affect how the live loop idles and how work is spread across cores. Reach for them when you are chasing latency, not before.| Variable | Meaning |
|---|---|
CERULION_MONITOR_WAIT | 1 forces the live-loop CPU park on, 0 disables it. The default is on for live runs. --no-monitor-wait beats this in both directions. A ROS 2 process on rmw_cerulion reads the same variable for the park its executor wait uses, where the default is per platform: on for Linux aarch64, off for x86_64, on which blocking in the kernel measured faster. |
CERULION_DOORBELL | 1 forces the data doorbell on (a publish wakes a parked consumer immediately), 0 leaves a timer-only park. Linux only. |
CERULION_CPU_DMA_LOCK | 1 pins the CPU out of deep idle states, 0 disables the cap. By default Cerulion derives a cap from the graph’s own tightest timing. Linux only, and it needs privileges — a failed acquire warns and the run continues. |
CERULION_CPU_DMA_LOCK_US | An explicit idle exit-latency cap in microseconds, used under the automatic mode. |
CERULION_FIRE_THREADS | Size of the pool that fires independent nodes within one level. Read once at graph build; the default is derived from the machine and the graph’s widest level. It never changes what fires or in what order. |
CERULION_BARRIER_SPIN_US | Multi-process only: how long a worker waits actively at each level boundary before it sleeps. 0 skips the active wait. Values above 100 ms are clamped with a warning. |
CERULION_BARRIER_OS_SYNC | macOS only: 0 opts out of the faster wake path at level boundaries, at the cost of latency. |
CERULION_CREDIT_WAKE | Multi-process only, on Unix: the producer-side credit park. A producer deferred at a cross-process block gate blocks on that edge’s shared credit word until the consumer’s drain wakes it; 0 turns that off and the producer falls back to the park’s recheck cadence. Correct and bounded either way — all 0 costs is wake latency. Anything other than 0 or 1 warns and stays enabled. Inert on a run that splits no block edge. |
CERULION_CREDIT_OS_SYNC | macOS only: 0 drops the credit word’s kernel-wake tier to a sleep-and-recheck fallback. It is deliberately separate from CERULION_BARRIER_OS_SYNC — opting out of the barrier’s wake tier says nothing about the credit plane. |
CERULION_PARK_OS_SYNC | macOS 14.4 and later: 0 opts out of the faster wait the live-loop park uses between rechecks, so each recheck waits with a plain sleep instead. It changes only how tightly the park keeps to its recheck interval, never what fires. 1 or unset is the default, any other value warns and keeps the faster wait, and older macOS versions and every other platform are unaffected. |
Build
| Variable | Meaning |
|---|---|
CARGO_TARGET_DIR | Honored identically by cerulion node build and cerulion graph run, so a shared target directory works. |
Related
CLI reference
The flags that override several of these variables.
Network a graph
What the network variables change in practice.