Skip to content

Feat: Adds a high precision rate limiter#988

Merged
gbin merged 2 commits into
masterfrom
gbin/hp-rl
Mar 31, 2026
Merged

Feat: Adds a high precision rate limiter#988
gbin merged 2 commits into
masterfrom
gbin/hp-rl

Conversation

@gbin

@gbin gbin commented Mar 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a centralized high-precision main-loop limiter and a better cadence probe for cu_rate_target.

  • Moved loop-rate limiting into cu29_runtime with a shared LoopRateLimiter based on absolute deadlines instead of per-iteration remainder sleeping.
  • Added high-precision-limiter as an opt-in std feature. In that mode the limiter uses sleep-then-spin with a fixed 200us scheduler handoff window.
  • Updated generated sync and parallel runtime loops to use the shared limiter logic.
  • Added validation for runtime.rate_target_hz so 0 and out-of-range values fail early.

Example / tooling:

  • Split examples/cu_rate_target into two binaries: default and high-precision.
  • Simplified the example justfile to four targets: loose, precise, rt-loose, rt-precise.
  • Made loose / precise use the screaming profile by default.
  • Added Linux RT variants using chrt --fifo.
  • Replaced cu_logmon in the example with a dedicated colored cadence probe that reports:
    • dt p50/p95/max
    • jitter p95/max
    • phase p50/p99/max
    • missed / max_gap

Related issues

Changes

Testing

  • just fmt
  • just lint
  • just test
  • optional full just std-ci (if std/runtime paths are impacted)
  • optional full just nostd-ci (if embedded/no_std paths are impacted)
  • Other (please specify):

pro-tip: just with no parameters in the root defaults to just fmt, just lint, and just test.

Checklist

  • I have updated docs or examples where needed
  • I have added or updated tests where needed
  • I have considered platform impact (Linux/macOS/Windows/embedded)
  • I have considered config/logging changes (if applicable)
  • This change is not a breaking change (or I documented it below)

Breaking changes (if any)

Additional context

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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() to cu29_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_hz early).
  • Refactored examples/cu_rate_target into multiple bins and added a cadence probe + simplified justfile targets.

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))

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Suggested change
Ok(CuDuration::from(MAX_RATE_TARGET_HZ / rate_target_hz))
Ok(CuDuration::from((MAX_RATE_TARGET_HZ + rate_target_hz - 1) / rate_target_hz))

Copilot uses AI. Check for mistakes.
Comment on lines +279 to +280
let _ = deadline;
std::thread::sleep(std::time::Duration::from(remaining));

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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));
}

Copilot uses AI. Check for mistakes.
@gbin

gbin commented Mar 31, 2026

Copy link
Copy Markdown
Collaborator Author

the 2 comments from copilots are kind of garbage, ignoring and moving forward

@gbin gbin merged commit fb22bcb into master Mar 31, 2026
27 checks passed
@gbin gbin deleted the gbin/hp-rl branch March 31, 2026 20:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

question: Clarify rate_target_hz performance

2 participants