Skip to content

Commit 51e0043

Browse files
authored
[Turbopack] Compute module batches and use them for chunking (#76133)
### What? Compute module batches and refactor chunking to work on the batches graph instead of the modules graph With many pages we run into the problem that each page has a lot of modules, even if the total amount of modules is not super high. This multiples the number of edges needed in our graph. To reduce that, group modules to module batches and module batches to batch groups and query information on these batches resp. batch groups to reduce the work needed. A module batch will be formed from modules that are always used in a specific execution order. A batch group will be formed from module batches that are in the same chunk groups. Usually we work with module batches in a certain order and a unordered list of batch groups. We query information from the batch group and sort the results based on the order of module batches.
1 parent dbb19c5 commit 51e0043

File tree

241 files changed

+2877
-730
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

241 files changed

+2877
-730
lines changed

Cargo.lock

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/next-api/src/app.rs

+17-4
Original file line numberDiff line numberDiff line change
@@ -1902,10 +1902,23 @@ impl Endpoint for AppEndpoint {
19021902

19031903
#[turbo_tasks::function]
19041904
async fn entries(self: Vc<Self>) -> Result<Vc<GraphEntries>> {
1905-
Ok(Vc::cell(vec![(
1906-
vec![self.app_endpoint_entry().await?.rsc_entry],
1907-
ChunkGroupType::Entry,
1908-
)]))
1905+
let this = self.await?;
1906+
Ok(Vc::cell(vec![
1907+
(
1908+
vec![self.app_endpoint_entry().await?.rsc_entry],
1909+
ChunkGroupType::Entry,
1910+
),
1911+
(
1912+
this.app_project
1913+
.client_runtime_entries()
1914+
.await?
1915+
.iter()
1916+
.copied()
1917+
.map(ResolvedVc::upcast)
1918+
.collect(),
1919+
ChunkGroupType::Entry,
1920+
),
1921+
]))
19091922
}
19101923

19111924
#[turbo_tasks::function]

crates/next-api/src/webpack_stats.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use anyhow::Result;
22
use serde::Serialize;
33
use turbo_rcstr::RcStr;
44
use turbo_tasks::{FxIndexMap, FxIndexSet, ResolvedVc, Vc};
5-
use turbopack_browser::ecmascript::EcmascriptDevChunk;
5+
use turbopack_browser::ecmascript::EcmascriptBrowserChunk;
66
use turbopack_core::{
77
chunk::{Chunk, ChunkItem},
88
output::OutputAsset,
@@ -27,7 +27,7 @@ where
2727
continue;
2828
};
2929

30-
if let Some(chunk) = ResolvedVc::try_downcast_type::<EcmascriptDevChunk>(*asset) {
30+
if let Some(chunk) = ResolvedVc::try_downcast_type::<EcmascriptBrowserChunk>(*asset) {
3131
let chunk_ident = normalize_client_path(&chunk.path().await?.path);
3232
chunks.push(WebpackStatsChunk {
3333
size: asset_len,

turbopack/crates/turbo-tasks-fs/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ name = "mod"
1313
harness = false
1414

1515
[features]
16+
default = []
1617
# Enables dynamic linking (and hot reloading) of embedded files/dirs.
1718
# A binary built with this option **is not portable**, the directory
1819
# path will be embedded into the binary.

turbopack/crates/turbo-tasks/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ serde = { workspace = true, features = ["rc", "derive"] }
4242
serde_json = { workspace = true }
4343
serde_regex = "1.1.0"
4444
shrink-to-fit = { workspace=true,features = ["indexmap", "serde_json", "smallvec", "nightly"] }
45+
smallvec = { workspace = true }
4546
thiserror = { workspace = true }
4647
tokio = { workspace = true, features = ["full"] }
4748
tokio-util = { workspace = true }

turbopack/crates/turbo-tasks/src/debug/mod.rs

+32
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::fmt::{Debug, Display};
22

33
use auto_hash_map::{AutoMap, AutoSet};
4+
use smallvec::SmallVec;
45
use turbo_rcstr::RcStr;
56
use turbo_tasks::{FxIndexMap, FxIndexSet, Vc};
67
pub use turbo_tasks_macros::ValueDebugFormat;
@@ -157,6 +158,37 @@ where
157158
}
158159
}
159160

161+
impl<T, const N: usize> ValueDebugFormat for SmallVec<[T; N]>
162+
where
163+
T: ValueDebugFormat,
164+
{
165+
fn value_debug_format(&self, depth: usize) -> ValueDebugFormatString {
166+
if depth == 0 {
167+
return ValueDebugFormatString::Sync(std::any::type_name::<Self>().to_string());
168+
}
169+
170+
let values = self
171+
.iter()
172+
.map(|value| value.value_debug_format(depth.saturating_sub(1)))
173+
.collect::<Vec<_>>();
174+
175+
ValueDebugFormatString::Async(Box::pin(async move {
176+
let mut values_string = vec![];
177+
for value in values {
178+
match value {
179+
ValueDebugFormatString::Sync(string) => {
180+
values_string.push(PassthroughDebug::new_string(string));
181+
}
182+
ValueDebugFormatString::Async(future) => {
183+
values_string.push(PassthroughDebug::new_string(future.await?));
184+
}
185+
}
186+
}
187+
Ok(format!("{:#?}", values_string))
188+
}))
189+
}
190+
}
191+
160192
impl<K> ValueDebugFormat for AutoSet<K>
161193
where
162194
K: ValueDebugFormat,

turbopack/crates/turbo-tasks/src/marker_trait.rs

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ macro_rules! impl_auto_marker_trait {
4747

4848
unsafe impl<T: $trait> $trait for ::std::option::Option<T> {}
4949
unsafe impl<T: $trait> $trait for ::std::vec::Vec<T> {}
50+
unsafe impl<T: $trait, const N: usize> $trait for ::smallvec::SmallVec<[T; N]> {}
5051
unsafe impl<T: $trait, const N: usize> $trait for [T; N] {}
5152
unsafe impl<T: $trait> $trait for [T] {}
5253
unsafe impl<T: $trait, S> $trait for ::std::collections::HashSet<T, S> {}

turbopack/crates/turbo-tasks/src/trace.rs

+9
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::{
1111
use auto_hash_map::{AutoMap, AutoSet};
1212
use either::Either;
1313
use indexmap::{IndexMap, IndexSet};
14+
use smallvec::SmallVec;
1415
use turbo_rcstr::RcStr;
1516

1617
use crate::RawVc;
@@ -130,6 +131,14 @@ impl<T: TraceRawVcs> TraceRawVcs for Box<[T]> {
130131
}
131132
}
132133

134+
impl<T: TraceRawVcs, const N: usize> TraceRawVcs for SmallVec<[T; N]> {
135+
fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext) {
136+
for item in self.iter() {
137+
TraceRawVcs::trace_raw_vcs(item, trace_context);
138+
}
139+
}
140+
}
141+
133142
impl<T: TraceRawVcs, const N: usize> TraceRawVcs for [T; N] {
134143
fn trace_raw_vcs(&self, trace_context: &mut TraceRawVcsContext) {
135144
for item in self.iter() {

turbopack/crates/turbo-tasks/src/vc/resolved.rs

+15
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::{
44
future::IntoFuture,
55
hash::{Hash, Hasher},
66
marker::PhantomData,
7+
mem::transmute,
78
ops::Deref,
89
};
910

@@ -205,6 +206,20 @@ where
205206
node: Vc::upcast(this.node),
206207
}
207208
}
209+
210+
/// Cheaply converts a Vec of resolved Vcs to a Vec of Vcs.
211+
pub fn deref_vec(vec: Vec<ResolvedVc<T>>) -> Vec<Vc<T>> {
212+
debug_assert!(size_of::<ResolvedVc<T>>() == size_of::<Vc<T>>());
213+
// Safety: The memory layout of `ResolvedVc<T>` and `Vc<T>` is the same.
214+
unsafe { transmute::<Vec<ResolvedVc<T>>, Vec<Vc<T>>>(vec) }
215+
}
216+
217+
/// Cheaply converts a slice of resolved Vcs to a slice of Vcs.
218+
pub fn deref_slice(slice: &[ResolvedVc<T>]) -> &[Vc<T>] {
219+
debug_assert!(size_of::<ResolvedVc<T>>() == size_of::<Vc<T>>());
220+
// Safety: The memory layout of `ResolvedVc<T>` and `Vc<T>` is the same.
221+
unsafe { transmute::<&[ResolvedVc<T>], &[Vc<T>]>(slice) }
222+
}
208223
}
209224

210225
impl<T> ResolvedVc<T>

turbopack/crates/turbopack-browser/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ workspace = true
2020

2121
[dependencies]
2222
anyhow = { workspace = true }
23+
either = { workspace = true }
2324
indexmap = { workspace = true }
2425
indoc = { workspace = true }
2526
rustc-hash = { workspace = true }

turbopack/crates/turbopack-browser/src/chunking_context.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ use turbopack_ecmascript::{
2727
use turbopack_ecmascript_runtime::RuntimeType;
2828

2929
use crate::ecmascript::{
30-
chunk::EcmascriptDevChunk,
31-
evaluate::chunk::EcmascriptDevEvaluateChunk,
30+
chunk::EcmascriptBrowserChunk,
31+
evaluate::chunk::EcmascriptBrowserEvaluateChunk,
3232
list::asset::{EcmascriptDevChunkList, EcmascriptDevChunkListSource},
3333
};
3434

@@ -236,7 +236,7 @@ impl BrowserChunkingContext {
236236
// TODO(sokra) remove this argument and pass chunk items instead
237237
module_graph: Vc<ModuleGraph>,
238238
) -> Vc<Box<dyn OutputAsset>> {
239-
Vc::upcast(EcmascriptDevEvaluateChunk::new(
239+
Vc::upcast(EcmascriptBrowserEvaluateChunk::new(
240240
self,
241241
ident,
242242
other_chunks,
@@ -271,7 +271,7 @@ impl BrowserChunkingContext {
271271
if let Some(ecmascript_chunk) =
272272
Vc::try_resolve_downcast_type::<EcmascriptChunk>(chunk).await?
273273
{
274-
Vc::upcast(EcmascriptDevChunk::new(self, ecmascript_chunk))
274+
Vc::upcast(EcmascriptBrowserChunk::new(self, ecmascript_chunk))
275275
} else if let Some(output_asset) =
276276
Vc::try_resolve_sidecast::<Box<dyn OutputAsset>>(chunk).await?
277277
{

turbopack/crates/turbopack-browser/src/ecmascript/chunk.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,24 @@ use turbopack_core::{
1212
};
1313
use turbopack_ecmascript::chunk::EcmascriptChunk;
1414

15-
use crate::{ecmascript::content::EcmascriptDevChunkContent, BrowserChunkingContext};
15+
use crate::{ecmascript::content::EcmascriptBrowserChunkContent, BrowserChunkingContext};
1616

1717
/// Development Ecmascript chunk.
1818
#[turbo_tasks::value(shared)]
19-
pub struct EcmascriptDevChunk {
19+
pub struct EcmascriptBrowserChunk {
2020
chunking_context: ResolvedVc<BrowserChunkingContext>,
2121
chunk: ResolvedVc<EcmascriptChunk>,
2222
}
2323

2424
#[turbo_tasks::value_impl]
25-
impl EcmascriptDevChunk {
25+
impl EcmascriptBrowserChunk {
2626
/// Creates a new [`Vc<EcmascriptDevChunk>`].
2727
#[turbo_tasks::function]
2828
pub fn new(
2929
chunking_context: ResolvedVc<BrowserChunkingContext>,
3030
chunk: ResolvedVc<EcmascriptChunk>,
3131
) -> Vc<Self> {
32-
EcmascriptDevChunk {
32+
EcmascriptBrowserChunk {
3333
chunking_context,
3434
chunk,
3535
}
@@ -38,15 +38,15 @@ impl EcmascriptDevChunk {
3838
}
3939

4040
#[turbo_tasks::value_impl]
41-
impl ValueToString for EcmascriptDevChunk {
41+
impl ValueToString for EcmascriptBrowserChunk {
4242
#[turbo_tasks::function]
4343
fn to_string(&self) -> Vc<RcStr> {
4444
Vc::cell("Ecmascript Dev Chunk".into())
4545
}
4646
}
4747

4848
#[turbo_tasks::value_impl]
49-
impl OutputChunk for EcmascriptDevChunk {
49+
impl OutputChunk for EcmascriptBrowserChunk {
5050
#[turbo_tasks::function]
5151
async fn runtime_info(&self) -> Result<Vc<OutputChunkRuntimeInfo>> {
5252
Ok(OutputChunkRuntimeInfo {
@@ -63,11 +63,11 @@ fn modifier() -> Vc<RcStr> {
6363
}
6464

6565
#[turbo_tasks::value_impl]
66-
impl EcmascriptDevChunk {
66+
impl EcmascriptBrowserChunk {
6767
#[turbo_tasks::function]
68-
async fn own_content(self: Vc<Self>) -> Result<Vc<EcmascriptDevChunkContent>> {
68+
async fn own_content(self: Vc<Self>) -> Result<Vc<EcmascriptBrowserChunkContent>> {
6969
let this = self.await?;
70-
Ok(EcmascriptDevChunkContent::new(
70+
Ok(EcmascriptBrowserChunkContent::new(
7171
*this.chunking_context,
7272
self,
7373
this.chunk.chunk_content(),
@@ -81,7 +81,7 @@ impl EcmascriptDevChunk {
8181
}
8282

8383
#[turbo_tasks::value_impl]
84-
impl OutputAsset for EcmascriptDevChunk {
84+
impl OutputAsset for EcmascriptBrowserChunk {
8585
#[turbo_tasks::function]
8686
fn path(&self) -> Vc<FileSystemPath> {
8787
let ident = self.chunk.ident().with_modifier(modifier());
@@ -117,7 +117,7 @@ impl OutputAsset for EcmascriptDevChunk {
117117
}
118118

119119
#[turbo_tasks::value_impl]
120-
impl Asset for EcmascriptDevChunk {
120+
impl Asset for EcmascriptBrowserChunk {
121121
#[turbo_tasks::function]
122122
fn content(self: Vc<Self>) -> Vc<AssetContent> {
123123
self.own_content().content()
@@ -130,7 +130,7 @@ impl Asset for EcmascriptDevChunk {
130130
}
131131

132132
#[turbo_tasks::value_impl]
133-
impl GenerateSourceMap for EcmascriptDevChunk {
133+
impl GenerateSourceMap for EcmascriptBrowserChunk {
134134
#[turbo_tasks::function]
135135
fn generate_source_map(self: Vc<Self>) -> Vc<OptionStringifiedSourceMap> {
136136
self.own_content().generate_source_map()
@@ -153,7 +153,7 @@ fn introspectable_details() -> Vc<RcStr> {
153153
}
154154

155155
#[turbo_tasks::value_impl]
156-
impl Introspectable for EcmascriptDevChunk {
156+
impl Introspectable for EcmascriptBrowserChunk {
157157
#[turbo_tasks::function]
158158
fn ty(&self) -> Vc<RcStr> {
159159
introspectable_type()

0 commit comments

Comments
 (0)