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] add new backend #69667

Merged
merged 81 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
c47d6e5
add new backend
sokra Jul 26, 2024
c33edc1
new backend
sokra Jul 29, 2024
c55395c
add more backend method implementations
sokra Aug 2, 2024
0409755
very basic operation working
sokra Aug 7, 2024
f6002fc
add own cells reading
sokra Aug 7, 2024
06be6c6
call transient tasks
sokra Aug 7, 2024
2687517
call persistent tasks
sokra Aug 7, 2024
c0a3dae
run tests multiple times to test caching
sokra Aug 7, 2024
814e4e6
add cell/output reading and creating cached tasks
sokra Aug 7, 2024
8e067c9
remove unused stuff
sokra Aug 9, 2024
6cb3e5d
clippy
sokra Aug 9, 2024
6e5c565
remove things not yet used (persistence)
sokra Aug 9, 2024
06da3b8
clippy
sokra Aug 9, 2024
9cd0f1a
add more tests for new backend
sokra Aug 9, 2024
aff4e95
add support for connect_child
sokra Aug 13, 2024
c230ba0
set root type on root tasks
sokra Aug 9, 2024
486752a
remove old edges when task recomputation completes
sokra Aug 12, 2024
6392582
add try_get_function_id
sokra Aug 14, 2024
432c69c
move backend impl into type alias
sokra Aug 12, 2024
7fa1086
add new backend feature
sokra Sep 4, 2024
ec3fd54
initial aggregation update
sokra Aug 13, 2024
584c8e3
more aggregation operations
sokra Aug 13, 2024
b7316a1
remove exceeding cells
sokra Aug 15, 2024
9feec20
remove clean flag in favor of Dirty
sokra Aug 15, 2024
a76d0ec
avoid marking once tasks as stale
sokra Aug 15, 2024
4d32f66
notify in progress cells
sokra Aug 16, 2024
909f924
asset adding, note on listener
sokra Aug 16, 2024
20d4957
remove helpers
sokra Aug 16, 2024
dd7834a
event listen note, remove start event
sokra Aug 16, 2024
cabc0f7
improve once task handling
sokra Sep 4, 2024
42b630c
fix notify when recomputing values
sokra Aug 16, 2024
816f4c2
remove from dirty list again
sokra Aug 16, 2024
54b3b70
fixup
sokra Aug 16, 2024
1652251
fix hanging of stale tasks
sokra Aug 17, 2024
66de1c2
avoid race condition
sokra Aug 17, 2024
82d036c
remove outdated child
sokra Aug 17, 2024
bf3843d
transient tasks are scheduled by the manager
sokra Aug 17, 2024
2cfe0a2
improve aggregation implementation
sokra Sep 2, 2024
308bcd0
fixup
sokra Sep 3, 2024
8f502e6
strong reads
sokra Sep 3, 2024
7e2de2f
improve task aggregation
sokra Sep 4, 2024
446caa6
remove scheduling on invalidation
sokra Sep 3, 2024
703b017
add recompute test case
sokra Sep 3, 2024
fcb7401
more test cases
sokra Sep 3, 2024
e6f55b4
aggregation improvements
sokra Sep 4, 2024
12f26c9
aggregation fixes
sokra Sep 6, 2024
efba41b
clippy
sokra Sep 6, 2024
3ddc905
shared_amount need to be a power to two
sokra Sep 6, 2024
89ca6b8
fix concurrent data update
sokra Sep 20, 2024
ee0064d
add more test cases
sokra Sep 20, 2024
f805046
run scope_stress with persistent cache too
sokra Sep 20, 2024
44bb3ec
avoid flagging once tasks as dirty
sokra Sep 5, 2024
46f244c
refactor dirty task list to be cached in subgraphs and propagate less…
sokra Sep 23, 2024
b00979a
fix deadlock
sokra Sep 23, 2024
0164bfc
fix deadlock
sokra Sep 23, 2024
c515a8e
print timing when running test cases
sokra Sep 23, 2024
87c45c0
little refactor
sokra Sep 23, 2024
db27a40
add indicies for faster access
sokra Sep 23, 2024
4895244
optimize aggregation number based on number of children
sokra Sep 23, 2024
741cf1e
add performance test case
sokra Sep 23, 2024
eb1d2e7
refactor aggregation update into separate functions
sokra Sep 26, 2024
3c640b3
more efficent new follower handling
sokra Sep 26, 2024
3bb7cab
more efficient new follower handling
sokra Sep 26, 2024
1eaf8db
fixup! refactor aggregation update into separate functions
sokra Sep 26, 2024
f9826b7
remove todo
sokra Oct 2, 2024
9e11d45
serialization fixup
sokra Aug 9, 2024
eb464f7
improve macro visibility, method name and long types
sokra Oct 2, 2024
f79cf89
improve macro readablility
sokra Oct 2, 2024
6d5dee1
clippy
sokra Oct 2, 2024
a9f19c6
readablilty
sokra Oct 2, 2024
8bb77ac
add documentation
sokra Oct 2, 2024
1c65669
review cleanups
sokra Oct 2, 2024
d5ec3bf
add documentation
sokra Oct 2, 2024
47c19dc
use BITS
sokra Oct 2, 2024
7308a36
clippy
sokra Oct 2, 2024
a445451
comment
sokra Oct 2, 2024
68c4bed
remove unneeded `let _ = `
sokra Oct 4, 2024
b466e86
remove allow dead_code
sokra Oct 4, 2024
fbcd760
improve imports
sokra Oct 4, 2024
d2c34b6
fix scope_stress test case
sokra Oct 4, 2024
e8d0378
add stress test for dash_map multi locking
sokra Oct 4, 2024
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
28 changes: 28 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ swc-ast-explorer = { path = "turbopack/crates/turbopack-swc-ast-explorer" }
turbo-prehash = { path = "turbopack/crates/turbo-prehash" }
turbo-tasks-malloc = { path = "turbopack/crates/turbo-tasks-malloc", default-features = false }
turbo-tasks = { path = "turbopack/crates/turbo-tasks" }
turbo-tasks-backend = { path = "turbopack/crates/turbo-tasks-backend" }
turbo-tasks-build = { path = "turbopack/crates/turbo-tasks-build" }
turbo-tasks-bytes = { path = "turbopack/crates/turbo-tasks-bytes" }
turbo-tasks-env = { path = "turbopack/crates/turbo-tasks-env" }
Expand Down Expand Up @@ -143,6 +144,7 @@ dunce = "1.0.3"
either = "1.9.0"
futures = "0.3.26"
futures-retry = "0.6.0"
hashbrown = "0.14.5"
httpmock = { version = "0.6.8", default-features = false }
image = { version = "0.25.0", default-features = false }
indexmap = "1.9.2"
Expand Down
3 changes: 3 additions & 0 deletions crates/napi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ __internal_dhat-heap = ["dhat"]
# effectively does nothing.
__internal_dhat-ad-hoc = ["dhat"]

