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

Refactor ContentSources to RouteTree for more efficient routing #5360

Merged
merged 44 commits into from
Jun 30, 2023

Conversation

sokra
Copy link
Member

@sokra sokra commented Jun 22, 2023

Description

Routing is inefficient with many pages

next.js PR: vercel/next.js#51660

@vercel
Copy link

vercel bot commented Jun 22, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
examples-cra-web 🔄 Building (Inspect) Visit Preview 💬 Add feedback Jun 30, 2023 9:43am
examples-kitchensink-blog 🔄 Building (Inspect) Visit Preview 💬 Add feedback Jun 30, 2023 9:43am
examples-vite-web 🔄 Building (Inspect) Visit Preview 💬 Add feedback Jun 30, 2023 9:43am
8 Ignored Deployments
Name Status Preview Comments Updated (UTC)
examples-basic-web ⬜️ Ignored (Inspect) Visit Preview Jun 30, 2023 9:43am
examples-designsystem-docs ⬜️ Ignored (Inspect) Visit Preview Jun 30, 2023 9:43am
examples-gatsby-web ⬜️ Ignored (Inspect) Visit Preview Jun 30, 2023 9:43am
examples-native-web ⬜️ Ignored (Inspect) Visit Preview Jun 30, 2023 9:43am
examples-nonmonorepo ⬜️ Ignored (Inspect) Visit Preview Jun 30, 2023 9:43am
examples-svelte-web ⬜️ Ignored (Inspect) Visit Preview Jun 30, 2023 9:43am
examples-tailwind-web ⬜️ Ignored (Inspect) Visit Preview Jun 30, 2023 9:43am
turbo-site ⬜️ Ignored (Inspect) Visit Preview Jun 30, 2023 9:43am

@github-actions
Copy link
Contributor

✅ This change can build next-swc

@github-actions
Copy link
Contributor

github-actions bot commented Jun 22, 2023

🟢 CI successful 🟢

Thanks

@github-actions
Copy link
Contributor

Linux Benchmark for a20cb2b

Click to view benchmark
Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 11.30ms ± 0.07ms 11.31ms ± 0.08ms +0.09%
bench_hmr_to_eval/Turbopack CSR/1000 modules 10.47ms ± 0.05ms 10.30ms ± 0.07ms -1.60%
bench_startup/Turbopack CSR/1000 modules 1257.04ms ± 10.88ms 1239.51ms ± 11.90ms -1.40%

@github-actions
Copy link
Contributor

Linux Benchmark for 6870deb

Click to view benchmark
Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 11.90ms ± 0.10ms 11.79ms ± 0.06ms -0.87%
bench_hmr_to_eval/Turbopack CSR/1000 modules 10.82ms ± 0.09ms 10.82ms ± 0.07ms +0.03%
bench_startup/Turbopack CSR/1000 modules 1149.65ms ± 2.20ms 1146.81ms ± 2.94ms -0.25%

@github-actions
Copy link
Contributor

Linux Benchmark for 3fe8321

Click to view benchmark
Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 10.24ms ± 0.06ms 10.17ms ± 0.02ms -0.66%
bench_hmr_to_eval/Turbopack CSR/1000 modules 9169.55µs ± 48.88µs 9558.38µs ± 239.13µs +4.24%
bench_startup/Turbopack CSR/1000 modules 1085.17ms ± 1.79ms 1084.87ms ± 6.52ms -0.03%

@github-actions
Copy link
Contributor

MacOS Benchmark for 3fe8321

Test Base PR % Significant %
bench_hmr_to_eval/Turbopack CSR/1000 modules 27.19ms ± 0.28ms 53.63ms ± 4.35ms +97.22% +61.95%
Click to view full benchmark
Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 28.11ms ± 0.15ms 27.63ms ± 0.16ms -1.72%
bench_hmr_to_eval/Turbopack CSR/1000 modules 27.19ms ± 0.28ms 53.63ms ± 4.35ms +97.22% +61.95%
bench_startup/Turbopack CSR/1000 modules 3676.52ms ± 40.75ms 3854.77ms ± 96.92ms +4.85%

@github-actions
Copy link
Contributor

Linux Benchmark for d7f68e2

