@@ -829,7 +829,7 @@ pub struct ForwardPartialPathStitcher<H> {
829829 queue : VecDeque < ( PartialPath , AppendingCycleDetector < H > , bool ) > ,
830830 // tracks the number of initial paths in the queue because we do not want call
831831 // extend_until on those
832- initial_paths : usize ,
832+ initial_paths_in_queue : usize ,
833833 // next_iteration is a tuple of queues instead of an queue of tuples so that the path queue
834834 // can be cheaply exposed through the C API as a continuous memory block
835835 next_iteration : (
@@ -841,7 +841,8 @@ pub struct ForwardPartialPathStitcher<H> {
841841 similar_path_detector : Option < SimilarPathDetector < PartialPath > > ,
842842 check_only_join_nodes : bool ,
843843 max_work_per_phase : usize ,
844- stats : Stats ,
844+ initial_paths : usize ,
845+ stats : Option < Stats > ,
845846 #[ cfg( feature = "copious-debugging" ) ]
846847 phase_number : usize ,
847848}
@@ -866,13 +867,12 @@ impl<H> ForwardPartialPathStitcher<H> {
866867 ( p, c, false )
867868 } )
868869 . multiunzip ( ) ;
869- let mut stats = Stats :: default ( ) ;
870- stats. initial_paths . record ( next_iteration. 0 . len ( ) ) ;
870+ let initial_paths = next_iteration. 0 . len ( ) ;
871871 Self {
872872 candidates : Vec :: new ( ) ,
873873 extensions : Vec :: new ( ) ,
874874 queue : VecDeque :: new ( ) ,
875- initial_paths : next_iteration . 0 . len ( ) ,
875+ initial_paths_in_queue : initial_paths ,
876876 next_iteration,
877877 appended_paths,
878878 // By default, all paths are checked for similarity
@@ -881,7 +881,8 @@ impl<H> ForwardPartialPathStitcher<H> {
881881 check_only_join_nodes : false ,
882882 // By default, there's no artificial bound on the amount of work done per phase
883883 max_work_per_phase : usize:: MAX ,
884- stats,
884+ initial_paths,
885+ stats : None ,
885886 #[ cfg( feature = "copious-debugging" ) ]
886887 phase_number : 1 ,
887888 }
@@ -916,11 +917,24 @@ impl<H> ForwardPartialPathStitcher<H> {
916917 self . max_work_per_phase = max_work_per_phase;
917918 }
918919
920+ /// Sets whether to collect statistics during stitching.
921+ pub fn set_collect_stats ( & mut self , collect_stats : bool ) {
922+ if !collect_stats {
923+ self . stats = None ;
924+ } else if self . stats . is_none ( ) {
925+ let mut stats = Stats :: default ( ) ;
926+ stats. initial_paths . record ( self . initial_paths ) ;
927+ self . stats = Some ( stats) ;
928+ }
929+ }
930+
919931 pub fn into_stats ( mut self ) -> Stats {
920- if let Some ( similar_path_detector) = self . similar_path_detector {
921- self . stats . similar_paths_stats = similar_path_detector. stats ( ) ;
932+ if let ( Some ( stats) , Some ( similar_path_detector) ) =
933+ ( & mut self . stats , self . similar_path_detector )
934+ {
935+ stats. similar_paths_stats = similar_path_detector. stats ( ) ;
922936 }
923- self . stats
937+ self . stats . unwrap_or_default ( )
924938 }
925939}
926940
@@ -1069,22 +1083,21 @@ impl<H: Clone> ForwardPartialPathStitcher<H> {
10691083 self . next_iteration . 2 . push ( new_has_split) ;
10701084 }
10711085
1072- let ( graph, _, _) = candidates. get_graph_partials_and_db ( ) ;
1073- let end_node = & graph[ partial_path. end_node ] ;
1074- if end_node. is_root ( ) {
1075- self . stats . candidates_per_root_path . record ( candidate_count) ;
1076- self . stats . extensions_per_root_path . record ( extension_count) ;
1077- self . stats . root_visits += 1 ;
1078- } else {
1079- self . stats . candidates_per_node_path . record ( candidate_count) ;
1080- self . stats . extensions_per_node_path . record ( extension_count) ;
1081- self . stats . node_visits . record ( end_node. id ( ) ) ;
1082- }
1083-
1084- if extension_count == 0 {
1085- self . stats
1086- . terminal_path_lengh
1087- . record ( partial_path. edges . len ( ) ) ;
1086+ if let Some ( stats) = & mut self . stats {
1087+ let ( graph, _, _) = candidates. get_graph_partials_and_db ( ) ;
1088+ let end_node = & graph[ partial_path. end_node ] ;
1089+ if end_node. is_root ( ) {
1090+ stats. candidates_per_root_path . record ( candidate_count) ;
1091+ stats. extensions_per_root_path . record ( extension_count) ;
1092+ stats. root_visits += 1 ;
1093+ } else {
1094+ stats. candidates_per_node_path . record ( candidate_count) ;
1095+ stats. extensions_per_node_path . record ( extension_count) ;
1096+ stats. node_visits . record ( end_node. id ( ) ) ;
1097+ }
1098+ if extension_count == 0 {
1099+ stats. terminal_path_lengh . record ( partial_path. edges . len ( ) ) ;
1100+ }
10881101 }
10891102 candidate_count
10901103 }
@@ -1119,16 +1132,18 @@ impl<H: Clone> ForwardPartialPathStitcher<H> {
11191132 self . next_iteration. 1 . drain( ..) ,
11201133 self . next_iteration. 2 . drain( ..) ,
11211134 ) ) ;
1122- self . stats . queued_paths_per_phase . record ( self . queue . len ( ) ) ;
1135+ if let Some ( stats) = & mut self . stats {
1136+ stats. queued_paths_per_phase . record ( self . queue . len ( ) ) ;
1137+ }
11231138 let mut work_performed = 0 ;
11241139 while let Some ( ( partial_path, cycle_detector, has_split) ) = self . queue . pop_front ( ) {
11251140 let ( graph, partials, _) = candidates. get_graph_partials_and_db ( ) ;
11261141 copious_debugging ! (
11271142 "--> Candidate partial path {}" ,
11281143 partial_path. display( graph, partials)
11291144 ) ;
1130- if self . initial_paths > 0 {
1131- self . initial_paths -= 1 ;
1145+ if self . initial_paths_in_queue > 0 {
1146+ self . initial_paths_in_queue -= 1 ;
11321147 } else if !extend_while ( graph, partials, & partial_path) {
11331148 copious_debugging ! (
11341149 " Do not extend {}" ,
@@ -1141,7 +1156,9 @@ impl<H: Clone> ForwardPartialPathStitcher<H> {
11411156 break ;
11421157 }
11431158 }
1144- self . stats . processed_paths_per_phase . record ( work_performed) ;
1159+ if let Some ( stats) = & mut self . stats {
1160+ stats. processed_paths_per_phase . record ( work_performed) ;
1161+ }
11451162
11461163 #[ cfg( feature = "copious-debugging" ) ]
11471164 {
@@ -1354,6 +1371,8 @@ impl std::ops::AddAssign<&Self> for Stats {
13541371pub struct StitcherConfig {
13551372 /// Enables similar path detection during path stitching.
13561373 detect_similar_paths : bool ,
1374+ /// Collect statistics about path stitching.
1375+ collect_stats : bool ,
13571376}
13581377
13591378impl StitcherConfig {
@@ -1365,18 +1384,29 @@ impl StitcherConfig {
13651384 self . detect_similar_paths = detect_similar_paths;
13661385 self
13671386 }
1387+
1388+ pub fn collect_stats ( & self ) -> bool {
1389+ self . collect_stats
1390+ }
1391+
1392+ pub fn with_collect_stats ( mut self , collect_stats : bool ) -> Self {
1393+ self . collect_stats = collect_stats;
1394+ self
1395+ }
13681396}
13691397
13701398impl StitcherConfig {
13711399 fn apply < H > ( & self , stitcher : & mut ForwardPartialPathStitcher < H > ) {
13721400 stitcher. set_similar_path_detection ( self . detect_similar_paths ) ;
1401+ stitcher. set_collect_stats ( self . collect_stats ) ;
13731402 }
13741403}
13751404
13761405impl Default for StitcherConfig {
13771406 fn default ( ) -> Self {
13781407 Self {
13791408 detect_similar_paths : true ,
1409+ collect_stats : false ,
13801410 }
13811411 }
13821412}
0 commit comments