Repository: vercel/next.js
Pull request: Turbopack: Trace task modifications

### What?

add a feature flag `trace_task_modification` which adds the reason why a task was marked as modified to the tracing

Changed files:
filename: turbopack/crates/turbo-tasks-backend/Cargo.toml
patch: @@ -25,6 +25,7 @@ trace_aggregation_update = ["trace_aggregation_update_queue"]
 trace_leaf_distance_update = []
 trace_find_and_schedule = ["trace_aggregation_update_queue"]
 trace_task_completion = []
+trace_task_modification = []
 trace_task_dirty = ["trace_aggregation_update_queue"]
 trace_task_output_dependencies = []
 trace_task_details = []

filename: turbopack/crates/turbo-tasks-backend/src/backend/operation/mod.rs
patch: @@ -993,8 +993,10 @@ impl<B: BackingStorage> TaskGuard for TaskGuardImpl<'_, B> {
         // TODO this causes race conditions, since we never know when a value is changed. We can't
         // "snapshot" the value correctly.
         if !self.task_id.is_transient() {
-            self.task.track_modification(SpecificTaskDataCategory::Data);
-            self.task.track_modification(SpecificTaskDataCategory::Meta);
+            self.task
+                .track_modification(SpecificTaskDataCategory::Data, "invalidate_serialization");
+            self.task
+                .track_modification(SpecificTaskDataCategory::Meta, "invalidate_serialization");
         }
     }
 
@@ -1043,9 +1045,14 @@ impl<'a, B: BackingStorage> TaskStorageAccessors for TaskGuardImpl<'a, B> {
         &mut self.task
     }
 
-    fn track_modification(&mut self, category: crate::backend::storage::SpecificTaskDataCategory) {
+    #[inline(always)]
+    fn track_modification(
+        &mut self,
+        category: crate::backend::storage::SpecificTaskDataCategory,
+        name: &str,
+    ) {
         if !self.task_id.is_transient() {
-            self.task.track_modification(category);
+            self.task.track_modification(category, name);
         }
     }
 

filename: turbopack/crates/turbo-tasks-backend/src/backend/storage.rs
patch: @@ -288,12 +288,31 @@ pub struct StorageWriteGuard<'a> {
 
 impl StorageWriteGuard<'_> {
     /// Tracks mutation of this task
-    pub fn track_modification(&mut self, category: SpecificTaskDataCategory) {
+    #[inline(always)]
+    pub fn track_modification(
+        &mut self,
+        category: SpecificTaskDataCategory,
+        #[allow(unused_variables)] name: &str,
+    ) {
+        self.track_modification_internal(
+            category,
+            #[cfg(feature = "trace_task_modification")]
+            name,
+        );
+    }
+
+    fn track_modification_internal(
+        &mut self,
+        category: SpecificTaskDataCategory,
+        #[cfg(feature = "trace_task_modification")] name: &str,
+    ) {
         let flags = &self.inner.flags;
         if flags.is_snapshot(category) {
             return;
         }
         let modified = flags.is_modified(category);
+        #[cfg(feature = "trace_task_modification")]
+        let _span = (!modified).then(|| tracing::trace_span!("mark_modified", name).entered());
         match (self.storage.snapshot_mode(), modified) {
             (false, false) => {
                 // Not in snapshot mode and item is unmodified

filename: turbopack/crates/turbo-tasks-macros/src/derive/task_storage_macro.rs
patch: @@ -99,12 +99,13 @@ impl FieldInfo {
 
     /// Generate the full `self.track_modification(...)` call for this field.
     fn track_modification_call(&self) -> TokenStream {
+        let field_name_str = self.field_name.to_string();
         match self.category {
             Category::Data => {
-                quote! { self.track_modification(crate::backend::storage::SpecificTaskDataCategory::Data); }
+                quote! { self.track_modification(crate::backend::storage::SpecificTaskDataCategory::Data, #field_name_str); }
             }
             Category::Meta => {
-                quote! { self.track_modification(crate::backend::storage::SpecificTaskDataCategory::Meta); }
+                quote! { self.track_modification(crate::backend::storage::SpecificTaskDataCategory::Meta, #field_name_str); }
             }
             Category::Transient => {
                 quote! {
@@ -1230,7 +1231,7 @@ fn generate_task_storage_accessors_trait(grouped_fields: &GroupedFields) -> Toke
             #[doc = "Should be called after confirming that data actually changed."]
             #[doc = "This is separate from `typed_mut()` to allow optimizations where"]
             #[doc = "we only track modifications when something actually changes."]
-            fn track_modification(&mut self, category: crate::backend::storage::SpecificTaskDataCategory);
+            fn track_modification(&mut self, category: crate::backend::storage::SpecificTaskDataCategory, name: &str);
 
             #[doc = "Verify that the task was accessed with the correct category before reading/writing."]
             #[doc = ""]