Click to view benchmark
Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 5870.69µs ± 48.37µs 5840.83µs ± 21.97µs -0.51%
bench_hmr_to_eval/Turbopack CSR/1000 modules 5516.36µs ± 22.14µs 5614.36µs ± 152.47µs +1.78%
bench_startup/Turbopack CSR/1000 modules 906.19ms ± 1.07ms 907.60ms ± 3.05ms +0.16%

crates/turbopack-convert-trace/src/main.rs Outdated Show resolved Hide resolved
crates/turbopack-dev-server/src/http.rs Outdated Show resolved Hide resolved
crates/turbopack-dev-server/src/source/mod.rs Outdated Show resolved Hide resolved
let last_tree = tree_values.pop().unwrap();
'outer: while common_base < last_tree.base.len() {
for tree in tree_values.iter() {
if tree.base.len() <= common_base {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the < case be an invariant at this point? Maybe a debug_assert?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we would have to change the outer's loop condition to be something like while common_base < min_base_len, with let min_base_len = tree_values.iter().min_by_key(…).unwrap().base.len()

}
common_base += 1;
}
tree_values.push(last_tree);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we need to pop it in the first place?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically not, but without that we would need to skip the last element of an iterator, which has more code.

crates/turbopack-node/src/render/node_api_source.rs Outdated Show resolved Hide resolved
@github-actions
Copy link
Contributor

MacOS Benchmark for d7f68e2

Test Base PR % Significant %
bench_hmr_to_eval/Turbopack CSR/1000 modules 26.78ms ± 0.18ms 25.74ms ± 0.15ms -3.89% -1.50%
bench_startup/Turbopack CSR/1000 modules 9479.68ms ± 2174.25ms 3333.48ms ± 56.53ms -64.84% -32.83%
Click to view full benchmark
Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 27.04ms ± 0.10ms 27.12ms ± 0.09ms +0.32%
bench_hmr_to_eval/Turbopack CSR/1000 modules 26.78ms ± 0.18ms 25.74ms ± 0.15ms -3.89% -1.50%
bench_startup/Turbopack CSR/1000 modules 9479.68ms ± 2174.25ms 3333.48ms ± 56.53ms -64.84% -32.83%

