Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
57 changes: 45 additions & 12 deletions turbopack/crates/turbo-tasks-backend/src/backend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ use turbo_tasks::{
event::{Event, EventListener},
message_queue::TimingEvent,
registry::get_value_type,
scope::scope_and_block,
task_statistics::TaskStatisticsApi,
trace::TraceRawVcs,
turbo_tasks,
util::{IdFactoryWithReuse, good_chunk_size},
util::{IdFactoryWithReuse, good_chunk_size, into_chunks},
};

pub use self::{operation::AnyOperation, storage::TaskDataCategory};
Expand All @@ -48,10 +49,11 @@ use crate::backend::operation::TaskDirtyCause;
use crate::{
backend::{
operation::{
AggregationUpdateJob, AggregationUpdateQueue, CleanupOldEdgesOperation,
ComputeDirtyAndCleanUpdate, ConnectChildOperation, ExecuteContext, ExecuteContextImpl,
Operation, OutdatedEdge, TaskGuard, connect_children, get_aggregation_number,
get_uppers, is_root_node, make_task_dirty_internal, prepare_new_children,
AggregationUpdateJob, AggregationUpdateQueue, ChildExecuteContext,
CleanupOldEdgesOperation, ComputeDirtyAndCleanUpdate, ConnectChildOperation,
ExecuteContext, ExecuteContextImpl, Operation, OutdatedEdge, TaskGuard,
connect_children, get_aggregation_number, get_uppers, is_root_node,
make_task_dirty_internal, prepare_new_children,
},
storage::{
InnerStorageSnapshot, Storage, count, get, get_many, get_mut, get_mut_or_insert_with,
Expand Down Expand Up @@ -2160,8 +2162,12 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
) {
debug_assert!(!output_dependent_tasks.is_empty());

let mut queue = AggregationUpdateQueue::new();
for dependent_task_id in output_dependent_tasks {
fn process_output_dependents(
ctx: &mut impl ExecuteContext<'_>,
task_id: TaskId,
dependent_task_id: TaskId,
queue: &mut AggregationUpdateQueue,
) {
#[cfg(feature = "trace_task_output_dependencies")]
let span = tracing::trace_span!(
"invalidate output dependency",
Expand All @@ -2174,37 +2180,64 @@ impl<B: BackingStorage> TurboTasksBackendInner<B> {
// once tasks are never invalidated
#[cfg(feature = "trace_task_output_dependencies")]
span.record("result", "once task");
continue;
return;
}
let dependent = ctx.task(dependent_task_id, TaskDataCategory::All);
if dependent.has_key(&CachedDataItemKey::OutdatedOutputDependency { target: task_id }) {
// output dependency is outdated, so it hasn't read the output yet
// and doesn't need to be invalidated
#[cfg(feature = "trace_task_output_dependencies")]
span.record("result", "outdated dependency");
continue;
return;
}
if !dependent.has_key(&CachedDataItemKey::OutputDependency { target: task_id }) {
// output dependency has been removed, so the task doesn't depend on the
// output anymore and doesn't need to be invalidated
#[cfg(feature = "trace_task_output_dependencies")]
span.record("result", "no backward dependency");
continue;
return;
}
make_task_dirty_internal(
dependent,
dependent_task_id,
true,
#[cfg(feature = "trace_task_dirty")]
TaskDirtyCause::OutputChange { task_id },
&mut queue,
queue,
ctx,
);
#[cfg(feature = "trace_task_output_dependencies")]
span.record("result", "marked dirty");
}

queue.execute(ctx);
if output_dependent_tasks.len() > 128 {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: extract a const

also is 128 kinda low? or is dirty propagation pretty expensive?

let chunk_size = good_chunk_size(output_dependent_tasks.len());
let chunks = into_chunks(output_dependent_tasks.to_vec(), chunk_size);
let _ = scope_and_block(chunks.len(), |scope| {
for chunk in chunks {
let child_ctx = ctx.child_context();
scope.spawn(move || {
let mut ctx = child_ctx.create();
let mut queue = AggregationUpdateQueue::new();
for dependent_task_id in chunk {
process_output_dependents(
&mut ctx,
task_id,
dependent_task_id,
&mut queue,
)
}
queue.execute(&mut ctx);
});
}
});
} else {
let mut queue = AggregationUpdateQueue::new();
for dependent_task_id in output_dependent_tasks {
process_output_dependents(ctx, task_id, dependent_task_id, &mut queue);
}
queue.execute(ctx);
}
}

fn task_execution_completed_unfinished_children_dirty(
Expand Down
22 changes: 22 additions & 0 deletions turbopack/crates/turbo-tasks/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,16 @@ pub struct IntoChunks<T> {
chunk_size: usize,
}

impl<T> IntoChunks<T> {
pub fn len(&self) -> usize {
(self.data.len() - self.index).div_ceil(self.chunk_size)
}

pub fn is_empty(&self) -> bool {
self.index >= self.data.len()
}
}

impl<T> Iterator for IntoChunks<T> {
type Item = Chunk<T>;

Expand Down Expand Up @@ -414,6 +424,18 @@ impl<T> Drop for Chunk<T> {
mod tests {
use super::*;

#[test]
fn test_into_chunks_len() {
assert_eq!(into_chunks::<i32>(vec![], 2).len(), 0);
assert_eq!(into_chunks(vec![1], 2).len(), 1);
assert_eq!(into_chunks(vec![1, 2], 2).len(), 1);
assert_eq!(into_chunks(vec![1, 2, 3], 2).len(), 2);
assert_eq!(into_chunks(vec![1, 2, 3, 4], 2).len(), 2);
assert_eq!(into_chunks(vec![1, 2, 3, 4, 5], 2).len(), 3);
assert_eq!(into_chunks(vec![1, 2, 3, 4, 5, 6], 2).len(), 3);
assert_eq!(into_chunks(vec![1, 2, 3, 4, 5, 6, 7], 2).len(), 4);
}

#[test]
fn test_chunk_iterator() {
let data = [(); 10]
Expand Down
Loading