In a world first, copper builds an OS tailored to your robot at compile time using performance data from past logs to automatically tune it for your latency and bandwidth goals with zero runtime costs. Still conserving all the deterministic properties that makes copper so unique to validate autonomous robotics behavior.
Context
A robot can have individually fast algorithms and still be slow. A camera frame waits behind another job. Perception can compete with a control loop for the same resources like memory, IO or simply CPU. Adding a worker improves throughput but makes the longest delays worse. Somewhere in that graph, the scheduling choices become as consequential as the algorithms themselves.
Copper 1.3 makes those choices something you can describe, inspect, and optimize automatically. Profile Guided Scheduling brings autotuning to the generated robot runtime. You specify the rates and deadlines your application needs, record a representative run, and let Copper search for execution plans that fit the measured workload. The resulting schedule is compiled into your application, preserving deterministic execution and replay.
Profile Guided Scheduling
Imagine a graph combining camera processing, an estimator, a planner, and a controller. Their costs differ. Their rates differ. Some operations can overlap across frames; others must preserve state from one iteration to the next. A schedule that looks balanced in a diagram can still deliver camera frames too slowly or delay a critical path.
There are many interacting choices: how many workers to use, which CPUs they run on, where each operation belongs, what order operations follow, and how much work can be in flight. Exploring that space by hand quickly exceeds what a developer can reasonably keep in their head. Every change needs another run, another measurement, and another decision about which tradeoff actually helped the robot.
Copper 1.3 addresses this in two parts.
First, describe exactly how the application should execute
An explicit execution plan lets you specify worker assignments, operation order, CPU placement, dependencies across workers and cycles, and the number of in-flight CopperLists. A CopperList carries one execution's messages through the graph; keeping several in flight allows stages of different executions to overlap.
The plan is a portable `CuPlan`, saved in RON. Copper validates it against the application's static graph and generates the corresponding runtime. You can write a plan yourself or start with the built-in `Serial` and `Pipeline` plans.
That gives you a concrete answer to what the application will execute and where. The schedule can be reviewed, saved alongside the application, and visualized.
Then, let Copper search for a better plan
Profile Guided Scheduling (PGS) uses timings from a representative recording together with your scheduling requirements: source periods, end-to-end deadlines, available CPUs, pipeline depth, and timing margin.
The workflow:
Record the application under a representative workload.
Describe the rates, deadlines, and hardware budget you need.
Generate candidate execution plans from the measured costs.
Rebuild and run the candidates on the target hardware.
Compare delivered source rates and p99 chain latency, then compile the selected plan into the application.
The search model proposes plans and real runs show how they behave on your hardware.
The ranking keeps source delivery visible alongside latency, so a plan cannot look successful merely because it processes fewer inputs.
The baseline remains a candidate too. Sometime like this contrived example, the simplest scheduling is actually the best!
Copper was already turning a static task graph into typed Rust calls that the compiler can optimize. PGS extends that approach to the execution schedule itself at the heart of the operating system primitives: the application's recorded behavior becomes input to the generation of its next runtime. It adds an optimization layer across tasks, workers, and successive executions, complementing the optimizations Rust and LLVM perform inside the generated code.
The profiling and search happen offline. The deployed application executes the selected, validated plan; it pays no runtime cost for the search, and the optimizer does not change the schedule while the robot is running. Deterministic execution and replay remain completely intact.
Also in this release a companion to PGS: The new stateless task type gives the optimizer even more freedom
A controller with accumulated state needs ordering between successive executions. A pure image conversion often does not: converting one frame need not wait for the conversion of the previous frame.
`CuStatelessTask` lets you express that distinction. Its per-cycle methods borrow `&self`, and its contract says calls for different CopperLists can execute independently. That is an explicit optimization hint to Copper: the planner can overlap that work and explore schedules that would be inappropriate for a task carrying state between iterations.
The important part is the behavior you promise. A lock around shared mutable data may make a task thread-safe while its output still depends on call order. A stateless declaration promises independence across overlapping executions. Stateful controllers continue to use regular tasks.
This makes PGS more powerful. The graph tells Copper where data must flow; the task contract tells it which work can overlap. Together, they expose optimization opportunities that are difficult to infer from opaque callbacks
The Copper 1.3 release notes cover the complete changes and upgrade details.
Try our new section in the copper book to get started with the PGS workflow.