aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-08-21 13:18:04 +0000
committerGitHub <[email protected]>2022-08-21 13:18:04 +0000
commit1b9599025868d3a5d0d8e773593b05df8b2fecf2 (patch)
tree97643e046656bdd8297b07dea9a62160a9ecce82
parentb7d77985cf230416e53190c4edde4030e42266ed (diff)
parent614b894ff871add9f0394fcf9ef220f133c4aae4 (diff)
Merge #897
897: Add support for `rtos-trace` behind a feature flag r=lulf a=quentinmit This allows SystemView to be used to profile the behavior of the user's application. Co-authored-by: Quentin Smith <[email protected]>
-rw-r--r--embassy-executor/Cargo.toml4
-rw-r--r--embassy-executor/src/lib.rs25
-rw-r--r--embassy-executor/src/raw/mod.rs35
-rw-r--r--embassy-macros/src/macros/cortex_m_interrupt_take.rs8
-rw-r--r--examples/nrf-rtos-trace/.cargo/config.toml9
-rw-r--r--examples/nrf-rtos-trace/Cargo.toml35
-rw-r--r--examples/nrf-rtos-trace/build.rs36
-rw-r--r--examples/nrf-rtos-trace/memory.x7
-rw-r--r--examples/nrf-rtos-trace/src/bin/rtos_trace.rs69
9 files changed, 227 insertions, 1 deletions
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index 25c3f0abd..7d5c4a045 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -30,9 +30,13 @@ nightly = []
30 30
31integrated-timers = ["dep:embassy-time"] 31integrated-timers = ["dep:embassy-time"]
32 32
33# Trace interrupt invocations with rtos-trace.
34rtos-trace-interrupt = ["rtos-trace"]
35
33[dependencies] 36[dependencies]
34defmt = { version = "0.3", optional = true } 37defmt = { version = "0.3", optional = true }
35log = { version = "0.4.14", optional = true } 38log = { version = "0.4.14", optional = true }
39rtos-trace = { version = "0.1.2", optional = true }
36 40
37futures-util = { version = "0.3.17", default-features = false } 41futures-util = { version = "0.3.17", default-features = false }
38embassy-macros = { version = "0.1.0", path = "../embassy-macros"} 42embassy-macros = { version = "0.1.0", path = "../embassy-macros"}
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs
index 9328a7378..93f2eaa6d 100644
--- a/embassy-executor/src/lib.rs
+++ b/embassy-executor/src/lib.rs
@@ -38,6 +38,31 @@ cfg_if::cfg_if! {
38 } 38 }
39} 39}
40 40
41#[doc(hidden)]
42/// Implementation details for embassy macros. DO NOT USE.
43pub mod export {
44 #[cfg(feature = "rtos-trace")]
45 pub use rtos_trace::trace;
46
47 /// Expands the given block of code when `embassy-executor` is compiled with
48 /// the `rtos-trace-interrupt` feature.
49 #[doc(hidden)]
50 #[macro_export]
51 #[cfg(feature = "rtos-trace-interrupt")]
52 macro_rules! rtos_trace_interrupt {
53 ($($tt:tt)*) => { $($tt)* };
54 }
55
56 /// Does not expand the given block of code when `embassy-executor` is
57 /// compiled without the `rtos-trace-interrupt` feature.
58 #[doc(hidden)]
59 #[macro_export]
60 #[cfg(not(feature = "rtos-trace-interrupt"))]
61 macro_rules! rtos_trace_interrupt {
62 ($($tt:tt)*) => {};
63 }
64}
65
41pub mod raw; 66pub mod raw;
42 67
43mod spawner; 68mod spawner;
diff --git a/embassy-executor/src/raw/mod.rs b/embassy-executor/src/raw/mod.rs
index afe67decb..c55d10699 100644
--- a/embassy-executor/src/raw/mod.rs
+++ b/embassy-executor/src/raw/mod.rs
@@ -26,6 +26,8 @@ use critical_section::CriticalSection;
26use embassy_time::driver::{self, AlarmHandle}; 26use embassy_time::driver::{self, AlarmHandle};
27#[cfg(feature = "integrated-timers")] 27#[cfg(feature = "integrated-timers")]
28use embassy_time::Instant; 28use embassy_time::Instant;
29#[cfg(feature = "rtos-trace")]
30use rtos_trace::trace;
29 31
30use self::run_queue::{RunQueue, RunQueueItem}; 32use self::run_queue::{RunQueue, RunQueueItem};
31use self::util::UninitCell; 33use self::util::UninitCell;
@@ -306,6 +308,9 @@ impl Executor {
306 /// - `task` must NOT be already enqueued (in this executor or another one). 308 /// - `task` must NOT be already enqueued (in this executor or another one).
307 #[inline(always)] 309 #[inline(always)]
308 unsafe fn enqueue(&self, cs: CriticalSection, task: NonNull<TaskHeader>) { 310 unsafe fn enqueue(&self, cs: CriticalSection, task: NonNull<TaskHeader>) {
311 #[cfg(feature = "rtos-trace")]
312 trace::task_ready_begin(task.as_ptr() as u32);
313
309 if self.run_queue.enqueue(cs, task) { 314 if self.run_queue.enqueue(cs, task) {
310 (self.signal_fn)(self.signal_ctx) 315 (self.signal_fn)(self.signal_ctx)
311 } 316 }
@@ -323,6 +328,9 @@ impl Executor {
323 pub(super) unsafe fn spawn(&'static self, task: NonNull<TaskHeader>) { 328 pub(super) unsafe fn spawn(&'static self, task: NonNull<TaskHeader>) {
324 task.as_ref().executor.set(self); 329 task.as_ref().executor.set(self);
325 330
331 #[cfg(feature = "rtos-trace")]
332 trace::task_new(task.as_ptr() as u32);
333
326 critical_section::with(|cs| { 334 critical_section::with(|cs| {
327 self.enqueue(cs, task); 335 self.enqueue(cs, task);
328 }) 336 })
@@ -365,9 +373,15 @@ impl Executor {
365 return; 373 return;
366 } 374 }
367 375
376 #[cfg(feature = "rtos-trace")]
377 trace::task_exec_begin(p.as_ptr() as u32);
378
368 // Run the task 379 // Run the task
369 task.poll_fn.read()(p as _); 380 task.poll_fn.read()(p as _);
370 381
382 #[cfg(feature = "rtos-trace")]
383 trace::task_exec_end();
384
371 // Enqueue or update into timer_queue 385 // Enqueue or update into timer_queue
372 #[cfg(feature = "integrated-timers")] 386 #[cfg(feature = "integrated-timers")]
373 self.timer_queue.update(p); 387 self.timer_queue.update(p);
@@ -381,6 +395,9 @@ impl Executor {
381 let next_expiration = self.timer_queue.next_expiration(); 395 let next_expiration = self.timer_queue.next_expiration();
382 driver::set_alarm(self.alarm, next_expiration.as_ticks()); 396 driver::set_alarm(self.alarm, next_expiration.as_ticks());
383 } 397 }
398
399 #[cfg(feature = "rtos-trace")]
400 trace::system_idle();
384 } 401 }
385 402
386 /// Get a spawner that spawns tasks in this executor. 403 /// Get a spawner that spawns tasks in this executor.
@@ -426,3 +443,21 @@ unsafe fn _embassy_time_schedule_wake(at: Instant, waker: &core::task::Waker) {
426 let expires_at = task.expires_at.get(); 443 let expires_at = task.expires_at.get();
427 task.expires_at.set(expires_at.min(at)); 444 task.expires_at.set(expires_at.min(at));
428} 445}
446
447#[cfg(feature = "rtos-trace")]
448impl rtos_trace::RtosTraceOSCallbacks for Executor {
449 fn task_list() {
450 // We don't know what tasks exist, so we can't send them.
451 }
452 #[cfg(feature = "integrated-timers")]
453 fn time() -> u64 {
454 Instant::now().as_micros()
455 }
456 #[cfg(not(feature = "integrated-timers"))]
457 fn time() -> u64 {
458 0
459 }
460}
461
462#[cfg(feature = "rtos-trace")]
463rtos_trace::global_os_callbacks! {Executor}
diff --git a/embassy-macros/src/macros/cortex_m_interrupt_take.rs b/embassy-macros/src/macros/cortex_m_interrupt_take.rs
index 9e40a56f1..f6e41bcb4 100644
--- a/embassy-macros/src/macros/cortex_m_interrupt_take.rs
+++ b/embassy-macros/src/macros/cortex_m_interrupt_take.rs
@@ -19,7 +19,13 @@ pub fn run(name: syn::Ident) -> Result<TokenStream, TokenStream> {
19 let func = HANDLER.func.load(interrupt::_export::atomic::Ordering::Relaxed); 19 let func = HANDLER.func.load(interrupt::_export::atomic::Ordering::Relaxed);
20 let ctx = HANDLER.ctx.load(interrupt::_export::atomic::Ordering::Relaxed); 20 let ctx = HANDLER.ctx.load(interrupt::_export::atomic::Ordering::Relaxed);
21 let func: fn(*mut ()) = ::core::mem::transmute(func); 21 let func: fn(*mut ()) = ::core::mem::transmute(func);
22 func(ctx) 22 ::embassy_executor::rtos_trace_interrupt! {
23 ::embassy_executor::export::trace::isr_enter();
24 }
25 func(ctx);
26 ::embassy_executor::rtos_trace_interrupt! {
27 ::embassy_executor::export::trace::isr_exit();
28 }
23 } 29 }
24 30
25 static TAKEN: interrupt::_export::atomic::AtomicBool = interrupt::_export::atomic::AtomicBool::new(false); 31 static TAKEN: interrupt::_export::atomic::AtomicBool = interrupt::_export::atomic::AtomicBool::new(false);
diff --git a/examples/nrf-rtos-trace/.cargo/config.toml b/examples/nrf-rtos-trace/.cargo/config.toml
new file mode 100644
index 000000000..8ca28df39
--- /dev/null
+++ b/examples/nrf-rtos-trace/.cargo/config.toml
@@ -0,0 +1,9 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2# replace nRF82840_xxAA with your chip as listed in `probe-run --list-chips`
3runner = "probe-run --chip nRF52840_xxAA"
4
5[build]
6target = "thumbv7em-none-eabi"
7
8[env]
9DEFMT_LOG = "trace"
diff --git a/examples/nrf-rtos-trace/Cargo.toml b/examples/nrf-rtos-trace/Cargo.toml
new file mode 100644
index 000000000..b0907f92c
--- /dev/null
+++ b/examples/nrf-rtos-trace/Cargo.toml
@@ -0,0 +1,35 @@
1[package]
2edition = "2021"
3name = "embassy-nrf-rtos-trace-examples"
4version = "0.1.0"
5
6[features]
7default = ["log", "nightly"]
8nightly = ["embassy-executor/nightly", "embassy-nrf/nightly", "embassy-nrf/unstable-traits"]
9log = [
10 "dep:log",
11 "embassy-util/log",
12 "embassy-executor/log",
13 "embassy-time/log",
14 "embassy-nrf/log",
15]
16
17[dependencies]
18embassy-util = { version = "0.1.0", path = "../../embassy-util" }
19embassy-executor = { version = "0.1.0", path = "../../embassy-executor", features=["rtos-trace", "rtos-trace-interrupt", "integrated-timers"] }
20embassy-time = { version = "0.1.0", path = "../../embassy-time" }
21embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["nrf52840", "time-driver-rtc1", "gpiote", "unstable-pac"] }
22
23cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
24cortex-m-rt = "0.7.0"
25panic-probe = { version = "0.3" }
26futures = { version = "0.3.17", default-features = false, features = ["async-await"] }
27rand = { version = "0.8.4", default-features = false }
28serde = { version = "1.0.136", default-features = false }
29rtos-trace = "0.1.3"
30systemview-target = { version = "0.1.2", features = ["callbacks-app", "callbacks-os", "log", "cortex-m"] }
31log = { version = "0.4.17", optional = true }
32
33[[bin]]
34name = "rtos_trace"
35required-features = ["nightly"]
diff --git a/examples/nrf-rtos-trace/build.rs b/examples/nrf-rtos-trace/build.rs
new file mode 100644
index 000000000..36cdb65a8
--- /dev/null
+++ b/examples/nrf-rtos-trace/build.rs
@@ -0,0 +1,36 @@
1//! This build script copies the `memory.x` file from the crate root into
2//! a directory where the linker can always find it at build time.
3//! For many projects this is optional, as the linker always searches the
4//! project root directory -- wherever `Cargo.toml` is. However, if you
5//! are using a workspace or have a more complicated build setup, this
6//! build script becomes required. Additionally, by requesting that
7//! Cargo re-run the build script whenever `memory.x` is changed,
8//! updating `memory.x` ensures a rebuild of the application with the
9//! new memory settings.
10
11use std::env;
12use std::fs::File;
13use std::io::Write;
14use std::path::PathBuf;
15
16fn main() {
17 // Put `memory.x` in our output directory and ensure it's
18 // on the linker search path.
19 let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20 File::create(out.join("memory.x"))
21 .unwrap()
22 .write_all(include_bytes!("memory.x"))
23 .unwrap();
24 println!("cargo:rustc-link-search={}", out.display());
25
26 // By default, Cargo will re-run a build script whenever
27 // any file in the project changes. By specifying `memory.x`
28 // here, we ensure the build script is only re-run when
29 // `memory.x` is changed.
30 println!("cargo:rerun-if-changed=memory.x");
31
32 println!("cargo:rustc-link-arg-bins=--nmagic");
33 println!("cargo:rustc-link-arg-bins=-Tlink.x");
34 #[cfg(feature = "defmt")]
35 println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
36}
diff --git a/examples/nrf-rtos-trace/memory.x b/examples/nrf-rtos-trace/memory.x
new file mode 100644
index 000000000..9b04edec0
--- /dev/null
+++ b/examples/nrf-rtos-trace/memory.x
@@ -0,0 +1,7 @@
1MEMORY
2{
3 /* NOTE 1 K = 1 KiBi = 1024 bytes */
4 /* These values correspond to the NRF52840 with Softdevices S140 7.0.1 */
5 FLASH : ORIGIN = 0x00000000, LENGTH = 1024K
6 RAM : ORIGIN = 0x20000000, LENGTH = 256K
7}
diff --git a/examples/nrf-rtos-trace/src/bin/rtos_trace.rs b/examples/nrf-rtos-trace/src/bin/rtos_trace.rs
new file mode 100644
index 000000000..7d1ad87c8
--- /dev/null
+++ b/examples/nrf-rtos-trace/src/bin/rtos_trace.rs
@@ -0,0 +1,69 @@
1#![no_std]
2#![no_main]
3#![feature(type_alias_impl_trait)]
4
5use core::task::Poll;
6
7use embassy_executor::Spawner;
8use embassy_time::{Duration, Instant, Timer};
9#[cfg(feature = "log")]
10use log::*;
11use panic_probe as _;
12// N.B. systemview_target cannot be used at the same time as defmt_rtt.
13use rtos_trace;
14use systemview_target::SystemView;
15
16static LOGGER: systemview_target::SystemView = systemview_target::SystemView::new();
17rtos_trace::global_trace! {SystemView}
18
19struct TraceInfo();
20
21impl rtos_trace::RtosTraceApplicationCallbacks for TraceInfo {
22 fn system_description() {}
23 fn sysclock() -> u32 {
24 64000000
25 }
26}
27rtos_trace::global_application_callbacks! {TraceInfo}
28
29#[embassy_executor::task]
30async fn run1() {
31 loop {
32 #[cfg(feature = "log")]
33 info!("DING DONG");
34 #[cfg(not(feature = "log"))]
35 rtos_trace::trace::marker(13);
36 Timer::after(Duration::from_ticks(16000)).await;
37 }
38}
39
40#[embassy_executor::task]
41async fn run2() {
42 loop {
43 Timer::at(Instant::from_ticks(0)).await;
44 }
45}
46
47#[embassy_executor::task]
48async fn run3() {
49 futures::future::poll_fn(|cx| {
50 cx.waker().wake_by_ref();
51 Poll::<()>::Pending
52 })
53 .await;
54}
55
56#[embassy_executor::main]
57async fn main(spawner: Spawner) {
58 let _p = embassy_nrf::init(Default::default());
59 LOGGER.init();
60 #[cfg(feature = "log")]
61 {
62 ::log::set_logger(&LOGGER).ok();
63 ::log::set_max_level(::log::LevelFilter::Trace);
64 }
65
66 spawner.spawn(run1()).unwrap();
67 spawner.spawn(run2()).unwrap();
68 spawner.spawn(run3()).unwrap();
69}