Feat: Adds a high precision rate limiter#988
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a centralized, higher-precision loop rate limiter for runtime.rate_target_hz, moving rate limiting policy into cu29_runtime (with an opt-in high-precision-limiter std feature) and updating generated runtime loops and examples accordingly. It targets tighter, phase-stable cadence control to address observed under-target rates (Issue #987).
Changes:
- Added
LoopRateLimiter+rate_target_period()tocu29_runtime, using absolute deadlines (plus optional sleep-then-spin for high precision). - Updated proc-macro generated sync + parallel runtime loops to use the shared limiter (and validated
runtime.rate_target_hzearly). - Refactored
examples/cu_rate_targetinto multiple bins and added a cadence probe + simplifiedjustfiletargets.
Reviewed changes
Copilot reviewed 11 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| examples/cu_rate_target/src/main.rs | Removed old single-binary example entrypoint. |
| examples/cu_rate_target/src/lib.rs | New shared example library with cadence probe + run_example(). |
| examples/cu_rate_target/src/bin/rate_target.rs | New default limiter binary entrypoint. |
| examples/cu_rate_target/src/bin/rate_target_precise.rs | New high-precision limiter binary entrypoint (feature-gated). |
| examples/cu_rate_target/justfile | Updated example commands for loose/precise and RT variants. |
| examples/cu_rate_target/copperconfig.ron | Updated example runtime rate target to 1000 Hz. |
| examples/cu_rate_target/Cargo.toml | Added feature wiring + split into lib + two bins. |
| core/cu29/src/lib.rs | Documented new high-precision-limiter feature. |
| core/cu29/Cargo.toml | Added high-precision-limiter feature forwarding to cu29-runtime. |
| core/cu29_runtime/src/curuntime.rs | Implemented LoopRateLimiter, rate_target_period(), and added tests; runtime config validation call added. |
| core/cu29_runtime/src/config.rs | Added MAX_RATE_TARGET_HZ and runtime config validation (plus tests). |
| core/cu29_runtime/Cargo.toml | Added high-precision-limiter feature flag. |
| core/cu29_derive/src/lib.rs | Updated generated runtime loops (sync + parallel) to use LoopRateLimiter. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ))); | ||
| } | ||
|
|
||
| Ok(CuDuration::from(MAX_RATE_TARGET_HZ / rate_target_hz)) |
There was a problem hiding this comment.
rate_target_period uses integer division (1_000_000_000 / rate_target_hz) which rounds down when the rate doesn’t evenly divide 1e9. That produces a shorter period and can allow the runtime to exceed the configured rate_target_hz (even if only slightly). To preserve the “rate target as an upper bound” semantics, compute the period with ceiling division (e.g., (NANOS_PER_SEC + rate_target_hz - 1) / rate_target_hz).
| Ok(CuDuration::from(MAX_RATE_TARGET_HZ / rate_target_hz)) | |
| Ok(CuDuration::from((MAX_RATE_TARGET_HZ + rate_target_hz - 1) / rate_target_hz)) |
| let _ = deadline; | ||
| std::thread::sleep(std::time::Duration::from(remaining)); |
There was a problem hiding this comment.
In the std + non high-precision-limiter path, wait_until_ready does a single std::thread::sleep(remaining) and then returns without re-checking the deadline. sleep can return early (e.g., due to interrupts/spurious wakeups), which can violate the rate limit. Consider looping until clock.now() >= deadline (potentially with a short final spin) to guarantee the limiter never releases early.
| let _ = deadline; | |
| std::thread::sleep(std::time::Duration::from(remaining)); | |
| // Loop and re-check the remaining time to handle early wakeups from sleep. | |
| // `self.remaining(clock)` should return `None` once the deadline has passed. | |
| while let Some(remaining) = self.remaining(clock) { | |
| std::thread::sleep(std::time::Duration::from(remaining)); | |
| } |
|
the 2 comments from copilots are kind of garbage, ignoring and moving forward |
Summary
Adds a centralized high-precision main-loop limiter and a better cadence probe for cu_rate_target.
Example / tooling:
Related issues
Changes
Testing
just fmtjust lintjust testjust std-ci(if std/runtime paths are impacted)just nostd-ci(if embedded/no_std paths are impacted)pro-tip:
justwith no parameters in the root defaults tojust fmt,just lint, andjust test.Checklist
Breaking changes (if any)
Additional context