Skip to content

Commit 1716248

Browse files
author
Ariel Ben-Yehuda
committed
make self-tracing public
1 parent 3b677d1 commit 1716248

File tree

3 files changed

+120
-2
lines changed

3 files changed

+120
-2
lines changed

tokio/src/runtime/dump.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,14 @@
33
//! See [Handle::dump][crate::runtime::Handle::dump].
44
55
use crate::task::Id;
6-
use std::fmt;
6+
use std::{fmt, future::Future};
7+
8+
pub use crate::runtime::task::trace::Root;
9+
10+
/// missing dok
11+
pub fn root<F: Future>(f: F) -> Root<F> {
12+
crate::runtime::task::trace::Trace::root(f)
13+
}
714

815
/// A snapshot of a runtime's state.
916
///
@@ -38,6 +45,25 @@ pub struct Trace {
3845
inner: super::task::trace::Trace,
3946
}
4047

48+
impl Trace {
49+
/// document
50+
pub fn capture<F, R>(f: F) -> (R, Trace)
51+
where
52+
F: FnOnce() -> R,
53+
{
54+
let (res, trace) = super::task::trace::Trace::capture(f);
55+
(res, Trace { inner: trace })
56+
}
57+
58+
/// doc doc doc
59+
pub fn root<F>(f: F) -> Root<F>
60+
where
61+
F: Future,
62+
{
63+
crate::runtime::task::trace::Trace::root(f)
64+
}
65+
}
66+
4167
impl Dump {
4268
pub(crate) fn new(tasks: Vec<Task>) -> Self {
4369
Self {

tokio/src/runtime/task/trace/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ pub(crate) struct Trace {
5656
pin_project_lite::pin_project! {
5757
#[derive(Debug, Clone)]
5858
#[must_use = "futures do nothing unless you `.await` or poll them"]
59-
pub(crate) struct Root<T> {
59+
/// Dok: roots a trace
60+
pub struct Root<T> {
6061
#[pin]
6162
future: T,
6263
}

tokio/tests/task_trace_self.rs

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#![allow(unexpected_cfgs)]
2+
#![cfg(all(
3+
tokio_unstable,
4+
tokio_taskdump,
5+
feature = "full",
6+
not(target_os = "wasi"),
7+
not(miri)
8+
))] // Wasi doesn't support bind
9+
10+
use std::{
11+
future::Future,
12+
mem,
13+
pin::Pin,
14+
sync::{Arc, Mutex},
15+
task::{Context, Poll},
16+
time::{Duration, Instant},
17+
};
18+
19+
use tokio::runtime::dump::{Root, Trace};
20+
21+
pin_project_lite::pin_project! { pub struct PrettyFuture<F: Future> {
22+
#[pin]
23+
f: Root<F>,
24+
t_last: Option<Instant>,
25+
logs: Arc<Mutex<Vec<Trace>>>,
26+
}
27+
}
28+
29+
impl<F: Future> PrettyFuture<F> {
30+
pub fn pretty(f: F, logs: Arc<Mutex<Vec<Trace>>>) -> Self {
31+
PrettyFuture {
32+
f: Trace::root(f),
33+
t_last: None,
34+
logs,
35+
}
36+
}
37+
}
38+
39+
impl<F: Future> Future for PrettyFuture<F> {
40+
type Output = F::Output;
41+
42+
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<F::Output> {
43+
let mut this = self.project();
44+
let now = Instant::now();
45+
let t_last = mem::replace(this.t_last, Some(now));
46+
if t_last.is_some_and(|t_last| now.duration_since(t_last) > Duration::from_millis(10)) {
47+
let (res, trace) = tokio::runtime::dump::Trace::capture(|| this.f.as_mut().poll(cx));
48+
this.logs.lock().unwrap().push(trace);
49+
return res;
50+
}
51+
this.f.as_mut().poll(cx)
52+
}
53+
}
54+
55+
#[tokio::test]
56+
async fn task_trace_self() {
57+
let log = Arc::new(Mutex::new(vec![]));
58+
let log2 = Arc::new(Mutex::new(vec![]));
59+
let mut good_line = vec![];
60+
let mut bad_line = vec![];
61+
PrettyFuture::pretty(
62+
PrettyFuture::pretty(
63+
async {
64+
bad_line.push(line!() + 1);
65+
tokio::task::yield_now().await;
66+
bad_line.push(line!() + 1);
67+
tokio::time::sleep(Duration::from_millis(1)).await;
68+
good_line.push(line!() + 1);
69+
tokio::time::sleep(Duration::from_millis(1000)).await;
70+
},
71+
log.clone(),
72+
),
73+
log2.clone(),
74+
)
75+
.await;
76+
for line in good_line {
77+
let s = format!("{}:{}:", file!(), line);
78+
assert!(log.lock().unwrap().iter().any(|x| {
79+
eprintln!("{}", x);
80+
format!("{}", x).contains(&s)
81+
}));
82+
}
83+
for line in bad_line {
84+
let s = format!("{}:{}:", file!(), line);
85+
assert!(!log
86+
.lock()
87+
.unwrap()
88+
.iter()
89+
.any(|x| format!("{}", x).contains(&s)));
90+
}
91+
}

0 commit comments

Comments
 (0)