From dc83de16281fe3bab4a9eb145558824ac5af7254 Mon Sep 17 00:00:00 2001 From: Per Lindgren <per.lindgren@ltu.se> Date: Thu, 12 Nov 2020 15:15:18 +0100 Subject: [PATCH] timing_resources2 --- examples/timing_resources2.rs | 253 ++++++++++++++++++++++++++++++++++ examples/timing_task.rs | 2 +- 2 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 examples/timing_resources2.rs diff --git a/examples/timing_resources2.rs b/examples/timing_resources2.rs new file mode 100644 index 0000000..1d6bf27 --- /dev/null +++ b/examples/timing_resources2.rs @@ -0,0 +1,253 @@ +//! examples/timing_resources.rs + +// #![deny(unsafe_code)] +#![deny(warnings)] +#![no_main] +#![no_std] + +use cortex_m::peripheral::DWT; +//use cortex_m::{asm, peripheral::DWT}; +use panic_halt as _; +use stm32f4::stm32f411; + +#[rtic::app(device = stm32f411)] +const APP: () = { + struct Resources { + dwt: DWT, + + #[init(0)] + shared: u64, // non atomic data + } + + #[init] + fn init(mut cx: init::Context) -> init::LateResources { + // Initialize (enable) the monotonic timer (CYCCNT) + cx.core.DCB.enable_trace(); + cx.core.DWT.enable_cycle_counter(); + init::LateResources { dwt: cx.core.DWT } + } + + #[idle(resources = [shared])] + fn idle(_cx: idle::Context) -> ! { + // unsafe { cx.resources.dwt.cyccnt.write(0) }; + // // asm::bkpt(); + // rtic::pend(stm32f411::Interrupt::EXTI0); + // // asm::bkpt(); + // cx.resources.shared.lock(|shared| { + // // asm::bkpt(); + // *shared += 1; + // // asm::bkpt(); + // }); + // asm::bkpt(); + loop { + continue; + } + } + + #[task(binds = EXTI0, resources = [shared], priority = 2)] + fn exti0(cx: exti0::Context) { + // asm::bkpt(); + *cx.resources.shared += 1; + } + + #[task(binds = EXTI1, resources = [dwt, shared], priority = 1)] + fn exti1(mut cx: exti1::Context) { + unsafe { cx.resources.dwt.cyccnt.write(0) }; + // asm::bkpt(); + rtic::pend(stm32f411::Interrupt::EXTI0); + // asm::bkpt(); + cx.resources.shared.lock(|shared| { + // asm::bkpt(); + *shared += 1; + // asm::bkpt(); + }); + // asm::bkpt(); + } +}; + +// Now we are going to have a look at the resource management of RTIC. +// +// First create an objdump file: +// > cargo objdump --example timing_resources --release --features nightly -- --disassemble > timing_resources.objdump +// +// Lookup the EXTI0 symbol (RTIC binds the exti0 task to the interrupt vector). +// +// You should find something like: +// +// 080002b6 <EXTI0>: +// 80002b6: 40 f2 00 00 movw r0, #0 +// 80002ba: 00 be bkpt #0 +// 80002bc: c2 f2 00 00 movt r0, #8192 +// 80002c0: d0 e9 00 12 ldrd r1, r2, [r0] +// 80002c4: 01 31 adds r1, #1 +// 80002c6: 42 f1 00 02 adc r2, r2, #0 +// 80002ca: c0 e9 00 12 strd r1, r2, [r0] +// 80002ce: 00 20 movs r0, #0 +// 80002d0: 80 f3 11 88 msr basepri, r0 +// 80002d4: 70 47 bx lr +// +// Explain what is happening here in your own words. +// +// [Your code here] +// +// > cargo run --example timing_resources --release --features nightly +// Then continue to the first breakpoint instruction: +// (gdb) c +// timing_resources::idle (cx=...) at examples/timing_resources.rs:32 +// 32 asm::bkpt(); +// +// (gdb) x 0xe0001004 +// 0 +// +// (gdb) c +// timing_resources::exti0 (cx=...) at examples/timing_resources.rs:44 +// 44 asm::bkpt(); +// +// (gdb) x 0xe0001004 +// +// [Your answer here] +// +// (gdb) disassemble +// +// [Your answer here] +// +// You should see that we hit the breakpoint in `exti0`, and +// that the code complies to the objdump EXTI disassembly. +// +// What was the software latency observed to enter the task? +// +// [Your answer here] +// +// Does RTIC infer any overhead? +// +// [Your answer here] +// +// Now we can continue to measure the round trip time. +// +// (gdb) c +// +// (gdb) x 0xe0001004 +// timing_resources::idle (cx=...) at examples/timing_resources.rs:34 +// 34 asm::bkpt(); +// +// [Your answer here] +// +// You should have a total execution time in the range of 30 cycles. +// +// Explain the reason (for this case) that resource access in +// `exti0` was safe without locking the resource. +// +// [Your answer here] +// +// In `idle` we also access `shared` but this time through a lock. +// +// (gdb) disassemble +// => 0x0800026e <+26>: bkpt 0x0000 +// 0x08000270 <+28>: ldrb r2, [r0, #0] +// 0x08000272 <+30>: cbz r2, 0x800028c <timing_resources::idle+56> +// 0x08000274 <+32>: movw r0, #0 +// 0x08000278 <+36>: movt r0, #8192 ; 0x2000 +// 0x0800027c <+40>: ldrd r1, r2, [r0] +// 0x08000280 <+44>: adds r1, #1 +// 0x08000282 <+46>: adc.w r2, r2, #0 +// 0x08000286 <+50>: strd r1, r2, [r0] +// 0x0800028a <+54>: b.n 0x80002b2 <timing_resources::idle+94> +// 0x0800028c <+56>: movs r2, #1 +// 0x0800028e <+58>: movw r12, #0 +// 0x08000292 <+62>: strb r2, [r0, #0] +// 0x08000294 <+64>: movs r2, #240 ; 0xf0 +// 0x08000296 <+66>: msr BASEPRI, r2 +// 0x0800029a <+70>: movt r12, #8192 ; 0x2000 +// 0x0800029e <+74>: ldrd r3, r2, [r12] +// 0x080002a2 <+78>: adds r3, #1 +// 0x080002a4 <+80>: adc.w r2, r2, #0 +// 0x080002a8 <+84>: strd r3, r2, [r12] +// 0x080002ac <+88>: msr BASEPRI, r1 +// 0x080002b0 <+92>: strb r1, [r0, #0] +// 0x080002b2 <+94>: bkpt 0x0000 +// +// We can now execute the code to the next breakpoint to get the +// execution time of the lock. +// +// (gdb) c +// timing_resources::idle (cx=...) at examples/timing_resources.rs:36 +// 36 asm::bkpt(); +// +// (gdb) x 0xe0001004 +// +// [Your answer here] +// +// Calculate the total time (in cycles), for this section of code. +// +// [Your answer here] +// +// You should get a value around 25 cycles. +// +// Now look at the "critical section", i.e., how many cycles +// are the lock held? +// To this end you need to insert `asm::bkpt()` on entry and exit +// inside the closure. +// +// cx.resources.shared.lock(|shared| { +// asm::bkpt(); +// *shared += 1; +// asm::bkpt(); +// }); +// +// Change the code, and compile it from withing gdb +// (gdb) shell cargo build --example timing_resources --release --features nightly +// Compiling app v0.1.0 (/home/pln/courses/e7020e/app) +// Finished release [optimized + debuginfo] target(s) in 0.32s +// +// and load the newly compiled executable: +// (gdb) load +// ... +// Transfer rate: 1 KB/sec, 406 bytes/write. +// +// Now you can continue until you hit the first breakpoint in the lock closure. +// +// (gdb) c +// rtic::export::lock<u64,(),closure-0> (ptr=<optimized out>, priority=0x2000ffef, ceiling=1, nvic_prio_bits=4, f=...) at /home/pln/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:11 +// 11 () => unsafe { llvm_asm!("bkpt" :::: "volatile") }, +// +// (gdb) x 0xe0001004 +// +// [Your answer here] +// +// (gdb) c +// rtic::export::lock<u64,(),closure-0> (ptr=<optimized out>, priority=0x2000ffef, ceiling=1, nvic_prio_bits=4, f=...) at /home/pln/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.6.4/src/asm.rs:11 +// 11 () => unsafe { llvm_asm!("bkpt" :::: "volatile") }, +// +// (gdb) x 0xe0001004 +// +// [Your answer here] +// +// From a real-time perspective the critical section infers +// blocking (of higher priority tasks). +// +// How many clock cycles is the blocking? +// +// [Your answer here] +// +// Finally continue out of the closure. +// +// (gdb) c +// timing_resources::idle (cx=...) at examples/timing_resources.rs:40 +// 40 asm::bkpt(); +// +// (gdb) x 0xe0001004 +// +// [Your answer here] +// +// This is the total execution time of. +// +// - pending a task `exti` for execution +// - preempt `idle` +// - inside `exti` safely access and update a shared (non atomic resource). +// - returning to `idle` +// - safely access and update a shared (non atomic) resource +// +// Notice here, the breakpoints infer some OH and may disable +// some potential LLVM optimizations. +// +// diff --git a/examples/timing_task.rs b/examples/timing_task.rs index 9736b60..811dca8 100644 --- a/examples/timing_task.rs +++ b/examples/timing_task.rs @@ -48,7 +48,7 @@ const APP: () = { // // You should find something like: // -// 08000232 <EXTI0>: +// 08000232 <EXTI0>: // 8000232: 00 be bkpt #0 // 8000234: 00 20 movs r0, #0 // 8000236: 80 f3 11 88 msr basepri, r0 -- GitLab