new-backend = ["dep:turbo-tasks-backend"]

# Enable specific tls features per-target.
[target.'cfg(all(target_os = "windows", target_arch = "aarch64"))'.dependencies]
next-core = { workspace = true, features = ["native-tls"] }
Expand Down Expand Up @@ -105,6 +107,7 @@ lightningcss-napi = { workspace = true }
tokio = { workspace = true, features = ["full"] }
turbo-tasks = { workspace = true }
turbo-tasks-memory = { workspace = true }
turbo-tasks-backend = { workspace = true, optional = true }
turbo-tasks-fs = { workspace = true }
next-api = { workspace = true }
next-build = { workspace = true }
Expand Down
67 changes: 33 additions & 34 deletions crates/napi/src/next_api/project.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{io::Write, path::PathBuf, sync::Arc, thread, time::Duration};
use std::{path::PathBuf, sync::Arc, thread, time::Duration};

use anyhow::{anyhow, bail, Context, Result};
use napi::{
Expand All @@ -24,7 +24,6 @@
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter, Registry};
use turbo_tasks::{Completion, RcStr, ReadRef, TransientInstance, TurboTasks, UpdateInfo, Vc};
use turbo_tasks_fs::{DiskFileSystem, FileContent, FileSystem, FileSystemPath};
use turbo_tasks_memory::MemoryBackend;
use turbopack_core::{
diagnostics::PlainDiagnostic,
error::PrettyPrintError,
Expand All @@ -44,8 +43,8 @@
use super::{
endpoint::ExternalEndpoint,
utils::{
get_diagnostics, get_issues, subscribe, NapiDiagnostic, NapiIssue, RootTask,
TurbopackResult, VcArc,
create_turbo_tasks, get_diagnostics, get_issues, subscribe, NapiDiagnostic, NapiIssue,
NextBackend, RootTask, TurbopackResult, VcArc,
},
};
use crate::register;
Expand Down Expand Up @@ -99,7 +98,7 @@

/// next.config's distDir. Project initialization occurs eariler than
/// deserializing next.config, so passing it as separate option.
pub dist_dir: Option<String>,
pub dist_dir: String,

/// Filesystem watcher options.
pub watch: NapiWatchOptions,
Expand Down Expand Up @@ -273,7 +272,7 @@
}

