tokio/runtime/dump.rs
1//! Snapshots of runtime state.
2//!
3//! See [`Handle::dump`][crate::runtime::Handle::dump].
4
5use crate::task::Id;
6use std::{fmt, future::Future, path::Path};
7
8pub use crate::runtime::task::trace::Root;
9
10/// A snapshot of a runtime's state.
11///
12/// See [`Handle::dump`][crate::runtime::Handle::dump].
13#[derive(Debug)]
14pub struct Dump {
15 tasks: Tasks,
16}
17
18/// Snapshots of tasks.
19///
20/// See [`Handle::dump`][crate::runtime::Handle::dump].
21#[derive(Debug)]
22pub struct Tasks {
23 tasks: Vec<Task>,
24}
25
26/// A snapshot of a task.
27///
28/// See [`Handle::dump`][crate::runtime::Handle::dump].
29#[derive(Debug)]
30pub struct Task {
31 id: Id,
32 trace: Trace,
33}
34
35/// Represents an address that should not be dereferenced.
36///
37/// This type exists to get the auto traits correct, the public API
38/// uses raw pointers to make life easier for users.
39#[derive(Copy, Clone, Debug)]
40struct Address(*mut std::ffi::c_void);
41
42// Safe since Address should not be dereferenced
43unsafe impl Send for Address {}
44unsafe impl Sync for Address {}
45
46/// A backtrace symbol.
47///
48/// This struct provides accessors for backtrace symbols, similar to [`backtrace::BacktraceSymbol`].
49#[derive(Clone, Debug)]
50pub struct BacktraceSymbol {
51 name: Option<Box<[u8]>>,
52 name_demangled: Option<Box<str>>,
53 addr: Option<Address>,
54 filename: Option<std::path::PathBuf>,
55 lineno: Option<u32>,
56 colno: Option<u32>,
57}
58
59impl BacktraceSymbol {
60 pub(crate) fn from_backtrace_symbol(sym: &backtrace::BacktraceSymbol) -> Self {
61 let name = sym.name();
62 Self {
63 name: name.as_ref().map(|name| name.as_bytes().into()),
64 name_demangled: name.map(|name| format!("{}", name).into()),
65 addr: sym.addr().map(Address),
66 filename: sym.filename().map(From::from),
67 lineno: sym.lineno(),
68 colno: sym.colno(),
69 }
70 }
71
72 /// Return the raw name of the symbol.
73 pub fn name_raw(&self) -> Option<&[u8]> {
74 self.name.as_deref()
75 }
76
77 /// Return the demangled name of the symbol.
78 pub fn name_demangled(&self) -> Option<&str> {
79 self.name_demangled.as_deref()
80 }
81
82 /// Returns the starting address of this symbol.
83 pub fn addr(&self) -> Option<*mut std::ffi::c_void> {
84 self.addr.map(|addr| addr.0)
85 }
86
87 /// Returns the file name where this function was defined. If debuginfo
88 /// is missing, this is likely to return None.
89 pub fn filename(&self) -> Option<&Path> {
90 self.filename.as_deref()
91 }
92
93 /// Returns the line number for where this symbol is currently executing.
94 ///
95 /// If debuginfo is missing, this is likely to return `None`.
96 pub fn lineno(&self) -> Option<u32> {
97 self.lineno
98 }
99
100 /// Returns the column number for where this symbol is currently executing.
101 ///
102 /// If debuginfo is missing, this is likely to return `None`.
103 pub fn colno(&self) -> Option<u32> {
104 self.colno
105 }
106}
107
108/// A backtrace frame.
109///
110/// This struct represents one stack frame in a captured backtrace, similar to [`backtrace::BacktraceFrame`].
111#[derive(Clone, Debug)]
112pub struct BacktraceFrame {
113 ip: Address,
114 symbol_address: Address,
115 symbols: Box<[BacktraceSymbol]>,
116}
117
118impl BacktraceFrame {
119 pub(crate) fn from_resolved_backtrace_frame(frame: &backtrace::BacktraceFrame) -> Self {
120 Self {
121 ip: Address(frame.ip()),
122 symbol_address: Address(frame.symbol_address()),
123 symbols: frame
124 .symbols()
125 .iter()
126 .map(BacktraceSymbol::from_backtrace_symbol)
127 .collect(),
128 }
129 }
130
131 /// Return the instruction pointer of this frame.
132 ///
133 /// See the ABI docs for your platform for the exact meaning.
134 pub fn ip(&self) -> *mut std::ffi::c_void {
135 self.ip.0
136 }
137
138 /// Returns the starting symbol address of the frame of this function.
139 pub fn symbol_address(&self) -> *mut std::ffi::c_void {
140 self.symbol_address.0
141 }
142
143 /// Return an iterator over the symbols of this backtrace frame.
144 ///
145 /// Due to inlining, it is possible for there to be multiple [`BacktraceSymbol`] items relating
146 /// to a single frame. The first symbol listed is the "innermost function",
147 /// whereas the last symbol is the outermost (last caller).
148 pub fn symbols(&self) -> impl Iterator<Item = &BacktraceSymbol> {
149 self.symbols.iter()
150 }
151}
152
153/// A captured backtrace.
154///
155/// This struct provides access to each backtrace frame, similar to [`backtrace::Backtrace`].
156#[derive(Clone, Debug)]
157pub struct Backtrace {
158 frames: Box<[BacktraceFrame]>,
159}
160
161impl Backtrace {
162 /// Return the frames in this backtrace, innermost (in a task dump,
163 /// likely to be a leaf future's poll function) first.
164 pub fn frames(&self) -> impl Iterator<Item = &BacktraceFrame> {
165 self.frames.iter()
166 }
167}
168
169/// An execution trace of a task's last poll.
170///
171/// <div class="warning">
172///
173/// Resolving a backtrace, either via the [`Display`][std::fmt::Display] impl or via
174/// [`resolve_backtraces`][Trace::resolve_backtraces], parses debuginfo, which is
175/// possibly a CPU-expensive operation that can take a platform-specific but
176/// long time to run - often over 100 milliseconds, especially if the current
177/// process's binary is big. In some cases, the platform might internally cache some of the
178/// debuginfo, so successive calls to `resolve_backtraces` might be faster than
179/// the first call, but all guarantees are platform-dependent.
180///
181/// To avoid blocking the runtime, it is recommended
182/// that you resolve backtraces inside of a [`spawn_blocking()`][crate::task::spawn_blocking]
183/// and to have some concurrency-limiting mechanism to avoid unexpected performance impact.
184/// </div>
185///
186/// See [`Handle::dump`][crate::runtime::Handle::dump].
187#[derive(Debug)]
188pub struct Trace {
189 inner: super::task::trace::Trace,
190}
191
192impl Trace {
193 /// Resolve and return a list of backtraces that are involved in polls in this trace.
194 ///
195 /// The exact backtraces included here are unstable and might change in the future,
196 /// but you can expect one [`Backtrace`] for every call to
197 /// [`poll`] to a bottom-level Tokio future - so if something like [`join!`] is
198 /// used, there will be a backtrace for each future in the join.
199 ///
200 /// [`poll`]: std::future::Future::poll
201 /// [`join!`]: macro@join
202 pub fn resolve_backtraces(&self) -> Vec<Backtrace> {
203 self.inner
204 .backtraces()
205 .iter()
206 .map(|backtrace| {
207 let mut backtrace = backtrace::Backtrace::from(backtrace.clone());
208 backtrace.resolve();
209 Backtrace {
210 frames: backtrace
211 .frames()
212 .iter()
213 .map(BacktraceFrame::from_resolved_backtrace_frame)
214 .collect(),
215 }
216 })
217 .collect()
218 }
219
220 /// Runs the function `f` in tracing mode, and returns its result along with the resulting [`Trace`].
221 ///
222 /// This is normally called with `f` being the poll function of a future, and will give you a backtrace
223 /// that tells you what that one future is doing.
224 ///
225 /// Use [`Handle::dump`] instead if you want to know what *all the tasks* in your program are doing.
226 /// Also see [`Handle::dump`] for more documentation about dumps, but unlike [`Handle::dump`], this function
227 /// should not be much slower than calling `f` directly.
228 ///
229 /// Due to the way tracing is implemented, Tokio leaf futures will usually, instead of doing their
230 /// actual work, do the equivalent of a `yield_now` (returning a `Poll::Pending` and scheduling the
231 /// current context for execution), which means forward progress will probably not happen unless
232 /// you eventually call your future outside of `capture`.
233 ///
234 /// [`Handle::dump`]: crate::runtime::Handle::dump
235 ///
236 /// Example usage:
237 /// ```
238 /// use std::future::Future;
239 /// use std::task::Poll;
240 /// use tokio::runtime::dump::Trace;
241 ///
242 /// # async fn test_fn() {
243 /// // some future
244 /// let mut test_future = std::pin::pin!(async move { tokio::task::yield_now().await; 0 });
245 ///
246 /// // trace it once, see what it's doing
247 /// let (trace, res) = Trace::root(std::future::poll_fn(|cx| {
248 /// let (res, trace) = Trace::capture(|| test_future.as_mut().poll(cx));
249 /// Poll::Ready((trace, res))
250 /// })).await;
251 ///
252 /// // await it to let it finish, outside of a `capture`
253 /// let output = match res {
254 /// Poll::Ready(output) => output,
255 /// Poll::Pending => test_future.await,
256 /// };
257 ///
258 /// println!("{trace}");
259 /// # }
260 /// ```
261 ///
262 /// ### Nested calls
263 ///
264 /// Nested calls to `capture` might return partial traces, but will not do any other undesirable behavior (for
265 /// example, they will not panic).
266 pub fn capture<F, R>(f: F) -> (R, Trace)
267 where
268 F: FnOnce() -> R,
269 {
270 let (res, trace) = super::task::trace::Trace::capture(f);
271 (res, Trace { inner: trace })
272 }
273
274 /// Create a root for stack traces captured using [`Trace::capture`]. Stack frames above
275 /// the root will not be captured.
276 ///
277 /// Nesting multiple [`Root`] futures is fine. Captures will stop at the first root. Not having
278 /// a [`Root`] is fine as well, but there is no guarantee on where the capture will stop.
279 pub fn root<F>(f: F) -> Root<F>
280 where
281 F: Future,
282 {
283 crate::runtime::task::trace::Trace::root(f)
284 }
285}
286
287impl Dump {
288 pub(crate) fn new(tasks: Vec<Task>) -> Self {
289 Self {
290 tasks: Tasks { tasks },
291 }
292 }
293
294 /// Tasks in this snapshot.
295 pub fn tasks(&self) -> &Tasks {
296 &self.tasks
297 }
298}
299
300impl Tasks {
301 /// Iterate over tasks.
302 pub fn iter(&self) -> impl Iterator<Item = &Task> {
303 self.tasks.iter()
304 }
305}
306
307impl Task {
308 pub(crate) fn new(id: Id, trace: super::task::trace::Trace) -> Self {
309 Self {
310 id,
311 trace: Trace { inner: trace },
312 }
313 }
314
315 /// Returns a [task ID] that uniquely identifies this task relative to other
316 /// tasks spawned at the time of the dump.
317 ///
318 /// **Note**: This is an [unstable API][unstable]. The public API of this type
319 /// may break in 1.x releases. See [the documentation on unstable
320 /// features][unstable] for details.
321 ///
322 /// [task ID]: crate::task::Id
323 /// [unstable]: crate#unstable-features
324 #[cfg(tokio_unstable)]
325 #[cfg_attr(docsrs, doc(cfg(tokio_unstable)))]
326 pub fn id(&self) -> Id {
327 self.id
328 }
329
330 /// A trace of this task's state.
331 pub fn trace(&self) -> &Trace {
332 &self.trace
333 }
334}
335
336impl fmt::Display for Trace {
337 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
338 self.inner.fmt(f)
339 }
340}