Skip to content

Commit

Permalink
perf(turbo-tasks): Use native async traits for TaskInput (not the asy…
Browse files Browse the repository at this point in the history
…nc_trait macro) (vercel#70084)

## What?

Use rustc's relatively new native support for async traits: https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html
Instead of the `async_trait` macro: https://docs.rs/async-trait/latest/async_trait/

The main differences are:

- `async_trait` supports dynamic dispatch. The compiler-native version does not yet.
- The compiler-native version often requires using messier `-> impl Future<...> + Send + '_` return types to declare additional bounds (usually `Send`).
- `async_trait` forcibly boxes your returned `Future<...>` as a `Box<dyn Future<...>>`.

## Why?

- We don't need dynamic dispatch.
- Most of the `TaskInput` code is macro-generated, so the uglier `impl Future` syntax doesn't matter.
- This is a hot codepath, and there's overhead associated with boxing a `dyn Future`. Removing the dynamic dispatch avoids pointer indirection and gives the compiler more opportunities to inline code.

## Benchmarks

No measurable change.

```
cargo bench -p turbopack-bench -p turbopack-cli -- "hmr_to_eval/Turbopack CSR"
```

```
bench_hmr_to_eval/Turbopack CSR/1000 modules
                        time:   [15.439 ms 15.633 ms 15.978 ms]
                        change: [-1.3769% +1.0017% +3.3534%] (p = 0.46 > 0.05)
                        No change in performance detected.
```


```
TURBOPACK_BENCH_STRESS=yes cargo bench -p turbo-tasks-memory 500
```

```
turbo_tasks_memory_stress/fibonacci/500
                        time:   [539.45 ms 544.10 ms 548.41 ms]
                        thrpt:  [228.39 Kelem/s 230.20 Kelem/s 232.18 Kelem/s]
                 change:
                        time:   [-1.3718% -0.1154% +1.1538%] (p = 0.87 > 0.05)
                        thrpt:  [-1.1406% +0.1155% +1.3909%]
                        No change in performance detected.
Found 1 outliers among 20 measurements (5.00%)
  1 (5.00%) low mild
```
  • Loading branch information
bgw authored Sep 13, 2024
1 parent 5732610 commit 6d8cd42
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 12 deletions.
13 changes: 11 additions & 2 deletions turbopack/crates/turbo-tasks-macros/src/derive/task_input_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,8 +168,17 @@ pub fn derive_task_input(input: TokenStream) -> TokenStream {

#[allow(non_snake_case)]
#[allow(unreachable_code)] // This can occur for enums with no variants.
async fn resolve(&self) -> turbo_tasks::Result<Self> {
#resolve_impl
#[allow(clippy::manual_async_fn)] // some impls need the manual return type to work :(
fn resolve(
&self,
) -> impl
::std::future::Future<Output = turbo_tasks::Result<Self>> +
::std::marker::Send +
'_
{
async move {
#resolve_impl
}
}
}
}
Expand Down
13 changes: 3 additions & 10 deletions turbopack/crates/turbo-tasks/src/task/task_input.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::{any::Any, fmt::Debug, hash::Hash};
use std::{any::Any, fmt::Debug, future::Future, hash::Hash};

use anyhow::Result;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};

use crate::{
Expand All @@ -12,10 +11,9 @@ use crate::{
/// [`#[turbo_tasks::function]`][crate::function] argument.
///
/// See also [`ConcreteTaskInput`].
#[async_trait]
pub trait TaskInput: Send + Sync + Clone + Debug + PartialEq + Eq + Hash {
async fn resolve(&self) -> Result<Self> {
Ok(self.clone())
fn resolve(&self) -> impl Future<Output = Result<Self>> + Send + '_ {
async { Ok(self.clone()) }
}
fn is_resolved(&self) -> bool {
true
Expand All @@ -28,7 +26,6 @@ pub trait TaskInput: Send + Sync + Clone + Debug + PartialEq + Eq + Hash {
macro_rules! impl_task_input {
($($t:ty),*) => {
$(
#[async_trait]
impl TaskInput for $t {}
)*
};
Expand All @@ -48,7 +45,6 @@ impl_task_input! {
ValueTypeId
}

#[async_trait]
impl<T> TaskInput for Vec<T>
where
T: TaskInput,
Expand All @@ -70,7 +66,6 @@ where
}
}

#[async_trait]
impl<T> TaskInput for Option<T>
where
T: TaskInput,
Expand All @@ -97,7 +92,6 @@ where
}
}

#[async_trait]
impl<T> TaskInput for Vc<T>
where
T: Send,
Expand Down Expand Up @@ -220,7 +214,6 @@ impl<'de, T> Deserialize<'de> for TransientInstance<T> {

macro_rules! tuple_impls {
( $( $name:ident )+ ) => {
#[async_trait]
impl<$($name: TaskInput),+> TaskInput for ($($name,)+)
where $($name: TaskInput),+
{
Expand Down

0 comments on commit 6d8cd42

Please sign in to comment.