Skip to content

Commit 1ad6745

Browse files
gbinCopilot
andauthored
Adds back a host/systime for demo only.
filter it behind a feature flag (#927) * This fixes the unstable timings in sim * Adds back a host/systime for demo only. filter it behind a feature flag * Update core/cu29_runtime/src/curuntime.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 3b16164 commit 1ad6745

File tree

9 files changed

+61
-33
lines changed

9 files changed

+61
-33
lines changed

core/cu29/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ units = ["dep:cu29-units"]
4747
macro_debug = ["cu29-derive/macro_debug", "cu29-log-derive/macro_debug"]
4848
logviz = ["cu29-derive/logviz"]
4949
signal-handler = ["dep:ctrlc", "cu29-derive/signal-handler"]
50+
sysclock-perf = ["std", "cu29-runtime/sysclock-perf"]
5051
log-level-debug = ["cu29-log-derive/log-level-debug"]
5152
log-level-info = ["cu29-log-derive/log-level-info"]
5253
log-level-warning = ["cu29-log-derive/log-level-warning"]

core/cu29/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
//! - `reflect`: reflection support for runtime and units types
2626
//! - `textlogs`: text logging derive support
2727
//! - `remote-debug`: remote debug transport support
28+
//! - `sysclock-perf`: use a host/system clock for runtime perf timing while keeping robot time for `tov`
2829
//!
2930
//! ## Concepts behind Copper
3031
//!

core/cu29_derive/src/lib.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2455,7 +2455,7 @@ pub fn copper_runtime(args: TokenStream, input: TokenStream) -> TokenStream {
24552455
let run_loop = if std {
24562456
quote! {
24572457
loop {
2458-
let iter_start = self.copper_runtime.clock.now();
2458+
let iter_start = cu29::curuntime::perf_now(&self.copper_runtime.clock);
24592459
let result = match std::panic::catch_unwind(std::panic::AssertUnwindSafe(
24602460
|| <Self as #app_trait<S, L>>::run_one_iteration(self, #sim_callback_arg)
24612461
)) {
@@ -2478,7 +2478,7 @@ pub fn copper_runtime(args: TokenStream, input: TokenStream) -> TokenStream {
24782478

24792479
if let Some(rate) = self.copper_runtime.runtime_config.rate_target_hz {
24802480
let period: CuDuration = (1_000_000_000u64 / rate).into();
2481-
let elapsed = self.copper_runtime.clock.now() - iter_start;
2481+
let elapsed = cu29::curuntime::perf_now(&self.copper_runtime.clock) - iter_start;
24822482
if elapsed < period {
24832483
std::thread::sleep(std::time::Duration::from_nanos(period.as_nanos() - elapsed.as_nanos()));
24842484
}
@@ -2492,11 +2492,11 @@ pub fn copper_runtime(args: TokenStream, input: TokenStream) -> TokenStream {
24922492
} else {
24932493
quote! {
24942494
loop {
2495-
let iter_start = self.copper_runtime.clock.now();
2495+
let iter_start = cu29::curuntime::perf_now(&self.copper_runtime.clock);
24962496
let result = <Self as #app_trait<S, L>>::run_one_iteration(self, #sim_callback_arg);
24972497
if let Some(rate) = self.copper_runtime.runtime_config.rate_target_hz {
24982498
let period: CuDuration = (1_000_000_000u64 / rate).into();
2499-
let elapsed = self.copper_runtime.clock.now() - iter_start;
2499+
let elapsed = cu29::curuntime::perf_now(&self.copper_runtime.clock) - iter_start;
25002500
if elapsed < period {
25012501
busy_wait_for(period - elapsed);
25022502
}
@@ -4564,12 +4564,12 @@ fn generate_task_execution_tokens(
45644564
let output_start_time = if output_ports.len() == 1 {
45654565
quote! {
45664566
if cumsg_output.metadata.process_time.start.is_none() {
4567-
cumsg_output.metadata.process_time.start = clock.now().into();
4567+
cumsg_output.metadata.process_time.start = cu29::curuntime::perf_now(clock).into();
45684568
}
45694569
}
45704570
} else {
45714571
quote! {
4572-
let start_time = clock.now().into();
4572+
let start_time = cu29::curuntime::perf_now(clock).into();
45734573
#( if cumsg_output.#output_ports.metadata.process_time.start.is_none() {
45744574
cumsg_output.#output_ports.metadata.process_time.start = start_time;
45754575
} )*
@@ -4578,12 +4578,12 @@ fn generate_task_execution_tokens(
45784578
let output_end_time = if output_ports.len() == 1 {
45794579
quote! {
45804580
if cumsg_output.metadata.process_time.end.is_none() {
4581-
cumsg_output.metadata.process_time.end = clock.now().into();
4581+
cumsg_output.metadata.process_time.end = cu29::curuntime::perf_now(clock).into();
45824582
}
45834583
}
45844584
} else {
45854585
quote! {
4586-
let end_time = clock.now().into();
4586+
let end_time = cu29::curuntime::perf_now(clock).into();
45874587
#( if cumsg_output.#output_ports.metadata.process_time.end.is_none() {
45884588
cumsg_output.#output_ports.metadata.process_time.end = end_time;
45894589
} )*
@@ -5065,7 +5065,7 @@ fn generate_bridge_rx_execution_tokens(
50655065
step: CuComponentState::Process,
50665066
culistid: Some(clid),
50675067
});
5068-
cumsg_output.metadata.process_time.start = clock.now().into();
5068+
cumsg_output.metadata.process_time.start = cu29::curuntime::perf_now(clock).into();
50695069
let maybe_error = {
50705070
#rt_guard
50715071
ctx.clear_current_task();
@@ -5075,7 +5075,7 @@ fn generate_bridge_rx_execution_tokens(
50755075
cumsg_output,
50765076
)
50775077
};
5078-
cumsg_output.metadata.process_time.end = clock.now().into();
5078+
cumsg_output.metadata.process_time.end = cu29::curuntime::perf_now(clock).into();
50795079
if let Err(error) = maybe_error {
50805080
let decision = monitor.process_error(cu29::monitoring::ComponentId::new(#monitor_index), CuComponentState::Process, &error);
50815081
match decision {
@@ -5210,7 +5210,7 @@ fn generate_bridge_tx_execution_tokens(
52105210
step: CuComponentState::Process,
52115211
culistid: Some(clid),
52125212
});
5213-
cumsg_output.metadata.process_time.start = clock.now().into();
5213+
cumsg_output.metadata.process_time.start = cu29::curuntime::perf_now(clock).into();
52145214
let maybe_error = {
52155215
#rt_guard
52165216
ctx.clear_current_task();
@@ -5240,7 +5240,7 @@ fn generate_bridge_tx_execution_tokens(
52405240
}
52415241
}
52425242
}
5243-
cumsg_output.metadata.process_time.end = clock.now().into();
5243+
cumsg_output.metadata.process_time.end = cu29::curuntime::perf_now(clock).into();
52445244
}
52455245
}
52465246
},

core/cu29_runtime/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ defmt = ["cu29-log/defmt", "cu29-log-derive/defmt", "cu29-traits/defmt"]
9090
cuda = ["dep:cudarc"]
9191
macro_debug = []
9292
reflect = ["dep:bevy_reflect", "cu29-traits/reflect"]
93+
sysclock-perf = ["std"]
9394
remote-debug = [
9495
"std",
9596
"reflect",

core/cu29_runtime/src/curuntime.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,25 @@ pub struct CopperContext {
6464
pub clock: RobotClock,
6565
}
6666

67+
/// Returns a monotonic instant used for local runtime performance timing.
68+
///
69+
/// When `sysclock-perf` (and `std`) are enabled this uses a process-local
70+
/// `RobotClock::new()` instance for timing. The returned value is a
71+
/// monotonically increasing duration since an unspecified origin (typically
72+
/// process or runtime initialization), not a wall-clock time-of-day. When
73+
/// `sysclock-perf` is disabled it delegates to the provided `RobotClock`.
74+
#[inline]
75+
pub fn perf_now(_clock: &RobotClock) -> CuTime {
76+
#[cfg(all(feature = "std", feature = "sysclock-perf"))]
77+
{
78+
static PERF_CLOCK: std::sync::OnceLock<RobotClock> = std::sync::OnceLock::new();
79+
return PERF_CLOCK.get_or_init(RobotClock::new).now();
80+
}
81+
82+
#[allow(unreachable_code)]
83+
_clock.now()
84+
}
85+
6786
/// Manages the lifecycle of the copper lists and logging.
6887
pub struct CopperListsManager<P: CopperListTuple + Default, const NBCL: usize> {
6988
pub inner: CuListsManager<P, NBCL>,

examples/cu_flight_controller/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ default = ["sim"]
169169
sim_core = [
170170
"dep:cu29",
171171
"cu29/std",
172+
"cu29/sysclock-perf",
172173
"dep:cu-ahrs",
173174
"dep:cu-crsf",
174175
"dep:cu-msp-bridge",

examples/cu_flight_controller/src/sim.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -525,10 +525,11 @@ fn default_callback(_step: gnss::SimStep) -> SimOverride {
525525
}
526526

527527
fn set_msg_timing<T: CuMsgPayload>(clock: &RobotClock, msg: &mut CuMsg<T>) {
528-
let now = clock.now();
529-
msg.tov = Tov::Time(now);
530-
msg.metadata.process_time.start = now.into();
531-
msg.metadata.process_time.end = now.into();
528+
let tov = clock.now();
529+
let perf = cu29::curuntime::perf_now(clock);
530+
msg.tov = Tov::Time(tov);
531+
msg.metadata.process_time.start = perf.into();
532+
msg.metadata.process_time.end = perf.into();
532533
}
533534

534535
fn axis_to_rc(value: f32) -> u16 {

examples/cu_rp_balancebot/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ sim = [
114114
"dep:bevy_anti_alias",
115115
"dep:avian3d",
116116
"dep:cached-path",
117+
"cu29/sysclock-perf",
117118
] # dependencies to run the Bevy-based balancebot sim
118119
bevymon = ["sim", "dep:cu-bevymon"]
119120

examples/cu_rp_balancebot/src/sim_driver.rs

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,20 @@ pub fn default_callback(step: crate::default::SimStep) -> SimOverride {
5555
}
5656
}
5757

58+
fn set_msg_timing<T: CuMsgPayload>(clock: &RobotClock, msg: &mut CuMsg<T>) {
59+
let tov = clock.now();
60+
let perf = cu29::curuntime::perf_now(clock);
61+
msg.tov = tov.into();
62+
msg.metadata.process_time.start = perf.into();
63+
msg.metadata.process_time.end = perf.into();
64+
}
65+
66+
fn set_process_timing<T: CuMsgPayload>(clock: &RobotClock, msg: &mut CuMsg<T>) {
67+
let perf = cu29::curuntime::perf_now(clock);
68+
msg.metadata.process_time.start = perf.into();
69+
msg.metadata.process_time.end = perf.into();
70+
}
71+
5872
#[cfg(not(target_arch = "wasm32"))]
5973
#[cfg_attr(feature = "bevymon", allow(dead_code))]
6074
pub fn setup_native_copper(mut commands: Commands) {
@@ -228,11 +242,8 @@ pub fn run_copper_callback<T: Send + Sync + 'static>(
228242
}
229243

230244
let analog_value = (angle_radians / (2.0 * std::f32::consts::PI) * 4096.0) as u16;
231-
let now = clock.now();
232245
output.set_payload(ADSReadingPayload { analog_value });
233-
output.tov = now.into();
234-
output.metadata.process_time.start = now.into();
235-
output.metadata.process_time.end = now.into();
246+
set_msg_timing(&clock, output);
236247
SimOverride::ExecutedBySim
237248
}
238249
crate::default::SimStep::Balpos(_) => SimOverride::ExecutedBySim,
@@ -241,11 +252,8 @@ pub fn run_copper_callback<T: Send + Sync + 'static>(
241252
let (cart_transform, _, _) =
242253
bindings.single_mut().expect("Failed to get cart transform");
243254
let ticks = (cart_transform.translation.x * 2000.0) as i32;
244-
let now = clock.now();
245255
output.set_payload(EncoderPayload { ticks });
246-
output.tov = now.into();
247-
output.metadata.process_time.start = now.into();
248-
output.metadata.process_time.end = now.into();
256+
set_msg_timing(&clock, output);
249257
SimOverride::ExecutedBySim
250258
}
251259
crate::default::SimStep::Railpos(_) => SimOverride::ExecutedBySim,
@@ -255,7 +263,6 @@ pub fn run_copper_callback<T: Send + Sync + 'static>(
255263
bindings.single_mut().expect("Failed to get cart force");
256264
let maybe_motor_actuation = input.payload();
257265
let override_motor = drag_state.override_motor;
258-
let now = clock.now();
259266
if override_motor {
260267
if let Some(motor_actuation) = maybe_motor_actuation
261268
&& !motor_actuation.power.get::<ratio>().is_nan()
@@ -269,15 +276,13 @@ pub fn run_copper_callback<T: Send + Sync + 'static>(
269276
.metadata
270277
.set_status(format!("Applied force: {force_magnitude}"));
271278
}
272-
output.metadata.process_time.start = now.into();
273-
output.metadata.process_time.end = now.into();
279+
set_process_timing(&clock, output);
274280
return SimOverride::ExecutedBySim;
275281
}
276282
if let Some(motor_actuation) = maybe_motor_actuation {
277283
if motor_actuation.power.get::<ratio>().is_nan() {
278284
cart_force.0 = Vector::ZERO;
279-
output.metadata.process_time.start = now.into();
280-
output.metadata.process_time.end = now.into();
285+
set_process_timing(&clock, output);
281286
return SimOverride::ExecutedBySim;
282287
}
283288
let total_mass = motor_model::total_mass_kg();
@@ -291,13 +296,11 @@ pub fn run_copper_callback<T: Send + Sync + 'static>(
291296
output
292297
.metadata
293298
.set_status(format!("Applied force: {force_magnitude}"));
294-
output.metadata.process_time.start = now.into();
295-
output.metadata.process_time.end = now.into();
299+
set_process_timing(&clock, output);
296300
SimOverride::ExecutedBySim
297301
} else {
298302
cart_force.0 = Vector::ZERO;
299-
output.metadata.process_time.start = now.into();
300-
output.metadata.process_time.end = now.into();
303+
set_process_timing(&clock, output);
301304
SimOverride::Errored("Safety Mode.".into())
302305
}
303306
}

0 commit comments

Comments
 (0)