//! rtic_bare3.rs //! //! Measuring execution time //! //! What it covers //! - Reading Rust documentation //! - Timing abstractions and semantics //! - Understanding Rust abstractions #![no_main] #![no_std] use cortex_m_semihosting::hprintln; use panic_semihosting as _; use rtic::cyccnt::Instant; use stm32f4; #[rtic::app(device = stm32f4)] const APP: () = { #[init] fn init(mut cx: init::Context) { cx.core.DWT.enable_cycle_counter(); let start = Instant::now(); wait(1_000_000); let end = Instant::now(); let diff = Instant::elapsed(&start); // notice all printing outside of the section to measure! hprintln!("Start {:?}", start).ok(); hprintln!("End {:?}", end).ok(); //let diff = Instant::duration_since(&end,start); hprintln!("Diff {:?}", diff.as_cycles()).ok(); } }; // burns CPU cycles by just looping `i` times #[inline(never)] #[no_mangle] fn wait(i: u32) { for _ in 0..i { // no operation (ensured not optimized out) cortex_m::asm::nop(); } } // 0. Setup // // > cargo doc --open // // In the docs, search (`S`) for `Monotonic` and read the API docs. // Also search for `Instant`, and `Duration`. // // Together these provide timing semantics. // // - `Monotonic` is a "trait" for a timer implementation. // - `Instant` is a point in time. // - `Duration` is a range in time. // // By default RTIC uses the `Systic` and the `DWT` cycle counter // to provide a `Monotonic` timer. // // 1. Build and run the application in vscode using (Cortex Release). // // What is the output in the Adapter Output console? // // Start Instant(2694714472) // End Instant(2698714489) // // As you see line 31 is commented out (we never print the difference). // // Now uncomment line 31, and try to run the program. You will see // that it fails to compile right as `Duration` does not implement `Debug` // (needed for formatting the printout.) // // This is on purpose as `Duration` is abstract (opaque). You need to // turn it into a concrete value. Look at the documentation, to find out // a way to turn it into clock cycles (which are printable). // // What is now the output in the Adapter Output console? // // Start Instant(2100880231) // End Instant(2104880247) // Diff 4000016 // // Commit your answers (bare3_1) // // 2. Look at the `Instant` documentation. // // Alter the code so that you use `duration_since`, instead of manual subtraction. // // What is now the output in the Adapter Output console? // // Start Instant(20606036) // End Instant(24606052) // Diff 4000016 // // Commit your answers (bare3_2) // // 3. Look at the `Instant` documentation. // Now alter the code so that it uses `elapsed` instead. // // What is now the output in the Adapter Output console? // // Start Instant(2395620599) // End Instant(2399620615) // Diff 4000020 // // Commit your answers (bare3_3) // // 4. Discussion. // // If you did implement the above exercises correctly you should get exactly the same // result (in clock cycles) for all cases as you got in the bare2 exercise. // (If not, go back and revise your code.) // // What this shows, is that we can step away from pure hardware accesses // and deal with time in a more convenient and "abstract" fashion. // // `Instant` and `Duration` are associated with semantics (meaning). // `Monotonic` is associated the implementation. // // This is an example of separation of concerns! // // If you implement your application based on Instant and Duration, your code // will be "portable" across all platforms (that implement Monotonic). // // The implementation of Monotonic is done only once for each platform, thus // bugs related to low level timer access will occur only at one place, // not scattered across thousands of manually written applications. // // However, as you have already seen, the current time abstraction (API) is // is rather "thin" (provided just a bare minimum functionality). // // We are working to further generalize timing semantics, by building // on a richer abstraction `https://docs.rs/embedded-time/0.10.1/embedded_time/`. // // Support for embedded time is projected for next RTIC release.