turbo_tasks/
capture_future.rs1use std::{
2 borrow::Cow,
3 cell::RefCell,
4 fmt::Display,
5 future::Future,
6 panic,
7 pin::Pin,
8 task::{Context, Poll},
9 time::{Duration, Instant},
10};
11
12use anyhow::Result;
13use pin_project_lite::pin_project;
14use serde::{Deserialize, Serialize};
15use turbo_tasks_malloc::{AllocationInfo, TurboMalloc};
16
17use crate::{backend::TurboTasksExecutionErrorMessage, panic_hooks::LAST_ERROR_LOCATION};
18
19struct ThreadLocalData {
20 duration: Duration,
21 allocations: usize,
22 deallocations: usize,
23}
24
25thread_local! {
26 static EXTRA: RefCell<Option<*mut ThreadLocalData>> = const { RefCell::new(None) };
27}
28
29pin_project! {
30 pub struct CaptureFuture<T, F: Future<Output = T>> {
31 #[pin]
32 future: F,
33 duration: Duration,
34 allocations: usize,
35 deallocations: usize,
36 }
37}
38
39impl<T, F: Future<Output = T>> CaptureFuture<T, F> {
40 pub fn new(future: F) -> Self {
41 Self {
42 future,
43 duration: Duration::ZERO,
44 allocations: 0,
45 deallocations: 0,
46 }
47 }
48}
49
50fn try_with_thread_local_data(f: impl FnOnce(&mut ThreadLocalData)) {
51 EXTRA.with_borrow(|cell| {
52 if let Some(data) = cell {
53 unsafe {
55 f(&mut **data);
56 }
57 }
58 });
59}
60
61pub fn add_duration(duration: Duration) {
62 try_with_thread_local_data(|data| {
63 data.duration += duration;
64 });
65}
66
67pub fn add_allocation_info(alloc_info: AllocationInfo) {
68 try_with_thread_local_data(|data| {
69 data.allocations += alloc_info.allocations;
70 data.deallocations += alloc_info.deallocations;
71 });
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
75pub struct TurboTasksPanic {
76 pub message: TurboTasksExecutionErrorMessage,
77 pub location: Option<String>,
78}
79
80impl Display for TurboTasksPanic {
81 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
82 write!(f, "{}", self.message)
83 }
84}
85
86impl<T, F: Future<Output = T>> Future for CaptureFuture<T, F> {
87 type Output = (Result<T, TurboTasksPanic>, Duration, usize);
88
89 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
90 let this = self.project();
91 let start = Instant::now();
92 let start_allocations = TurboMalloc::allocation_counters();
93 let guard = ThreadLocalDataDropGuard;
94 let mut data = ThreadLocalData {
95 duration: Duration::ZERO,
96 allocations: 0,
97 deallocations: 0,
98 };
99 EXTRA.with_borrow_mut(|cell| {
100 *cell = Some(&mut data as *mut ThreadLocalData);
101 });
102
103 let result =
104 panic::catch_unwind(panic::AssertUnwindSafe(|| this.future.poll(cx))).map_err(|err| {
105 let message = match err.downcast_ref::<&'static str>() {
106 Some(s) => TurboTasksExecutionErrorMessage::PIISafe(Cow::Borrowed(s)),
107 None => match err.downcast_ref::<String>() {
108 Some(s) => TurboTasksExecutionErrorMessage::NonPIISafe(s.clone()),
109 None => {
110 let error_message = err
111 .downcast_ref::<Box<dyn Display>>()
112 .map(|e| e.to_string())
113 .unwrap_or_else(|| String::from("<unknown panic>"));
114
115 TurboTasksExecutionErrorMessage::NonPIISafe(error_message)
116 }
117 },
118 };
119
120 LAST_ERROR_LOCATION.with_borrow(|loc| TurboTasksPanic {
121 message,
122 location: loc.clone(),
123 })
124 });
125
126 drop(guard);
127 let elapsed = start.elapsed();
128 let allocations = start_allocations.until_now();
129 *this.duration += elapsed + data.duration;
130 *this.allocations += allocations.allocations + data.allocations;
131 *this.deallocations += allocations.deallocations + data.deallocations;
132 match result {
133 Err(err) => {
134 let memory_usage = this.allocations.saturating_sub(*this.deallocations);
135 Poll::Ready((Err(err), *this.duration, memory_usage))
136 }
137 Ok(Poll::Ready(r)) => {
138 let memory_usage = this.allocations.saturating_sub(*this.deallocations);
139 Poll::Ready((Ok(r), *this.duration, memory_usage))
140 }
141 Ok(Poll::Pending) => Poll::Pending,
142 }
143 }
144}
145
146struct ThreadLocalDataDropGuard;
147
148impl Drop for ThreadLocalDataDropGuard {
149 fn drop(&mut self) {
150 EXTRA.with_borrow_mut(|cell| {
151 *cell = None;
152 });
153 }
154}