Skip to content
This repository was archived by the owner on Sep 9, 2025. It is now read-only.

Commit 8fbdfd3

Browse files
author
Hendrik van Antwerpen
committed
Only collect stats when explicitly enabled
1 parent 25139d8 commit 8fbdfd3

3 files changed

Lines changed: 103 additions & 57 deletions

File tree

‎stack-graphs/src/stitching.rs‎

Lines changed: 59 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -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 {
13541371
pub 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

13591378
impl 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

13701398
impl 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

13761405
impl Default for StitcherConfig {
13771406
fn default() -> Self {
13781407
Self {
13791408
detect_similar_paths: true,
1409+
collect_stats: false,
13801410
}
13811411
}
13821412
}

‎tree-sitter-stack-graphs/src/cli/index.rs‎

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ impl IndexArgs {
113113
let mut indexer = Indexer::new(&mut db, &mut loader, &reporter);
114114
indexer.force = self.force;
115115
indexer.max_file_time = self.max_file_time;
116+
indexer.set_collect_stats(self.stats);
116117

117118
let source_paths = self
118119
.source_paths
@@ -158,7 +159,7 @@ pub struct Indexer<'a> {
158159
db: &'a mut SQLiteWriter,
159160
loader: &'a mut Loader,
160161
reporter: &'a dyn Reporter,
161-
stats: IndexingStats,
162+
stats: Option<IndexingStats>,
162163
/// Index files, even if they already exist in the database.
163164
pub force: bool,
164165
/// Maximum time per file.
@@ -177,7 +178,15 @@ impl<'a> Indexer<'a> {
177178
reporter,
178179
force: false,
179180
max_file_time: None,
180-
stats: IndexingStats::default(),
181+
stats: None,
182+
}
183+
}
184+
185+
pub fn set_collect_stats(&mut self, collect_stats: bool) {
186+
if !collect_stats {
187+
self.stats = None;
188+
} else if self.stats.is_none() {
189+
self.stats = Some(IndexingStats::default());
181190
}
182191
}
183192

@@ -294,8 +303,9 @@ impl<'a> Indexer<'a> {
294303
}
295304
Err(e) => return Err(IndexError::LoadError(e)),
296305
};
297-
let stitcher_config =
298-
StitcherConfig::default().with_detect_similar_paths(!lcs.no_similar_paths_in_file());
306+
let stitcher_config = StitcherConfig::default()
307+
.with_detect_similar_paths(!lcs.no_similar_paths_in_file())
308+
.with_collect_stats(self.stats.is_some());
299309

