@@ -339,13 +339,11 @@ impl<D: Deps> DepGraphData<D> {
339339        let  ( result,  edges)  = if  cx. dep_context ( ) . is_eval_always ( key. kind )  { 
340340            ( with_deps ( TaskDepsRef :: EvalAlways ) ,  EdgesVec :: new ( ) ) 
341341        }  else  { 
342-             let  task_deps = Lock :: new ( TaskDeps   { 
342+             let  task_deps = Lock :: new ( TaskDeps :: new ( 
343343                #[ cfg( debug_assertions) ]  
344-                 node :  Some ( key) , 
345-                 reads :  EdgesVec :: new ( ) , 
346-                 read_set :  Default :: default ( ) , 
347-                 phantom_data :  PhantomData , 
348-             } ) ; 
344+                 Some ( key) , 
345+                 0 , 
346+             ) ) ; 
349347            ( with_deps ( TaskDepsRef :: Allow ( & task_deps) ) ,  task_deps. into_inner ( ) . reads ) 
350348        } ; 
351349
@@ -377,12 +375,18 @@ impl<D: Deps> DepGraphData<D> {
377375    { 
378376        debug_assert ! ( !cx. is_eval_always( dep_kind) ) ; 
379377
380-         let  task_deps = Lock :: new ( TaskDeps :: default ( ) ) ; 
378+         // Large numbers of reads are common enough here that pre-sizing `read_set` 
379+         // to 128 actually helps perf on some benchmarks. 
380+         let  task_deps = Lock :: new ( TaskDeps :: new ( 
381+             #[ cfg( debug_assertions) ]  
382+             None , 
383+             128 , 
384+         ) ) ; 
381385        let  result = D :: with_deps ( TaskDepsRef :: Allow ( & task_deps) ,  op) ; 
382386        let  task_deps = task_deps. into_inner ( ) ; 
383-         let  task_deps  = task_deps. reads ; 
387+         let  reads  = task_deps. reads ; 
384388
385-         let  dep_node_index = match  task_deps . len ( )  { 
389+         let  dep_node_index = match  reads . len ( )  { 
386390            0  => { 
387391                // Because the dep-node id of anon nodes is computed from the sets of its 
388392                // dependencies we already know what the ID of this dependency-less node is 
@@ -393,7 +397,7 @@ impl<D: Deps> DepGraphData<D> {
393397            } 
394398            1  => { 
395399                // When there is only one dependency, don't bother creating a node. 
396-                 task_deps [ 0 ] 
400+                 reads [ 0 ] 
397401            } 
398402            _ => { 
399403                // The dep node indices are hashed here instead of hashing the dep nodes of the 
@@ -402,7 +406,7 @@ impl<D: Deps> DepGraphData<D> {
402406                // combining it with the per session random number `anon_id_seed`. This hash only need 
403407                // to map the dependencies to a single value on a per session basis. 
404408                let  mut  hasher = StableHasher :: new ( ) ; 
405-                 task_deps . hash ( & mut  hasher) ; 
409+                 reads . hash ( & mut  hasher) ; 
406410
407411                let  target_dep_node = DepNode  { 
408412                    kind :  dep_kind, 
@@ -420,7 +424,7 @@ impl<D: Deps> DepGraphData<D> {
420424                // memory impact of this `anon_node_to_index` map remains tolerable, and helps 
421425                // us avoid useless growth of the graph with almost-equivalent nodes. 
422426                self . current . anon_node_to_index . get_or_insert_with ( target_dep_node,  || { 
423-                     self . current . alloc_new_node ( target_dep_node,  task_deps ,  Fingerprint :: ZERO ) 
427+                     self . current . alloc_new_node ( target_dep_node,  reads ,  Fingerprint :: ZERO ) 
424428                } ) 
425429            } 
426430        } ; 
@@ -471,18 +475,17 @@ impl<D: Deps> DepGraph<D> {
471475                    data. current . total_read_count . fetch_add ( 1 ,  Ordering :: Relaxed ) ; 
472476                } 
473477
474-                 // As long as we only have a low number of reads we can avoid doing a hash  
475-                 // insert and potentially allocating/reallocating the hashmap  
476-                 let  new_read = if  task_deps. reads . len ( )  <  EdgesVec :: INLINE_CAPACITY  { 
477-                     task_deps. reads . iter ( ) . all ( |other|  * other !=  dep_node_index) 
478+                 // Has `dep_node_index` been seen before? Use either a linear scan or a hashset  
479+                 // lookup to determine this. See `TaskDeps::read_set` for details.  
480+                 let  new_read = if  task_deps. reads . len ( )  <=  TaskDeps :: LINEAR_SCAN_MAX  { 
481+                     ! task_deps. reads . contains ( & dep_node_index) 
478482                }  else  { 
479483                    task_deps. read_set . insert ( dep_node_index) 
480484                } ; 
481485                if  new_read { 
482486                    task_deps. reads . push ( dep_node_index) ; 
483-                     if  task_deps. reads . len ( )  == EdgesVec :: INLINE_CAPACITY  { 
484-                         // Fill `read_set` with what we have so far so we can use the hashset 
485-                         // next time 
487+                     if  task_deps. reads . len ( )  == TaskDeps :: LINEAR_SCAN_MAX  + 1  { 
488+                         // Fill `read_set` with what we have so far. Future lookups will use it. 
486489                        task_deps. read_set . extend ( task_deps. reads . iter ( ) . copied ( ) ) ; 
487490                    } 
488491
@@ -1292,18 +1295,30 @@ pub enum TaskDepsRef<'a> {
12921295pub  struct  TaskDeps  { 
12931296    #[ cfg( debug_assertions) ]  
12941297    node :  Option < DepNode > , 
1298+ 
1299+     /// A vector of `DepNodeIndex`, basically. 
12951300reads :  EdgesVec , 
1301+ 
1302+     /// When adding new edges to `reads` in `DepGraph::read_index` we need to determine if the edge 
1303+ /// has been seen before. If the number of elements in `reads` is small, we just do a linear 
1304+ /// scan. If the number is higher, a hashset has better perf. This field is that hashset. It's 
1305+ /// only used if the number of elements in `reads` exceeds `LINEAR_SCAN_MAX`. 
12961306read_set :  FxHashSet < DepNodeIndex > , 
1307+ 
12971308    phantom_data :  PhantomData < DepNode > , 
12981309} 
12991310
1300- impl  Default  for  TaskDeps  { 
1301-     fn  default ( )  -> Self  { 
1302-         Self  { 
1311+ impl  TaskDeps  { 
1312+     /// See `TaskDeps::read_set` above. 
1313+ const  LINEAR_SCAN_MAX :  usize  = 16 ; 
1314+ 
1315+     #[ inline]  
1316+     fn  new ( #[ cfg( debug_assertions) ]   node :  Option < DepNode > ,  read_set_capacity :  usize )  -> Self  { 
1317+         TaskDeps  { 
13031318            #[ cfg( debug_assertions) ]  
1304-             node :   None , 
1319+             node, 
13051320            reads :  EdgesVec :: new ( ) , 
1306-             read_set :  FxHashSet :: with_capacity_and_hasher ( 128 ,  Default :: default ( ) ) , 
1321+             read_set :  FxHashSet :: with_capacity_and_hasher ( read_set_capacity ,  Default :: default ( ) ) , 
13071322            phantom_data :  PhantomData , 
13081323        } 
13091324    } 
0 commit comments