Repository: tokio-rs/tokio
File: tokio/src/runtime/dump.rs (Rust)

Code before:
    inner: super::task::trace::Trace,
}

impl Trace {
    /// Resolve and return a list of backtraces that are involved in polls in this task.
    pub fn resolve_backtraces(&self) -> Vec<Vec<BacktraceFrame>> {
        self.inner
            .backtraces()
            .iter()
            .map(|backtrace| {
                let mut backtrace = backtrace::Backtrace::from(backtrace.clone());
                backtrace.resolve();
                backtrace
                    .frames()
                    .iter()
                    .map(BacktraceFrame::from_resolved_backtrace_frame)
                    .collect()
            })
            .collect()
    }
}

impl Dump {
    pub(crate) fn new(tasks: Vec<Task>) -> Self {
        Self {
            tasks: Tasks { tasks },
        }
    }

    /// Tasks in this snapshot.
    pub fn tasks(&self) -> &Tasks {
        &self.tasks
    }
}

impl Tasks {
    /// Iterate over tasks.
    pub fn iter(&self) -> impl Iterator<Item = &Task> {
        self.tasks.iter()
    }
}

impl Task {
    pub(crate) fn new(id: Id, trace: super::task::trace::Trace) -> Self {
        Self {
            id,
            trace: Trace { inner: trace },
        }
    }

    /// Returns a [task ID] that uniquely identifies this task relative to other

Review comment (suggestion):
Perhaps we can fix this in the follow up PR, but if we are going to have our own `Backtrace` type, I think we can avoid this conversion by making [`trace_leaf`](https://github.com/tokio-rs/tokio/blob/d08578fc9a950c8ee0ef242dbce0fcaaed5e853f/tokio/src/runtime/task/trace/mod.rs#L153) function construct tokio's Backtrace struct directly.

Code after:
        self.frames.iter()
    }
}

/// An execution trace of a task's last poll.
///
/// <div class="warning">
///
/// Resolving a backtrace, either via the [`Display`][std::fmt::Display] impl or via
/// [`resolve_backtraces`][Trace::resolve_backtraces], parses debuginfo, which is
/// possibly a CPU-expensive operation that can take a platform-specific but
/// long time to run - often over 100 milliseconds, especially if the current
/// process's binary is big. In some cases, the platform might internally cache some of the
/// debuginfo, so successive calls to `resolve_backtraces` might be faster than
/// the first call, but all guarantees are platform-dependent.
///
/// To avoid blocking the runtime, it is recommended
/// that you resolve backtraces inside of a [`spawn_blocking()`][crate::task::spawn_blocking]
/// and to have some concurrency-limiting mechanism to avoid unexpected performance impact.
/// </div>
///
/// See [`Handle::dump`][crate::runtime::Handle::dump].
#[derive(Debug)]
pub struct Trace {
    inner: super::task::trace::Trace,
}

impl Trace {
    /// Resolve and return a list of backtraces that are involved in polls in this trace.
    ///
    /// The exact backtraces included here are unstable and might change in the future,
    /// but you can expect one [`Backtrace`] for every call to
    /// [`poll`] to a bottom-level Tokio future - so if something like [`join!`] is
    /// used, there will be a backtrace for each future in the join.
    ///
    /// [`poll`]: std::future::Future::poll
    /// [`join!`]: macro@join
    pub fn resolve_backtraces(&self) -> Vec<Backtrace> {
        self.inner
            .backtraces()
            .iter()
            .map(|backtrace| {
                let mut backtrace = backtrace::Backtrace::from(backtrace.clone());
                backtrace.resolve();
                Backtrace {
                    frames: backtrace
                        .frames()
                        .iter()
                        .map(BacktraceFrame::from_resolved_backtrace_frame)
                        .collect(),
                }