aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/src/raw/trace.rs
diff options
context:
space:
mode:
authorJames Munns <[email protected]>2025-04-01 14:06:04 +0200
committerJames Munns <[email protected]>2025-04-01 14:06:04 +0200
commit882e2180a4ec7f448ea4ddaccf2a65e6757654c7 (patch)
tree0241b22d69c03f2ea9b55343259839570ec9255b /embassy-executor/src/raw/trace.rs
parenta44abaf7e4562fa5393087fd845bf0d02141325b (diff)
Add docs, add `task_end` trace point
Diffstat (limited to 'embassy-executor/src/raw/trace.rs')
-rw-r--r--embassy-executor/src/raw/trace.rs149
1 files changed, 149 insertions, 0 deletions
diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs
index b34387b58..57222d60b 100644
--- a/embassy-executor/src/raw/trace.rs
+++ b/embassy-executor/src/raw/trace.rs
@@ -1,16 +1,157 @@
1#![allow(unused)] 1#![allow(unused)]
2use crate::raw::{SyncExecutor, TaskRef}; 2use crate::raw::{SyncExecutor, TaskRef};
3 3
4//! # Tracing
5//!
6//! The `trace` feature enables a number of callbacks that can be used to track the
7//! lifecycle of tasks and/or executors.
8//!
9//! Callbacks will have one or both of the following IDs passed to them:
10//!
11//! 1. A `task_id`, a `u32` value unique to a task for the duration of the time it is valid
12//! 2. An `executor_id`, a `u32` value unique to an executor for the duration of the time it is
13//! valid
14//!
15//! Today, both `task_id` and `executor_id` are u32s containing the least significant 32 bits of
16//! the address of the task or executor, however this is NOT a stable guarantee, and MAY change
17//! at any time.
18//!
19//! IDs are only guaranteed to be unique for the duration of time the item is valid. If a task
20//! ends, and is respond, it MAY or MAY NOT have the same ID. For tasks, this time is defined
21//! as the time between `_embassy_trace_task_new` and `_embassy_trace_task_end` for a given task.
22//! For executors, this time is not defined, but is often "forever" for practical embedded
23//! programs.
24//!
25//! Callbacks can be used by enabling the `trace` feature, and providing implementations of the
26//! `extern "Rust"` functions below. All callbacks must be implemented.
27//!
28//! ## Stability
29//!
30//! The `trace` interface is considered unstable. Callbacks may change, be added, or be removed
31//! in any minor or trivial release.
32//!
33//! ## Task Tracing lifecycle
34//!
35//! ```text
36//! ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
37//! │(1) │
38//! │ │
39//! ╔════▼════╗ (2) ┌─────────┐ (3) ┌─────────┐ │
40//! │ ║ SPAWNED ║────▶│ WAITING │────▶│ RUNNING │
41//! ╚═════════╝ └─────────┘ └─────────┘ │
42//! │ ▲ ▲ │ │ │
43//! │ (4) │ │(6) │
44//! │ │ └ ─ ─ ┘ │ │
45//! │ │ │ │
46//! │ ┌──────┐ (5) │ │ ┌─────┐
47//! │ IDLE │◀────────────────┘ └─▶│ END │ │
48//! │ └──────┘ └─────┘
49//! ┌──────────────────────┐ │
50//! └ ┤ Task Trace Lifecycle │─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
51//! └──────────────────────┘
52//! ```
53//!
54//! 1. A task is spawned. `_embassy_trace_task_new` is called
55//! 2. A task is enqueued for the first time, `_embassy_trace_task_ready_begin` is called
56//! 3. A task is polled, `_embassy_trace_task_exec_begin` is called
57//! 4. WHILE a task is polled, the task is re-awoken, and `_embassy_trace_task_ready_begin` is
58//! called. The task does not IMMEDIATELY move state, until polling is complete and the
59//! RUNNING state is existed. `_embassy_trace_task_exec_end` is called when polling is
60//! complete, marking the transition to WAITING
61//! 5. Polling is complete, `_embassy_trace_task_exec_end` is called
62//! 6. The task has completed, and `_embassy_trace_task_end` is called.
63//!
64//! ## Executor Tracing lifecycle
65//!
66//! ```text
67//! ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
68//! │(1) │
69//! │ │
70//! ╔═══▼══╗ (2) ┌────────────┐ (3) ┌─────────┐ │
71//! │ ║ IDLE ║──────────▶│ SCHEDULING │──────▶│ POLLING │
72//! ╚══════╝ └────────────┘ └─────────┘ │
73//! │ ▲ │ ▲ │
74//! │ (5) │ │ (4) │ │
75//! │ └──────────────┘ └────────────┘
76//! ┌──────────────────────────┐ │
77//! └ ┤ Executor Trace Lifecycle │─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
78//! └──────────────────────────┘
79//! ```
80//!
81//! 1. The executor is started (no associated trace)
82//! 2. A task on this executor is awoken. `_embassy_trace_task_ready_begin` is called
83//! when this occurs, and `_embassy_trace_poll_start` is called when the executor
84//! actually begins running.
85//! 3. The executor has decided a task to poll. `_embassy_trace_task_exec_begin` is called.
86//! 4. The executor finishes polling the task. `_embassy_trace_task_exec_end` is called.
87//! 5. The executor has finished polling tasks. `_embassy_trace_executor_idle` is called.
88
4#[cfg(not(feature = "rtos-trace"))] 89#[cfg(not(feature = "rtos-trace"))]
5extern "Rust" { 90extern "Rust" {
91 /// This callback is called when the executor begins polling. This will always
92 /// be paired with a later call to `_embassy_trace_executor_idle`.
93 ///
94 /// This marks the EXECUTOR state transition from IDLE -> SCHEDULING.
95 fn _embassy_trace_poll_start(executor_id: u32);
96
97 /// This callback is called AFTER a task is initialized/allocated, and BEFORE
98 /// it is enqueued to run for the first time. If the task ends (and does not
99 /// loop "forever"), there will be a matching call to `_embassy_trace_task_end`.
100 ///
101 /// Tasks start life in the SPAWNED state.
6 fn _embassy_trace_task_new(executor_id: u32, task_id: u32); 102 fn _embassy_trace_task_new(executor_id: u32, task_id: u32);
103
104 /// This callback is called AFTER a task is destructed/freed. This will always
105 /// have a prior matching call to `_embassy_trace_task_new`.
106 fn _embassy_trace_task_end(executor_id: u32, task_id: u32);
107
108 /// This callback is called AFTER a task has been dequeued from the runqueue,
109 /// and BEFORE the task is polled. There will always be a matching call to
110 /// `_embassy_trace_task_exec_end`.
111 ///
112 /// This marks the TASK state transition from WAITING -> RUNNING
113 /// This marks the EXECUTOR state transition from SCHEDULING -> POLLING
7 fn _embassy_trace_task_exec_begin(executor_id: u32, task_id: u32); 114 fn _embassy_trace_task_exec_begin(executor_id: u32, task_id: u32);
115
116 /// This callback is called AFTER a task has completed polling. There will
117 /// always be a matching call to `_embassy_trace_task_exec_begin`.
118 ///
119 /// This marks the TASK state transition from either:
120 /// * RUNNING -> IDLE - if there were no `_embassy_trace_task_ready_begin` events
121 /// for this task since the last `_embassy_trace_task_exec_begin` for THIS task
122 /// * RUNNING -> WAITING - if there WAS a `_embassy_trace_task_ready_begin` event
123 /// for this task since the last `_embassy_trace_task_exec_begin` for THIS task
124 ///
125 /// This marks the EXECUTOR state transition from POLLING -> SCHEDULING
8 fn _embassy_trace_task_exec_end(excutor_id: u32, task_id: u32); 126 fn _embassy_trace_task_exec_end(excutor_id: u32, task_id: u32);
127
128 /// This callback is called AFTER the waker for a task is awoken, and BEFORE it
129 /// is added to the run queue.
130 ///
131 /// If the given task is currently RUNNING, this marks no state change, BUT the
132 /// RUNNING task will then move to the WAITING stage when polling is complete.
133 ///
134 /// If the given task is currently IDLE, this marks the TASK state transition
135 /// from IDLE -> WAITING.
9 fn _embassy_trace_task_ready_begin(executor_id: u32, task_id: u32); 136 fn _embassy_trace_task_ready_begin(executor_id: u32, task_id: u32);
137
138 /// This callback is called AFTER all dequeued tasks in a single call to poll
139 /// have been processed. This will always be paired with a call to
140 /// `_embassy_trace_executor_idle`.
141 ///
142 /// This marks the EXECUTOR state transition from
10 fn _embassy_trace_executor_idle(executor_id: u32); 143 fn _embassy_trace_executor_idle(executor_id: u32);
11} 144}
12 145
13#[inline] 146#[inline]
147pub(crate) fn poll_start(executor: &SyncExecutor) {
148 #[cfg(not(feature = "rtos-trace"))]
149 unsafe {
150 _embassy_trace_poll_start(executor as *const _ as u32)
151 }
152}
153
154#[inline]
14pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) { 155pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) {
15 #[cfg(not(feature = "rtos-trace"))] 156 #[cfg(not(feature = "rtos-trace"))]
16 unsafe { 157 unsafe {
@@ -22,6 +163,14 @@ pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) {
22} 163}
23 164
24#[inline] 165#[inline]
166pub(crate) fn task_end(executor: &SyncExecutor, task: &TaskRef) {
167 #[cfg(not(feature = "rtos-trace"))]
168 unsafe {
169 _embassy_trace_task_end(executor as *const _ as u32, task.as_ptr() as u32)
170 }
171}
172
173#[inline]
25pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) { 174pub(crate) fn task_ready_begin(executor: &SyncExecutor, task: &TaskRef) {
26 #[cfg(not(feature = "rtos-trace"))] 175 #[cfg(not(feature = "rtos-trace"))]
27 unsafe { 176 unsafe {