11use std:: assert_matches;
2+ use std:: cell:: Cell ;
23use std:: fmt:: Debug ;
34use std:: hash:: Hash ;
45use std:: sync:: Arc ;
@@ -9,7 +10,7 @@ use rustc_data_structures::fx::FxHashSet;
910use rustc_data_structures:: profiling:: QueryInvocationId ;
1011use rustc_data_structures:: sharded:: { self , ShardedHashMap } ;
1112use rustc_data_structures:: stable_hash:: { StableHash , StableHasher } ;
12- use rustc_data_structures:: sync:: { AtomicU64 , Lock } ;
13+ use rustc_data_structures:: sync:: { AtomicU64 , Lock , WorkerLocal } ;
1314use rustc_data_structures:: unord:: UnordMap ;
1415use rustc_errors:: DiagInner ;
1516use rustc_index:: IndexVec ;
@@ -89,6 +90,38 @@ pub(crate) struct MarkFrame<'a> {
8990 parent : Option < & ' a MarkFrame < ' a > > ,
9091}
9192
93+ /// The edge list of one node being marked green: it occupies `buf[start..]` of the shared
94+ /// scratch buffer and is popped again on drop, restoring the buffer for the enclosing call.
95+ struct EdgeFrame < ' a > {
96+ buf : & ' a mut Vec < DepNodeIndex > ,
97+ start : usize ,
98+ }
99+
100+ impl < ' a > EdgeFrame < ' a > {
101+ #[ inline]
102+ fn new ( buf : & ' a mut Vec < DepNodeIndex > ) -> Self {
103+ EdgeFrame { start : buf. len ( ) , buf }
104+ }
105+
106+ #[ inline]
107+ fn push ( & mut self , edge : DepNodeIndex ) {
108+ self . buf . push ( edge) ;
109+ }
110+
111+ /// The edges pushed onto this frame so far.
112+ #[ inline]
113+ fn get ( & self ) -> & [ DepNodeIndex ] {
114+ & self . buf [ self . start ..]
115+ }
116+ }
117+
118+ impl Drop for EdgeFrame < ' _ > {
119+ #[ inline]
120+ fn drop ( & mut self ) {
121+ self . buf . truncate ( self . start ) ;
122+ }
123+ }
124+
92125#[ derive( Debug ) ]
93126pub ( super ) enum DepNodeColor {
94127 Green ( DepNodeIndex ) ,
@@ -119,6 +152,9 @@ pub struct DepGraphData {
119152 /// a particular query result was decoded from disk
120153 /// (not just marked green)
121154 debug_loaded_from_disk : Lock < FxHashSet < DepNode > > ,
155+
156+ /// Per-worker edge buffer amortized across `try_mark_green` calls.
157+ green_edge_buf : WorkerLocal < Cell < Vec < DepNodeIndex > > > ,
122158}
123159
124160pub fn hash_result < R > ( hcx : & mut StableHashState < ' _ > , result : & R ) -> Fingerprint
@@ -175,6 +211,7 @@ impl DepGraph {
175211 previous : prev_graph,
176212 colors,
177213 debug_loaded_from_disk : Default :: default ( ) ,
214+ green_edge_buf : WorkerLocal :: default ( ) ,
178215 } ) ) ,
179216 virtual_dep_node_index : Arc :: new ( AtomicU32 :: new ( 0 ) ) ,
180217 }
@@ -790,8 +827,9 @@ impl DepGraphData {
790827 fn promote_node_and_deps_to_current (
791828 & self ,
792829 prev_index : SerializedDepNodeIndex ,
830+ edges : & [ DepNodeIndex ] ,
793831 ) -> Option < DepNodeIndex > {
794- let dep_node_index = self . current . encoder . send_promoted ( prev_index, & self . colors ) ;
832+ let dep_node_index = self . current . encoder . send_promoted ( prev_index, & self . colors , edges ) ;
795833
796834 #[ cfg( debug_assertions) ]
797835 if let Some ( dep_node_index) = dep_node_index {
@@ -878,20 +916,29 @@ impl DepGraphData {
878916 // in the previous compilation session too, so we can try to
879917 // mark it as green by recursively marking all of its
880918 // dependencies green.
881- self . try_mark_previous_green ( tcx, prev_index, None )
882- . map ( |dep_node_index| ( prev_index, dep_node_index) )
919+
920+ // Reuse a per-worker buffer for the edges instead of allocating one per call.
921+ // The recursion gives it back empty: each `EdgeFrame` pops its edges on drop.
922+ let mut edge_buf = self . green_edge_buf . take ( ) ;
923+ let result = self . try_mark_previous_green ( tcx, prev_index, None , & mut edge_buf) ;
924+ debug_assert ! ( edge_buf. is_empty( ) ) ;
925+ self . green_edge_buf . set ( edge_buf) ;
926+ result. map ( |dep_node_index| ( prev_index, dep_node_index) )
883927 }
884928 }
885929 }
886930
887931 /// Try to mark a dep-node which existed in the previous compilation session as green.
888- #[ instrument( skip( self , tcx, prev_dep_node_index, frame) , level = "debug" ) ]
932+ #[ instrument( skip( self , tcx, prev_dep_node_index, frame, edge_buf ) , level = "debug" ) ]
889933 fn try_mark_previous_green < ' tcx > (
890934 & self ,
891935 tcx : TyCtxt < ' tcx > ,
892936 prev_dep_node_index : SerializedDepNodeIndex ,
893937 frame : Option < & MarkFrame < ' _ > > ,
938+ // Amortized buffer to store edges in.
939+ edge_buf : & mut Vec < DepNodeIndex > ,
894940 ) -> Option < DepNodeIndex > {
941+ let mut edges = EdgeFrame :: new ( edge_buf) ;
895942 let frame = MarkFrame { index : prev_dep_node_index, parent : frame } ;
896943
897944 // We never try to mark eval_always nodes as green
@@ -901,7 +948,10 @@ impl DepGraphData {
901948 match self . colors . get ( parent_dep_node_index) {
902949 // This dependency has been marked as green before, we are still ok and can
903950 // continue checking the remaining dependencies.
904- DepNodeColor :: Green ( _) => continue ,
951+ DepNodeColor :: Green ( parent_index) => {
952+ edges. push ( parent_index) ;
953+ continue ;
954+ }
905955
906956 // This dependency's result is different to the previous compilation session. We
907957 // cannot mark this dep_node as green, so stop checking.
@@ -915,8 +965,16 @@ impl DepGraphData {
915965
916966 // If this dependency isn't eval_always, try to mark it green recursively.
917967 if !tcx. is_eval_always ( parent_dep_node. kind )
918- && self . try_mark_previous_green ( tcx, parent_dep_node_index, Some ( & frame) ) . is_some ( )
968+ && let Some ( parent_index) = self . try_mark_previous_green (
969+ tcx,
970+ parent_dep_node_index,
971+ Some ( & frame) ,
972+ // Pass the edge buffer to the recursive call.
973+ // It will use an `EdgeFrame` to give it back unchanged.
974+ edges. buf ,
975+ )
919976 {
977+ edges. push ( parent_index) ;
920978 continue ;
921979 }
922980
@@ -926,7 +984,10 @@ impl DepGraphData {
926984 }
927985
928986 match self . colors . get ( parent_dep_node_index) {
929- DepNodeColor :: Green ( _) => continue ,
987+ DepNodeColor :: Green ( parent_index) => {
988+ edges. push ( parent_index) ;
989+ continue ;
990+ }
930991 DepNodeColor :: Red => return None ,
931992 DepNodeColor :: Unknown => { }
932993 }
@@ -954,7 +1015,8 @@ impl DepGraphData {
9541015 // adding all the appropriate edges imported from the previous graph.
9551016 //
9561017 // `no_hash` nodes may fail this promotion due to already being conservatively colored red.
957- let dep_node_index = self . promote_node_and_deps_to_current ( prev_dep_node_index) ?;
1018+ let dep_node_index =
1019+ self . promote_node_and_deps_to_current ( prev_dep_node_index, edges. get ( ) ) ?;
9581020
9591021 // ... and finally storing a "Green" entry in the color map.
9601022 // Multiple threads can all write the same color here.
0 commit comments