pub struct ProjectInstance {
turbo_tasks: Arc<TurboTasks<MemoryBackend>>,
turbo_tasks: Arc<TurboTasks<NextBackend>>,
container: Vc<ProjectContainer>,
exit_receiver: tokio::sync::Mutex<Option<ExitReceiver>>,
}
Expand Down Expand Up @@ -309,10 +308,7 @@
let subscriber = Registry::default();

let subscriber = subscriber.with(EnvFilter::builder().parse(trace).unwrap());
let dist_dir = options
.dist_dir
.as_ref()
.map_or_else(|| ".next".to_string(), |d| d.to_string());
let dist_dir = options.dist_dir.clone();

let internal_dir = PathBuf::from(&options.project_path).join(dist_dir);
std::fs::create_dir_all(&internal_dir)
Expand All @@ -338,27 +334,30 @@
subscriber.init();
}

let turbo_tasks = TurboTasks::new(MemoryBackend::new(
turbo_engine_options
.memory_limit
.map(|m| m as usize)
.unwrap_or(usize::MAX),
));
let stats_path = std::env::var_os("NEXT_TURBOPACK_TASK_STATISTICS");
if let Some(stats_path) = stats_path {
let task_stats = turbo_tasks.backend().task_statistics().enable().clone();
exit.on_exit(async move {
tokio::task::spawn_blocking(move || {
let mut file = std::fs::File::create(&stats_path)
.with_context(|| format!("failed to create or open {stats_path:?}"))?;
serde_json::to_writer(&file, &task_stats)
.context("failed to serialize or write task statistics")?;
file.flush().context("failed to flush file")
})
.await
.unwrap()
.unwrap();
});
let memory_limit = turbo_engine_options
.memory_limit
.map(|m| m as usize)
.unwrap_or(usize::MAX);
let turbo_tasks = create_turbo_tasks(PathBuf::from(&options.dist_dir), memory_limit)?;
#[cfg(not(feature = "new-backend"))]
{
use std::io::Write;
let stats_path = std::env::var_os("NEXT_TURBOPACK_TASK_STATISTICS");
if let Some(stats_path) = stats_path {
let task_stats = turbo_tasks.backend().task_statistics().enable().clone();
exit.on_exit(async move {
tokio::task::spawn_blocking(move || {
let mut file = std::fs::File::create(&stats_path)
.with_context(|| format!("failed to create or open {stats_path:?}"))?;
serde_json::to_writer(&file, &task_stats)
.context("failed to serialize or write task statistics")?;
file.flush().context("failed to flush file")
})
.await
.unwrap()
.unwrap();
});
}
}
let options: ProjectOptions = options.into();
let container = turbo_tasks
Expand Down Expand Up @@ -502,7 +501,7 @@
fn from_route(
pathname: String,
value: Route,
turbo_tasks: &Arc<TurboTasks<MemoryBackend>>,
turbo_tasks: &Arc<TurboTasks<NextBackend>>,
) -> Self {
let convert_endpoint = |endpoint: Vc<Box<dyn Endpoint>>| {
Some(External::new(ExternalEndpoint(VcArc::new(
Expand Down Expand Up @@ -569,7 +568,7 @@
impl NapiMiddleware {
fn from_middleware(
value: &Middleware,
turbo_tasks: &Arc<TurboTasks<MemoryBackend>>,
turbo_tasks: &Arc<TurboTasks<NextBackend>>,
) -> Result<Self> {
Ok(NapiMiddleware {
endpoint: External::new(ExternalEndpoint(VcArc::new(
Expand All @@ -589,7 +588,7 @@
impl NapiInstrumentation {
fn from_instrumentation(
value: &Instrumentation,
turbo_tasks: &Arc<TurboTasks<MemoryBackend>>,
turbo_tasks: &Arc<TurboTasks<NextBackend>>,
) -> Result<Self> {
Ok(NapiInstrumentation {
node_js: External::new(ExternalEndpoint(VcArc::new(
Expand Down Expand Up @@ -931,7 +930,7 @@
}
}

/// Subscribes to lifecycle events of the compilation.

Check warning on line 933 in crates/napi/src/next_api/project.rs

View workflow job for this annotation

GitHub Actions / rustdoc check / build

public documentation for `project_update_info_subscribe` links to private item `UpdateMessage::Start`

Check warning on line 933 in crates/napi/src/next_api/project.rs

View workflow job for this annotation

GitHub Actions / rustdoc check / build

public documentation for `project_update_info_subscribe` links to private item `UpdateMessage::End`

Check warning on line 933 in crates/napi/src/next_api/project.rs

View workflow job for this annotation

GitHub Actions / rustdoc check / build

public documentation for `project_update_info_subscribe` links to private item `UpdateMessage::End`

Check warning on line 933 in crates/napi/src/next_api/project.rs

View workflow job for this annotation

GitHub Actions / rustdoc check / build

public documentation for `project_update_info_subscribe` links to private item `UpdateMessage::Start`
/// Emits an [UpdateMessage::Start] event when any computation starts.
/// Emits an [UpdateMessage::End] event when there was no computation for the
/// specified time (`aggregation_ms`). The [UpdateMessage::End] event contains
Expand Down
32 changes: 25 additions & 7 deletions crates/napi/src/next_api/utils.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{collections::HashMap, future::Future, ops::Deref, sync::Arc};
use std::{collections::HashMap, future::Future, ops::Deref, path::PathBuf, sync::Arc};

use anyhow::{anyhow, Context, Result};
use napi::{
Expand All @@ -9,7 +9,6 @@ use napi::{
use serde::Serialize;
use turbo_tasks::{ReadRef, TaskId, TryJoinIterExt, TurboTasks, Vc};
use turbo_tasks_fs::FileContent;
use turbo_tasks_memory::MemoryBackend;
use turbopack_core::{
diagnostics::{Diagnostic, DiagnosticContextExt, PlainDiagnostic},
error::PrettyPrintError,
Expand All @@ -19,22 +18,41 @@ use turbopack_core::{

use crate::util::log_internal_error_and_inform;

#[cfg(not(feature = "new-backend"))]
pub type NextBackend = turbo_tasks_memory::MemoryBackend;
#[cfg(feature = "new-backend")]
pub type NextBackend = turbo_tasks_backend::TurboTasksBackend;

#[allow(unused_variables, reason = "feature-gated")]
pub fn create_turbo_tasks(
output_path: PathBuf,
memory_limit: usize,
) -> Result<Arc<TurboTasks<NextBackend>>> {
#[cfg(not(feature = "new-backend"))]
let backend = TurboTasks::new(turbo_tasks_memory::MemoryBackend::new(memory_limit));
#[cfg(feature = "new-backend")]
let backend = TurboTasks::new(turbo_tasks_backend::TurboTasksBackend::new(Arc::new(
turbo_tasks_backend::LmdbBackingStorage::new(&output_path.join("cache/turbopack"))?,
)));
Ok(backend)
}

/// A helper type to hold both a Vc operation and the TurboTasks root process.
/// Without this, we'd need to pass both individually all over the place
#[derive(Clone)]
pub struct VcArc<T> {
turbo_tasks: Arc<TurboTasks<MemoryBackend>>,
turbo_tasks: Arc<TurboTasks<NextBackend>>,
/// The Vc. Must be resolved, otherwise you are referencing an inactive
/// operation.
vc: T,
}

impl<T> VcArc<T> {
pub fn new(turbo_tasks: Arc<TurboTasks<MemoryBackend>>, vc: T) -> Self {
pub fn new(turbo_tasks: Arc<TurboTasks<NextBackend>>, vc: T) -> Self {
Self { turbo_tasks, vc }
}

pub fn turbo_tasks(&self) -> &Arc<TurboTasks<MemoryBackend>> {
pub fn turbo_tasks(&self) -> &Arc<TurboTasks<NextBackend>> {
&self.turbo_tasks
}
}
Expand All @@ -57,7 +75,7 @@ pub fn serde_enum_to_string<T: Serialize>(value: &T) -> Result<String> {
/// The root of our turbopack computation.
pub struct RootTask {
#[allow(dead_code)]
turbo_tasks: Arc<TurboTasks<MemoryBackend>>,
turbo_tasks: Arc<TurboTasks<NextBackend>>,
#[allow(dead_code)]
task_id: Option<TaskId>,
}
Expand Down Expand Up @@ -301,7 +319,7 @@ impl<T: ToNapiValue> ToNapiValue for TurbopackResult<T> {
}

pub fn subscribe<T: 'static + Send + Sync, F: Future<Output = Result<T>> + Send, V: ToNapiValue>(
turbo_tasks: Arc<TurboTasks<MemoryBackend>>,
turbo_tasks: Arc<TurboTasks<NextBackend>>,
func: JsFunction,
handler: impl 'static + Sync + Send + Clone + Fn() -> F,
mapper: impl 'static + Sync + Send + FnMut(ThreadSafeCallContext<T>) -> napi::Result<Vec<V>>,
Expand Down
26 changes: 13 additions & 13 deletions crates/napi/src/turbotrace.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
use std::sync::Arc;
use std::{path::PathBuf, sync::Arc};

use napi::bindgen_prelude::*;
use node_file_trace::{start, Args};
use turbo_tasks::TurboTasks;
use turbo_tasks_memory::MemoryBackend;
use turbopack::{
module_options::{EcmascriptOptionsContext, ModuleOptionsContext},
resolve_options_context::ResolveOptionsContext,
};

use crate::next_api::utils::{self, NextBackend};

#[napi]
pub fn create_turbo_tasks(memory_limit: Option<i64>) -> External<Arc<TurboTasks<MemoryBackend>>> {
let turbo_tasks = TurboTasks::new(MemoryBackend::new(
memory_limit.map(|m| m as usize).unwrap_or(usize::MAX),
));
External::new_with_size_hint(
turbo_tasks,
memory_limit.map(|u| u as usize).unwrap_or(usize::MAX),
)
pub fn create_turbo_tasks(
output_path: String,
memory_limit: Option<i64>,
) -> External<Arc<TurboTasks<NextBackend>>> {
let limit = memory_limit.map(|u| u as usize).unwrap_or(usize::MAX);
let turbo_tasks = utils::create_turbo_tasks(PathBuf::from(&output_path), limit)
.expect("Failed to create TurboTasks");
External::new_with_size_hint(turbo_tasks, limit)
}

#[napi]
pub async fn run_turbo_tracing(
options: Buffer,
turbo_tasks: Option<External<Arc<TurboTasks<MemoryBackend>>>>,
turbo_tasks: External<Arc<TurboTasks<NextBackend>>>,
) -> napi::Result<Vec<String>> {
let args: Args = serde_json::from_slice(options.as_ref())?;
let turbo_tasks = turbo_tasks.map(|t| t.clone());
let files = start(
Arc::new(args),
turbo_tasks.as_ref(),
turbo_tasks.clone(),
Some(ModuleOptionsContext {
ecmascript: EcmascriptOptionsContext {
enable_types: true,
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/build/collect-build-traces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export async function collectBuildTraces({
let turbotraceOutputPath: string | undefined
let turbotraceFiles: string[] | undefined
turboTasksForTrace = bindings.turbo.createTurboTasks(
distDir,
(config.experimental.turbotrace?.memoryLimit ??
TURBO_TRACE_DEFAULT_MEMORY_LIMIT) *
1024 *
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1379,6 +1379,7 @@ export default async function build(
config.experimental?.turbo?.root ||
config.outputFileTracingRoot ||
dir,
distDir,
nextConfig: config,
jsConfig: await getTurbopackJsConfig(dir, config),
watch: {
Expand Down
5 changes: 3 additions & 2 deletions packages/next/src/build/swc/generated-native.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export interface NapiProjectOptions {
* next.config's distDir. Project initialization occurs eariler than
* deserializing next.config, so passing it as separate option.
*/
distDir?: string
distDir: string
/** Filesystem watcher options. */
watch: NapiWatchOptions
/** The contents of next.config.js, serialized to JSON. */
Expand Down Expand Up @@ -363,11 +363,12 @@ export interface NapiRewrite {
missing?: Array<NapiRouteHas>
}
export function createTurboTasks(
outputPath: string,
memoryLimit?: number | undefined | null
): ExternalObject<TurboTasks>
export function runTurboTracing(
options: Buffer,
turboTasks?: ExternalObject<TurboTasks> | undefined | null
turboTasks: ExternalObject<TurboTasks>
): Promise<Array<string>>
export function getTargetTriple(): string
export function initHeapProfiler(): ExternalObject<RefCell>
Expand Down
8 changes: 6 additions & 2 deletions packages/next/src/build/swc/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1054,6 +1054,7 @@ async function loadWasm(importPath = '') {
Log.error('Wasm binding does not support trace yet')
},
createTurboTasks: function (
_outputPath: string,
_memoryLimit?: number | undefined
): ExternalObject<TurboTasks> {
throw new Error(
Expand Down Expand Up @@ -1234,8 +1235,11 @@ function loadNative(importPath?: string) {
turboTasks
)
},
createTurboTasks(memoryLimit?: number): ExternalObject<TurboTasks> {
return bindings.createTurboTasks(memoryLimit)
createTurboTasks(
outputPath: string,
memoryLimit?: number
): ExternalObject<TurboTasks> {
return bindings.createTurboTasks(outputPath, memoryLimit)
},
createProject: bindingToApi(customBindings ?? bindings, false),
startTurbopackTraceServer(traceFilePath) {
Expand Down
Loading
Loading