crates/turbopack-dev-server/src/source/route_tree.rs Outdated Show resolved Hide resolved
let last_tree = tree_values.pop().unwrap();
'outer: while common_base < last_tree.base.len() {
for tree in tree_values.iter() {
if tree.base.len() <= common_base {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we would have to change the outer's loop condition to be something like while common_base < min_base_len, with let min_base_len = tree_values.iter().min_by_key(…).unwrap().base.len()

Comment on lines +102 to +107
catch_all_sources: Vec<GetContentSourceContentVc>,
fallback_sources: Vec<GetContentSourceContentVc>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Isn't a fallback just a catchall?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fallback is currently unused. I just migrated it from Specificity::Fallback.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I'm saying is that it's unnecessary with this scheme, every fallback could be a catchall instead, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a slight difference in ordering. All catch alls will match before all fallbacks. If you merge them, they will match in order of definition.

crates/turbopack-dev-server/src/source/asset_graph.rs Outdated Show resolved Hide resolved
Comment on lines +76 to +88
match &rewrite.ty {
RewriteType::Location { path_and_query } => {
let new_uri = Uri::try_from(path_and_query)?;
let new_asset_path =
urlencoding::decode(&new_uri.path()[1..])?.into_owned();
request_overwrites.uri = new_uri;
current_asset_path = new_asset_path;
continue 'routes;
}
RewriteType::ContentSource {
source,
path_and_query,
} => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I this this rewrite logic creates a lot of inconsistencies. Before we were rewriting the current sources's URL only, but now we're changing the URL for the current route and all routes that follow. I think it has to only rewrite the the URL for the current route tree, right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If referring to the next route in sources, on Rewrite we do no longer apply following routes. The continue 'routes; will skip all remaining routes and starts applying a new route tree with the new URL.

The Rewrite is basically counted as route match.

Comment on lines +98 to +103
RewriteType::Sources {
sources: new_sources,
} => {
sources = *new_sources;
continue 'sources;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this creates similar inconsistencies. There could be more sources after the current source that would give a valid result, but we'll never reach those. I think we need to only sources = new_sources.concat(remaining_sources) here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same, the Rewrite response is counted as route match and no following source is applied.

e. g. for /some/path and /some/[dynamic] returned by get_routes, once /some/path returns a Rewrite, /some/[dynamic] will no longer be applied

crates/turbopack-dev-server/src/source/router.rs Outdated Show resolved Hide resolved
@github-actions
Copy link
Contributor

Linux Benchmark for 4fb7bd1

Click to view benchmark
Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 7220.40µs ± 204.70µs 7473.51µs ± 156.74µs +3.51%
bench_hmr_to_eval/Turbopack CSR/1000 modules 7063.21µs ± 162.44µs 6863.09µs ± 130.72µs -2.83%
bench_startup/Turbopack CSR/1000 modules 929.78ms ± 2.45ms 923.42ms ± 2.24ms -0.68%

@github-actions
Copy link
Contributor

Windows Benchmark for 4fb7bd1

Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 15.52ms ± 0.01ms 15.57ms ± 0.01ms +0.33% +0.07%
Click to view full benchmark
Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 15.52ms ± 0.01ms 15.57ms ± 0.01ms +0.33% +0.07%
bench_hmr_to_eval/Turbopack CSR/1000 modules 15.52ms ± 0.01ms 15.55ms ± 0.02ms +0.17%
bench_startup/Turbopack CSR/1000 modules 3484.46ms ± 11.88ms 3510.90ms ± 54.80ms +0.76%

@github-actions
Copy link
Contributor

Linux Benchmark for d23d03d

Click to view benchmark
Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 6766.37µs ± 21.36µs 6833.35µs ± 73.79µs +0.99%
bench_hmr_to_eval/Turbopack CSR/1000 modules 6320.64µs ± 51.70µs 6499.91µs ± 220.64µs +2.84%
bench_startup/Turbopack CSR/1000 modules 923.34ms ± 1.86ms 936.68ms ± 5.31ms +1.44%

@github-actions
Copy link
Contributor

MacOS Benchmark for d23d03d

Test Base PR % Significant %
bench_hmr_to_eval/Turbopack CSR/1000 modules 27.27ms ± 0.09ms 26.64ms ± 0.05ms -2.30% -1.28%
Click to view full benchmark
Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 27.87ms ± 0.06ms 27.95ms ± 0.06ms +0.29%
bench_hmr_to_eval/Turbopack CSR/1000 modules 27.27ms ± 0.09ms 26.64ms ± 0.05ms -2.30% -1.28%
bench_startup/Turbopack CSR/1000 modules 3273.70ms ± 18.13ms 3314.77ms ± 72.30ms +1.25%

@github-actions
Copy link
Contributor

Linux Benchmark for 4ecb6d2

Click to view benchmark
Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 11.34ms ± 0.05ms 11.48ms ± 0.08ms +1.28%
bench_hmr_to_eval/Turbopack CSR/1000 modules 10.53ms ± 0.05ms 10.94ms ± 0.41ms +3.86%
bench_startup/Turbopack CSR/1000 modules 1137.23ms ± 2.65ms 1138.47ms ± 7.15ms +0.11%

@github-actions
Copy link
Contributor

MacOS Benchmark for 4ecb6d2

Test Base PR % Significant %
bench_startup/Turbopack CSR/1000 modules 8089.70ms ± 2035.05ms 3541.77ms ± 93.63ms -56.22% -7.23%
Click to view full benchmark
Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 27.35ms ± 0.24ms 27.12ms ± 0.16ms -0.84%
bench_hmr_to_eval/Turbopack CSR/1000 modules 26.00ms ± 0.17ms 25.60ms ± 0.06ms -1.56%
bench_startup/Turbopack CSR/1000 modules 8089.70ms ± 2035.05ms 3541.77ms ± 93.63ms -56.22% -7.23%

@@ -91,6 +93,14 @@ pub enum ContentSourceContent {
Rewrite(RewriteVc),
}

/// This trait can be emitted as collectible and will be applied after the
/// request is handled and it's ensured that it finishes before the next request
/// is handled.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you explain why you would want to do emit side effect vcs? What does it accomplish?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It moves the invalidation to a time after the request is sent to the user. This delays all computation for the state change to some time after this request and before the next request.

If we would just change it inline, the strongly consistent read from the request handling would wait for this invalidation to be completed as it might have effects on the current request (but it doesn't have these).

So for expensive invalidations this allows to respond ealier.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically it's also possible to return a list of SideEffectVcs, but this requires adding a list to all intermediate functions, which is quite a large change. Since we have to cool system of collectibles we can use that. It allows to emit a side effect from anywhere and the server will make sure that it's handled at the right time.

Comment on lines +153 to +154
/// A unresolve asset. We need to have a unresolve Asset here as we need to
/// lookup the Vc identity in the expanded set.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I still don't understand. What is it about a resolved asset that prevents vc identity lookup? How does an unresolved asset solve that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should hopefully explain it: 7bfe700

Comment on lines +102 to +107
catch_all_sources: Vec<GetContentSourceContentVc>,
fallback_sources: Vec<GetContentSourceContentVc>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I'm saying is that it's unnecessary with this scheme, every fallback could be a catchall instead, right?

Comment on lines +100 to +104
let sources = sources
.await?
.iter()
.map(|s| WrappedGetContentSourceContentVc::new(*s, processor).into())
.collect();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leave a TODO with linear task, please.

@github-actions
Copy link
Contributor

Linux Benchmark for 0f81f6a

Click to view benchmark
Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 11.32ms ± 0.08ms 11.38ms ± 0.05ms +0.54%
bench_hmr_to_eval/Turbopack CSR/1000 modules 10.36ms ± 0.06ms 10.99ms ± 0.50ms +6.12%
bench_startup/Turbopack CSR/1000 modules 1138.68ms ± 3.14ms 1135.16ms ± 4.34ms -0.31%

@github-actions
Copy link
Contributor

MacOS Benchmark for 0f81f6a

Test Base PR % Significant %
bench_hmr_to_eval/Turbopack CSR/1000 modules 27.18ms ± 0.11ms 25.86ms ± 0.40ms -4.86% -1.16%
Click to view full benchmark
Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 27.86ms ± 0.07ms 27.96ms ± 0.08ms +0.36%
bench_hmr_to_eval/Turbopack CSR/1000 modules 27.18ms ± 0.11ms 25.86ms ± 0.40ms -4.86% -1.16%
bench_startup/Turbopack CSR/1000 modules 4500.03ms ± 695.74ms 7735.97ms ± 1539.85ms +71.91%

@github-actions
Copy link
Contributor

Linux Benchmark for fd8784c

Click to view benchmark
Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 10.62ms ± 0.06ms 10.89ms ± 0.10ms +2.48%
bench_hmr_to_eval/Turbopack CSR/1000 modules 10.10ms ± 0.07ms 9982.00µs ± 69.39µs -1.15%
bench_startup/Turbopack CSR/1000 modules 1154.08ms ± 3.30ms 1148.01ms ± 6.00ms -0.53%

@sokra sokra merged commit b36c414 into main Jun 30, 2023
45 checks passed
@sokra sokra deleted the sokra/route-tree branch June 30, 2023 10:30
@github-actions
Copy link
Contributor

MacOS Benchmark for fd8784c

Test Base PR % Significant %
bench_hmr_to_eval/Turbopack CSR/1000 modules 57.79ms ± 2.98ms 35.44ms ± 5.56ms -38.67% -10.17%
Click to view full benchmark
Test Base PR % Significant %
bench_hmr_to_commit/Turbopack CSR/1000 modules 28.36ms ± 0.28ms 28.30ms ± 0.10ms -0.18%
bench_hmr_to_eval/Turbopack CSR/1000 modules 57.79ms ± 2.98ms 35.44ms ± 5.56ms -38.67% -10.17%
bench_startup/Turbopack CSR/1000 modules 3443.56ms ± 11.43ms 3606.04ms ± 104.69ms +4.72%

kodiakhq bot pushed a commit to vercel/next.js that referenced this pull request Jun 30, 2023
### What?

This fixes a performance problem when many pages are involved.

fixes WEB-1067

see also vercel/turbo#5360

### Turbopack Changes

* vercel/turbo#5416 
* vercel/turbo#5360
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants