Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Turbopack] improve task aggregation update #74771

Merged
merged 9 commits into from
Jan 14, 2025
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
add test case
  • Loading branch information
sokra committed Jan 14, 2025

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 975663661d710440c79cc3e0f279975c43079d79
193 changes: 175 additions & 18 deletions turbopack/crates/turbo-tasks-testing/tests/performance.rs
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@

use std::{future::Future, time::Duration};

use anyhow::Result;
use turbo_tasks::{TransientInstance, Vc};
use turbo_tasks_testing::{register, run, Registration};

@@ -13,22 +14,26 @@ const COUNT1: u32 = 100;
const COUNT2: u32 = 2000;

async fn run_test<F, T>(
f: impl Fn() -> F + Sync + Send + Copy + 'static,
f: impl Fn() -> F + Sync + Send + Clone + 'static,
limit: Duration,
) -> anyhow::Result<()>
where
F: Future<Output = anyhow::Result<T>> + Sync + Send + 'static,
{
// The first call will actually execute many_children and its children.
// The first call will actually execute everything.
let start = std::time::Instant::now();
f().await?;
println!("Initial call took {:?}", start.elapsed());

// The second call will connect to the cached many_children, but it would be ok if that's
// not yet optimized.
let start = std::time::Instant::now();
f().await?;
println!("Second call took {:?}", start.elapsed());
let mut warmup_calls = Vec::new();

for _ in 0..10 {
let start = std::time::Instant::now();
f().await?;
let warmup_call = start.elapsed();
println!("Subsequent call took {:?}", warmup_call);
warmup_calls.push(warmup_call);
}

// Susbsequent calls should be very fast.
let start = std::time::Instant::now();
@@ -96,6 +101,17 @@ where
let final_call = start.elapsed();
println!("Final call took {:?}", final_call);

let target = subsequent / COUNT1;

for (i, warmup_call) in warmup_calls.into_iter().enumerate() {
assert!(
warmup_call < target * 10,
"Warmup call {} should be less than {:?}",
i,
target * 10
);
}

assert!(
subsequent < limit * COUNT1,
"Each call should be less than {:?}",
@@ -117,16 +133,23 @@ where
anyhow::Ok(())
}

#[tokio::test]
async fn many_calls_to_many_children() {
fn check_skip() -> bool {
// if matches!(
// std::env::var("TURBOPACK_TEST_PERFORMANCE").ok().as_deref(),
// None | Some("") | Some("no") | Some("false")
// ) {
// println!("Skipping test, pass `TURBOPACK_TEST_PERFORMANCE=yes` to run it");
// return;
// return true;
// }

false
}

#[tokio::test]
async fn many_calls_to_many_children() {
if check_skip() {
return;
}
run(&REGISTRATION, || {
run_test(
|| calls_many_children(TransientInstance::new(()), None).strongly_consistent(),
@@ -139,14 +162,9 @@ async fn many_calls_to_many_children() {

#[tokio::test]
async fn many_calls_to_uncached_many_children() {
// if matches!(
// std::env::var("TURBOPACK_TEST_PERFORMANCE").ok().as_deref(),
// None | Some("") | Some("no") | Some("false")
// ) {
// println!("Skipping test, pass `TURBOPACK_TEST_PERFORMANCE=yes` to run it");
// return;
// }

if check_skip() {
return;
}
run(&REGISTRATION, || {
run_test(
|| {
@@ -160,6 +178,126 @@ async fn many_calls_to_uncached_many_children() {
.unwrap();
}

fn run_big_graph_test(counts: Vec<u32>) -> impl Future<Output = Result<()>> + Send + 'static {
println!(
"Graph {:?} = {} tasks",
counts,
(1..=counts.len())
.into_iter()
.map(|i| counts.iter().take(i).product::<u32>())
.sum::<u32>()
);
run_test(
move || calls_big_graph(counts.clone(), TransientInstance::new(())).strongly_consistent(),
Duration::from_micros(100),
)
}

#[tokio::test]
async fn many_calls_to_big_graph_1() {
if check_skip() {
return;
}
run(&REGISTRATION, || run_big_graph_test(vec![5, 8, 10, 15, 20]))
.await
.unwrap();
}

#[tokio::test]
async fn many_calls_to_big_graph_2() {
if check_skip() {
return;
}
run(&REGISTRATION, || {
run_big_graph_test(vec![2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])
})
.await
.unwrap();
}

#[tokio::test]
async fn many_calls_to_big_graph_3() {
if check_skip() {
return;
}
run(&REGISTRATION, || run_big_graph_test(vec![1000, 3, 3, 3, 3]))
.await
.unwrap();
}

#[tokio::test]
async fn many_calls_to_big_graph_4() {
if check_skip() {
return;
}
run(&REGISTRATION, || run_big_graph_test(vec![3, 3, 3, 3, 1000]))
.await
.unwrap();
}

#[tokio::test]
async fn many_calls_to_big_graph_5() {
if check_skip() {
return;
}
run(&REGISTRATION, || {
run_big_graph_test(vec![10, 10, 10, 10, 10])
})
.await
.unwrap();
}

#[tokio::test]
async fn many_calls_to_big_graph_6() {
if check_skip() {
return;
}
run(&REGISTRATION, || {
run_big_graph_test(vec![2, 2, 2, 1000, 2, 2, 2])
})
.await
.unwrap();
}

#[tokio::test]
async fn many_calls_to_big_graph_7() {
if check_skip() {
return;
}
run(&REGISTRATION, || {
run_big_graph_test(vec![
1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 3, 2, 1, 1, 1, 1, 5, 1, 1, 1, 200, 2, 1,
1, 1, 1, 1, 1, 1, 1, 1,
])
})
.await
.unwrap();
}

#[tokio::test]
async fn many_calls_to_big_graph_8() {
if check_skip() {
return;
}
run(&REGISTRATION, || {
run_big_graph_test(vec![200, 2, 2, 2, 2, 200])
})
.await
.unwrap();
}

#[tokio::test]
async fn many_calls_to_big_graph_9() {
if check_skip() {
return;
}
run(&REGISTRATION, || {
run_big_graph_test(vec![10000, 1, 1, 2, 1, 1, 2, 2, 1, 1, 1, 1])
})
.await
.unwrap();
}

#[turbo_tasks::value]
struct Value {
value: u32,
@@ -186,3 +324,22 @@ fn many_children(_j: Option<TransientInstance<()>>) -> Vc<()> {
fn many_children_inner(_i: u32) -> Vc<()> {
Vc::cell(())
}

#[turbo_tasks::function]
async fn calls_big_graph(mut counts: Vec<u32>, _i: TransientInstance<()>) -> Vc<()> {
counts.reverse();
let _ = big_graph(counts, vec![]);
Vc::cell(())
}

#[turbo_tasks::function]
fn big_graph(mut counts: Vec<u32>, keys: Vec<u32>) -> Vc<()> {
let Some(count) = counts.pop() else {
return Vc::cell(());
};
for i in 0..count {
let new_keys = keys.iter().copied().chain(std::iter::once(i)).collect();
let _ = big_graph(counts.clone(), new_keys);
}
Vc::cell(())
}