300310
let source = file_reader.get(source_path)?;
301311
let tag = sha1(source);
@@ -365,21 +375,19 @@ impl<'a> Indexer<'a> {
365375
}
366376
}
367377
};
368-
{
369-
self.stats
370-
.total_graph_nodes
371-
.record(graph.iter_nodes().count());
378+
if let Some(stats) = &mut self.stats {
379+
stats.total_graph_nodes.record(graph.iter_nodes().count());
372380
let mut total_edges = 0;
373381
for n in graph.iter_nodes() {
374382
let edge_count = graph.outgoing_edges(n).count();
375383
if graph[n].is_root() {
376-
self.stats.root_out_degree = edge_count;
384+
stats.root_out_degree = edge_count;
377385
} else {
378-
self.stats.node_out_degrees.record(edge_count);
386+
stats.node_out_degrees.record(edge_count);
379387
total_edges += edge_count;
380388
}
381389
}
382-
self.stats.total_graph_edges.record(total_edges);
390+
stats.total_graph_edges.record(total_edges);
383391
}
384392

385393
let mut partials = PartialPaths::new();
@@ -395,7 +403,9 @@ impl<'a> Indexer<'a> {
395403
},
396404
) {
397405
Ok(stitching_stats) => {
398-
self.stats.stitching_stats += stitching_stats;
406+
if let Some(stats) = &mut self.stats {
407+
stats.stitching_stats += stitching_stats;
408+
}
399409
}
400410
Err(_) => {
401411
file_status.warning("path computation timed out", None);
@@ -475,12 +485,8 @@ impl<'a> Indexer<'a> {
475485
false
476486
}
477487

478-
pub fn stats(&self) -> &IndexingStats {
479-
&self.stats
480-
}
481-
482488
pub fn into_stats(self) -> IndexingStats {
483-
self.stats
489+
self.stats.unwrap_or_default()
484490
}
485491
}
486492

‎tree-sitter-stack-graphs/src/cli/query.rs‎

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ impl QueryArgs {
5151
wait_for_input()?;
5252
}
5353
let mut db = SQLiteReader::open(&db_path)?;
54-
let stitching_stats = self.target.run(&mut db)?;
54+
let stitching_stats = self.target.run(&mut db, self.stats)?;
5555
if self.stats {
5656
println!();
5757
print_stitching_stats(stitching_stats);
@@ -68,9 +68,10 @@ pub enum Target {
6868
}
6969

7070
impl Target {
71-
pub fn run(self, db: &mut SQLiteReader) -> anyhow::Result<StitchingStats> {
71+
fn run(self, db: &mut SQLiteReader, collect_stats: bool) -> anyhow::Result<StitchingStats> {
7272
let reporter = ConsoleReporter::details();
7373
let mut querier = Querier::new(db, &reporter);
74+
querier.set_collect_stats(collect_stats);
7475
match self {
7576
Self::Definition(cmd) => cmd.run(&mut querier)?,
7677
}
@@ -152,15 +153,23 @@ impl Definition {
152153
pub struct Querier<'a> {
153154
db: &'a mut SQLiteReader,
154155
reporter: &'a dyn Reporter,
155-
stats: StitchingStats,
156+
stats: Option<StitchingStats>,
156157
}
157158

158159
impl<'a> Querier<'a> {
159160
pub fn new(db: &'a mut SQLiteReader, reporter: &'a dyn Reporter) -> Self {
160161
Self {
161162
db,
162163
reporter,
163-
stats: StitchingStats::default(),
164+
stats: None,
165+
}
166+
}
167+
168+
pub fn set_collect_stats(&mut self, collect_stats: bool) {
169+
if !collect_stats {
170+
self.stats = None;
171+
} else if self.stats.is_none() {
172+
self.stats = Some(StitchingStats::default());
164173
}
165174
}
166175

@@ -208,7 +217,8 @@ impl<'a> Querier<'a> {
208217
let mut reference_paths = Vec::new();
209218
let stitcher_config = StitcherConfig::default()
210219
// always detect similar paths, we don't know the language configurations for the data in the database
211-
.with_detect_similar_paths(true);
220+
.with_detect_similar_paths(true)
221+
.with_collect_stats(self.stats.is_some());
212222
let ref_result = ForwardPartialPathStitcher::find_all_complete_partial_paths(
213223
self.db,
214224
std::iter::once(node),
@@ -219,7 +229,11 @@ impl<'a> Querier<'a> {
219229
},
220230
);
221231
match ref_result {
222-
Ok(ref_stats) => self.stats += ref_stats,
232+
Ok(ref_stats) => {
233+
if let Some(stats) = &mut self.stats {
234+
*stats += ref_stats
235+
}
236+
}
223237
Err(err) => {
224238
self.reporter.failed(&log_path, "query timed out", None);
225239
return Err(err.into());
@@ -276,12 +290,8 @@ impl<'a> Querier<'a> {
276290
Ok(result)
277291
}
278292

279-
pub fn stats(&self) -> &StitchingStats {
280-
&self.stats
281-
}
282-
283293
pub fn into_stats(self) -> StitchingStats {
284-
self.stats
294+
self.stats.unwrap_or_default()
285295
}
286296
}
287297

0 commit comments

Comments
 (0)