From 3d31c59194629607a8c580b80a45228420a5cb97 Mon Sep 17 00:00:00 2001 From: kelmith Date: Wed, 24 Dec 2025 18:12:07 +0530 Subject: [PATCH 1/6] feat: rust profiling with flamegraph, tokio console and custom tracing --- Cargo.lock | 244 +++++++++++++++++++++++++- Cargo.toml | 3 + ast/src/builder/core.rs | 9 +- ast/src/builder/streaming.rs | 4 +- ast/src/lang/call_finder.rs | 9 + ast/src/lang/graphs/btreemap_graph.rs | 3 + ast/src/lang/graphs/graph_ops.rs | 4 +- ast/src/lang/linker.rs | 5 +- ast/src/repo.rs | 4 +- standalone/Cargo.toml | 3 +- standalone/src/main.rs | 2 + 11 files changed, 279 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a17574f25..000c65ea1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -785,7 +785,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", - "axum-core", + "axum-core 0.4.5", "axum-macros", "base64 0.22.1", "bytes", @@ -796,7 +796,7 @@ dependencies = [ "hyper 1.7.0", "hyper-util", "itoa", - "matchit", + "matchit 0.7.3", "memchr", "mime", "multer", @@ -817,6 +817,31 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" +dependencies = [ + "axum-core 0.5.5", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "itoa", + "matchit 0.8.4", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "sync_wrapper", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "axum-core" version = "0.4.5" @@ -838,6 +863,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-core" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" +dependencies = [ + "bytes", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", +] + [[package]] name = "axum-macros" version = "0.4.2" @@ -1216,6 +1259,46 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "console-api" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8599749b6667e2f0c910c1d0dff6901163ff698a52d5a39720f61b5be4b20d3" +dependencies = [ + "futures-core", + "prost", + "prost-types", + "tonic", + "tonic-prost", + "tracing-core", +] + +[[package]] +name = "console-subscriber" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4915b7d8dd960457a1b6c380114c2944f728e7c65294ab247ae6b6f1f37592" +dependencies = [ + "console-api", + "crossbeam-channel", + "crossbeam-utils", + "futures-task", + "hdrhistogram", + "humantime", + "hyper-util", + "prost", + "prost-types", + "serde", + "serde_json", + "thread_local", + "tokio", + "tokio-stream", + "tonic", + "tracing", + "tracing-core", + "tracing-subscriber", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -1303,6 +1386,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -2131,6 +2223,19 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +[[package]] +name = "hdrhistogram" +version = "7.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d" +dependencies = [ + "base64 0.21.7", + "byteorder", + "flate2", + "nom", + "num-traits", +] + [[package]] name = "heck" version = "0.5.0" @@ -2253,6 +2358,12 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" + [[package]] name = "hyper" version = "0.14.32" @@ -2334,6 +2445,19 @@ dependencies = [ "webpki-roots 1.0.3", ] +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper 1.7.0", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "hyper-tls" version = "0.6.0" @@ -2911,6 +3035,12 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + [[package]] name = "matrixmultiply" version = "0.3.10" @@ -3453,6 +3583,26 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + [[package]] name = "pin-project-lite" version = "0.2.16" @@ -3596,6 +3746,38 @@ dependencies = [ "syn 2.0.106", ] +[[package]] +name = "prost" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "prost-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72" +dependencies = [ + "prost", +] + [[package]] name = "pxfm" version = "0.1.25" @@ -4542,9 +4724,10 @@ name = "standalone" version = "0.1.0" dependencies = [ "ast", - "axum", + "axum 0.7.9", "base64 0.21.7", "chrono", + "console-subscriber", "futures", "hex", "hmac", @@ -4920,6 +5103,7 @@ dependencies = [ "slab", "socket2 0.6.0", "tokio-macros", + "tracing", "windows-sys 0.59.0", ] @@ -4964,6 +5148,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-tungstenite" version = "0.24.0" @@ -5023,6 +5218,46 @@ dependencies = [ "winnow", ] +[[package]] +name = "tonic" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" +dependencies = [ + "async-trait", + "axum 0.8.8", + "base64 0.22.1", + "bytes", + "h2 0.4.12", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "hyper 1.7.0", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "socket2 0.6.0", + "sync_wrapper", + "tokio", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tonic-prost" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" +dependencies = [ + "bytes", + "prost", + "tonic", +] + [[package]] name = "tower" version = "0.5.2" @@ -5031,9 +5266,12 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", + "indexmap", "pin-project-lite", + "slab", "sync_wrapper", "tokio", + "tokio-util", "tower-layer", "tower-service", "tracing", diff --git a/Cargo.toml b/Cargo.toml index 04da95694..5e1b204d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,3 +2,6 @@ members = ["ast", "lsp", "shared", "skill", "standalone"] resolver = "2" + +[profile.release] +debug = true diff --git a/ast/src/builder/core.rs b/ast/src/builder/core.rs index dd162d448..d95e8e009 100644 --- a/ast/src/builder/core.rs +++ b/ast/src/builder/core.rs @@ -20,7 +20,7 @@ use shared::error::Result; use std::collections::HashSet; use std::path::PathBuf; use tokio::fs; -use tracing::{debug, info, trace}; +use tracing::{debug, info, instrument, trace}; #[derive(Debug, Clone)] pub struct ImplementsRelationship { @@ -48,6 +48,8 @@ impl Repo { let streaming = std::env::var("STREAM_UPLOAD").is_ok(); self.build_graph_inner_with_streaming(streaming).await } + + #[instrument(skip(self))] pub async fn build_graph_inner_with_streaming(&self, streaming: bool) -> Result { let graph_root = strip_tmp(&self.root).display().to_string(); let mut graph = G::new(graph_root, self.lang.kind.clone()); @@ -799,6 +801,8 @@ impl Repo { info!("=> got {} data models", datamodel_count); Ok(()) } + + #[instrument(skip(self, graph), fields(files=filez.len()))] async fn process_functions_and_tests( &self, graph: &mut G, @@ -961,6 +965,8 @@ impl Repo { Ok(()) } + + #[instrument(skip(self, graph), fields(files=filez.len()))] fn process_endpoints(&self, graph: &mut G, filez: &[(String, String)]) -> Result<()> { self.send_status_update("process_endpoints", 11); let mut _i = 0; @@ -1021,6 +1027,7 @@ impl Repo { Ok(()) } + #[instrument(skip(self, graph, stats), fields(files=filez.len()))] async fn finalize_graph( &self, graph: &mut G, diff --git a/ast/src/builder/streaming.rs b/ast/src/builder/streaming.rs index a63b53420..3775381d8 100644 --- a/ast/src/builder/streaming.rs +++ b/ast/src/builder/streaming.rs @@ -5,7 +5,7 @@ use crate::lang::graphs::{neo4j::*, Neo4jGraph}; use crate::lang::{EdgeType, NodeData, NodeType}; use neo4rs::BoltMap; use shared::Result; -use tracing::{debug, info}; +use tracing::{debug, info, instrument}; use uuid::Uuid; pub struct GraphStreamingUploader {} @@ -14,7 +14,7 @@ impl GraphStreamingUploader { pub fn new() -> Self { Self {} } - +#[instrument(skip(self, neo, delta_node_queries), fields(stage, node_count = delta_node_queries.len()))] pub async fn flush_stage( &mut self, neo: &Neo4jGraph, diff --git a/ast/src/lang/call_finder.rs b/ast/src/lang/call_finder.rs index 486889d5b..f6a50c123 100644 --- a/ast/src/lang/call_finder.rs +++ b/ast/src/lang/call_finder.rs @@ -1,6 +1,7 @@ use super::parse::utils::trim_quotes; use super::queries::consts::{IMPORTS_ALIAS, IMPORTS_FROM, IMPORTS_NAME}; use super::{graphs::Graph, *}; +use tracing::instrument; use tree_sitter::QueryCursor; pub fn node_data_finder( @@ -23,6 +24,7 @@ pub fn node_data_finder( ) } +#[instrument(skip(graph), fields(func_name, current_file))] pub fn func_target_file_finder( func_name: &str, operand: &Option, @@ -85,6 +87,7 @@ pub fn func_target_file_finder( None } +#[instrument(skip(graph, lang), fields(current_file))] pub fn get_imports_for_file( current_file: &str, lang: &Lang, @@ -153,6 +156,7 @@ pub fn get_imports_for_file( } } +#[instrument(skip(graph), fields(func_name))] fn find_function_by_import( func_name: &str, import_names: Vec<(String, Vec)>, @@ -179,6 +183,7 @@ fn find_function_by_import( None } +#[instrument(skip(graph), fields(func_name, current_file))] fn find_only_one_function_file( func_name: &str, graph: &G, @@ -215,6 +220,7 @@ fn find_only_one_function_file( None } +#[instrument(skip(graph), fields(operand, func_name))] fn find_function_with_operand( operand: &str, func_name: &str, @@ -242,6 +248,7 @@ fn find_function_with_operand( target_file } +#[instrument(skip(graph), fields(var_name, func_name))] fn find_nested_function_in_variable( var_name: &str, func_name: &str, @@ -269,6 +276,7 @@ fn find_nested_function_in_variable( None } +#[instrument(skip(graph), fields(func_name, current_file))] fn find_function_in_same_file( func_name: &str, current_file: &str, @@ -294,6 +302,7 @@ fn find_function_in_same_file( None } +#[instrument(skip(graph), fields(func_name, current_file))] fn find_function_in_same_directory( func_name: &str, current_file: &str, diff --git a/ast/src/lang/graphs/btreemap_graph.rs b/ast/src/lang/graphs/btreemap_graph.rs index 95eccf65c..d5d641a6c 100644 --- a/ast/src/lang/graphs/btreemap_graph.rs +++ b/ast/src/lang/graphs/btreemap_graph.rs @@ -4,6 +4,7 @@ use crate::utils::{create_node_key, create_node_key_from_ref, sanitize_string}; use lsp::Language; use serde::Serialize; use shared::error::Result; +use tracing::instrument; use std::collections::{BTreeMap, BTreeSet, HashSet}; #[derive(Clone, Debug, Serialize, PartialEq, Eq)] @@ -67,6 +68,7 @@ impl Graph for BTreeMapGraph { (node_keys, edge_keys) } + #[instrument(skip(self), fields(node_type, name))] fn find_nodes_by_name(&self, node_type: NodeType, name: &str) -> Vec { let prefix = format!( "{}-{}", @@ -363,6 +365,7 @@ impl Graph for BTreeMapGraph { } } // Add calls only between function definitions not between function calls + #[instrument(skip(self, lang, calls))] fn add_calls(&mut self, calls: (Vec, Vec, Vec, Vec), lang: &Lang) { let (funcs, tests, int_tests, extras) = calls; // Diagnostic flag (see array_graph.rs for rationale) diff --git a/ast/src/lang/graphs/graph_ops.rs b/ast/src/lang/graphs/graph_ops.rs index c3fbf1721..e60a6c152 100644 --- a/ast/src/lang/graphs/graph_ops.rs +++ b/ast/src/lang/graphs/graph_ops.rs @@ -3,7 +3,7 @@ use std::time::Duration; use neo4rs::BoltMap; use shared::error::{Error, Result}; use tokio::sync::broadcast::Sender; -use tracing::{debug, error, info}; +use tracing::{debug, error, info, instrument}; use crate::lang::embedding::{vectorize_code_document, vectorize_query}; @@ -292,7 +292,7 @@ impl GraphOps { } - + #[instrument(skip(self, btree_graph, status_tx))] pub async fn upload_btreemap_to_neo4j( &mut self, btree_graph: &BTreeMapGraph, diff --git a/ast/src/lang/linker.rs b/ast/src/lang/linker.rs index 92920a1e9..c0d47ce2d 100644 --- a/ast/src/lang/linker.rs +++ b/ast/src/lang/linker.rs @@ -5,11 +5,12 @@ use regex::Regex; use shared::{Context, Error, Result}; use std::collections::{HashMap, HashSet}; use std::path::PathBuf; -use tracing::{debug, info}; +use tracing::{debug, info, instrument}; type EdgeKey = (String, String, usize); type EdgeIndex = HashMap>; +#[instrument(skip(edges))] fn build_edge_index(edges: &[Edge]) -> EdgeIndex { let mut index: EdgeIndex = HashMap::new(); for edge in edges { @@ -31,6 +32,7 @@ fn build_edge_index(edges: &[Edge]) -> EdgeIndex { index } +#[instrument(skip(graph))] pub fn link_integration_tests(graph: &mut G) -> Result<()> { let tests = graph.find_nodes_by_type(NodeType::IntegrationTest); if tests.is_empty() { @@ -361,6 +363,7 @@ pub fn extract_http_verbs_from_test(body: &str) -> Vec { verbs } +#[instrument(skip(graph))] pub fn link_api_nodes(graph: &mut G) -> Result<()> { // Collect requests and endpoints in a single pass let mut frontend_requests = Vec::new(); diff --git a/ast/src/repo.rs b/ast/src/repo.rs index 452cea17d..3931ece7e 100644 --- a/ast/src/repo.rs +++ b/ast/src/repo.rs @@ -13,7 +13,7 @@ use shared::{Context, Error, Result}; use std::str::FromStr; use std::{fs, path::PathBuf}; use tokio::sync::broadcast::Sender; -use tracing::{info, warn}; +use tracing::{info, instrument, warn}; use walkdir::{DirEntry, WalkDir}; const CONF_FILE_PATH: &str = ".ast.json"; @@ -86,6 +86,7 @@ impl Repos { let streaming = std::env::var("STREAM_UPLOAD").is_ok(); self.build_graphs_inner_impl(streaming).await } + #[instrument(skip(self))] async fn build_graphs_inner_impl(&self, streaming: bool) -> Result { if self.0.is_empty() { return Err(Error::Custom("Language is not supported".into())); @@ -194,6 +195,7 @@ impl Repo { skip_calls: false, }) } + #[instrument(skip(username, pat, files_filter, revs, commit, branch, use_lsp))] pub async fn new_clone_multi_detect( urls: &str, username: Option, diff --git a/standalone/Cargo.toml b/standalone/Cargo.toml index cc5143db0..5beb83762 100644 --- a/standalone/Cargo.toml +++ b/standalone/Cargo.toml @@ -10,9 +10,10 @@ lsp = { path = "../lsp" } serde = "1.0.210" serde_json = "1.0.129" -tokio = { version = "1", features = ["macros"] } +tokio = { version = "1", features = ["macros", "tracing", "rt-multi-thread"] } tracing = { version = "0.1.37" } tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } +console-subscriber = "0.5" tower-http = { version = "0.5", features = ["fs", "cors", "timeout", "trace"] } axum = { version = "0.7", features = ["ws", "multipart", "macros"] } futures = "0.3.31" diff --git a/standalone/src/main.rs b/standalone/src/main.rs index 115e508f9..74914175c 100644 --- a/standalone/src/main.rs +++ b/standalone/src/main.rs @@ -34,6 +34,8 @@ use tracing_subscriber::{filter::LevelFilter, EnvFilter}; .with_env_filter(filter) .init(); + console_subscriber::init(); + let mut graph_ops = ast::lang::graphs::graph_ops::GraphOps::new(); if let Err(e) = graph_ops.check_connection().await { panic!("Failed to connect to graph db: {:?}", e); From c3402eb9f25663acaed94158468450102d058f4d Mon Sep 17 00:00:00 2001 From: kelmith Date: Wed, 24 Dec 2025 22:43:16 +0530 Subject: [PATCH 2/6] fix: resolve async issues with trace --- .gitignore | 5 +- Cargo.lock | 243 +--------------------------------- ast/src/builder/core.rs | 25 +++- ast/src/lang/call_finder.rs | 33 +++-- ast/src/lang/linker.rs | 1 + ast/src/lang/queries/react.rs | 1 - ast/src/repo.rs | 1 - standalone/Cargo.toml | 2 +- standalone/src/main.rs | 2 +- 9 files changed, 58 insertions(+), 255 deletions(-) diff --git a/.gitignore b/.gitignore index a5b4ef12a..289c8462e 100644 --- a/.gitignore +++ b/.gitignore @@ -67,4 +67,7 @@ standalone/coverage_reports/* out.txt #Local AI files -.github/copilot-* \ No newline at end of file +.github/copilot-* + +# Profiling data +cargo-flamegraph.trace \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 000c65ea1..3acd389b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -785,7 +785,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", - "axum-core 0.4.5", + "axum-core", "axum-macros", "base64 0.22.1", "bytes", @@ -796,7 +796,7 @@ dependencies = [ "hyper 1.7.0", "hyper-util", "itoa", - "matchit 0.7.3", + "matchit", "memchr", "mime", "multer", @@ -817,31 +817,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "axum" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" -dependencies = [ - "axum-core 0.5.5", - "bytes", - "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "itoa", - "matchit 0.8.4", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "serde_core", - "sync_wrapper", - "tower", - "tower-layer", - "tower-service", -] - [[package]] name = "axum-core" version = "0.4.5" @@ -863,24 +838,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "axum-core" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" -dependencies = [ - "bytes", - "futures-core", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "mime", - "pin-project-lite", - "sync_wrapper", - "tower-layer", - "tower-service", -] - [[package]] name = "axum-macros" version = "0.4.2" @@ -1259,46 +1216,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "console-api" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8599749b6667e2f0c910c1d0dff6901163ff698a52d5a39720f61b5be4b20d3" -dependencies = [ - "futures-core", - "prost", - "prost-types", - "tonic", - "tonic-prost", - "tracing-core", -] - -[[package]] -name = "console-subscriber" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4915b7d8dd960457a1b6c380114c2944f728e7c65294ab247ae6b6f1f37592" -dependencies = [ - "console-api", - "crossbeam-channel", - "crossbeam-utils", - "futures-task", - "hdrhistogram", - "humantime", - "hyper-util", - "prost", - "prost-types", - "serde", - "serde_json", - "thread_local", - "tokio", - "tokio-stream", - "tonic", - "tracing", - "tracing-core", - "tracing-subscriber", -] - [[package]] name = "const-oid" version = "0.9.6" @@ -1386,15 +1303,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -2223,19 +2131,6 @@ version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" -[[package]] -name = "hdrhistogram" -version = "7.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d" -dependencies = [ - "base64 0.21.7", - "byteorder", - "flate2", - "nom", - "num-traits", -] - [[package]] name = "heck" version = "0.5.0" @@ -2358,12 +2253,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "humantime" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" - [[package]] name = "hyper" version = "0.14.32" @@ -2445,19 +2334,6 @@ dependencies = [ "webpki-roots 1.0.3", ] -[[package]] -name = "hyper-timeout" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" -dependencies = [ - "hyper 1.7.0", - "hyper-util", - "pin-project-lite", - "tokio", - "tower-service", -] - [[package]] name = "hyper-tls" version = "0.6.0" @@ -3035,12 +2911,6 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" -[[package]] -name = "matchit" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" - [[package]] name = "matrixmultiply" version = "0.3.10" @@ -3583,26 +3453,6 @@ dependencies = [ "siphasher", ] -[[package]] -name = "pin-project" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.106", -] - [[package]] name = "pin-project-lite" version = "0.2.16" @@ -3746,38 +3596,6 @@ dependencies = [ "syn 2.0.106", ] -[[package]] -name = "prost" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" -dependencies = [ - "bytes", - "prost-derive", -] - -[[package]] -name = "prost-derive" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" -dependencies = [ - "anyhow", - "itertools 0.14.0", - "proc-macro2", - "quote", - "syn 2.0.106", -] - -[[package]] -name = "prost-types" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72" -dependencies = [ - "prost", -] - [[package]] name = "pxfm" version = "0.1.25" @@ -4724,10 +4542,9 @@ name = "standalone" version = "0.1.0" dependencies = [ "ast", - "axum 0.7.9", + "axum", "base64 0.21.7", "chrono", - "console-subscriber", "futures", "hex", "hmac", @@ -5148,17 +4965,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-stream" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-tungstenite" version = "0.24.0" @@ -5218,46 +5024,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "tonic" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" -dependencies = [ - "async-trait", - "axum 0.8.8", - "base64 0.22.1", - "bytes", - "h2 0.4.12", - "http 1.3.1", - "http-body 1.0.1", - "http-body-util", - "hyper 1.7.0", - "hyper-timeout", - "hyper-util", - "percent-encoding", - "pin-project", - "socket2 0.6.0", - "sync_wrapper", - "tokio", - "tokio-stream", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tonic-prost" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" -dependencies = [ - "bytes", - "prost", - "tonic", -] - [[package]] name = "tower" version = "0.5.2" @@ -5266,12 +5032,9 @@ checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", - "indexmap", "pin-project-lite", - "slab", "sync_wrapper", "tokio", - "tokio-util", "tower-layer", "tower-service", "tracing", diff --git a/ast/src/builder/core.rs b/ast/src/builder/core.rs index d95e8e009..44bed76da 100644 --- a/ast/src/builder/core.rs +++ b/ast/src/builder/core.rs @@ -49,7 +49,6 @@ impl Repo { self.build_graph_inner_with_streaming(streaming).await } - #[instrument(skip(self))] pub async fn build_graph_inner_with_streaming(&self, streaming: bool) -> Result { let graph_root = strip_tmp(&self.root).display().to_string(); let mut graph = G::new(graph_root, self.lang.kind.clone()); @@ -67,6 +66,7 @@ impl Repo { }; self.send_status_update("initialization", 1); + info!("Starting parse stage: initialization"); self.add_repository_and_language_nodes(&mut graph).await?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { @@ -76,9 +76,11 @@ impl Repo { .flush_stage(&ctx.neo, "repository_language", &bolt_nodes) .await?; } + let files = self.collect_and_add_directories(&mut graph)?; stats.insert("directories".to_string(), files.len()); + info!("Starting parse stage: files"); let filez = self.process_and_add_files(&mut graph, &files).await?; stats.insert("files".to_string(), filez.len()); self.send_status_with_stats(stats.clone()); @@ -103,6 +105,8 @@ impl Repo { .filter(|(f, _)| is_allowed_file(&std::path::PathBuf::from(f), &self.lang.kind)) .cloned() .collect::>(); + + info!("Starting parse stage: libraries"); self.process_libraries(&mut graph, &allowed_files)?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { @@ -116,6 +120,8 @@ impl Repo { .flush_edges_stage(&ctx.neo, "libraries", &edges) .await?; } + + info!("Starting parse stage: imports"); self.process_import_sections(&mut graph, &filez)?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { @@ -129,6 +135,8 @@ impl Repo { .flush_edges_stage(&ctx.neo, "imports", &edges) .await?; } + + info!("Starting parse stage: variables"); self.process_variables(&mut graph, &allowed_files)?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { @@ -142,6 +150,8 @@ impl Repo { .flush_edges_stage(&ctx.neo, "variables", &edges) .await?; } + + info!("Starting parse stage: classes"); let impl_relationships = self.process_classes(&mut graph, &allowed_files)?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { @@ -155,6 +165,8 @@ impl Repo { .flush_edges_stage(&ctx.neo, "classes", &edges) .await?; } + + info!("Starting parse stage: instances_traits"); self.process_instances_and_traits(&mut graph, &allowed_files)?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { @@ -168,6 +180,7 @@ impl Repo { .flush_edges_stage(&ctx.neo, "instances_traits", &edges) .await?; } + info!("Starting parse stage: implements"); self.resolve_implements_edges(&mut graph, impl_relationships)?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { @@ -181,6 +194,8 @@ impl Repo { .flush_edges_stage(&ctx.neo, "implements", &edges) .await?; } + + info!("Starting parse stage: data_models"); self.process_data_models(&mut graph, &allowed_files)?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { @@ -194,6 +209,8 @@ impl Repo { .flush_edges_stage(&ctx.neo, "data_models", &edges) .await?; } + + info!("Starting parse stage: functions_tests"); self.process_functions_and_tests(&mut graph, &allowed_files) .await?; #[cfg(feature = "neo4j")] @@ -208,6 +225,8 @@ impl Repo { .flush_edges_stage(&ctx.neo, "functions_tests", &edges) .await?; } + + info!("Starting parse stage: pages_templates"); self.process_pages_and_templates(&mut graph, &filez)?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { @@ -221,6 +240,8 @@ impl Repo { .flush_edges_stage(&ctx.neo, "pages_templates", &edges) .await?; } + + info!("Starting parse stage: endpoints"); self.process_endpoints(&mut graph, &allowed_files)?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { @@ -234,6 +255,8 @@ impl Repo { .flush_edges_stage(&ctx.neo, "endpoints", &edges) .await?; } + + info!("Starting parse stage: finalize"); self.finalize_graph(&mut graph, &allowed_files, &mut stats) .await?; #[cfg(feature = "neo4j")] diff --git a/ast/src/lang/call_finder.rs b/ast/src/lang/call_finder.rs index f6a50c123..a3f90832c 100644 --- a/ast/src/lang/call_finder.rs +++ b/ast/src/lang/call_finder.rs @@ -1,7 +1,6 @@ use super::parse::utils::trim_quotes; use super::queries::consts::{IMPORTS_ALIAS, IMPORTS_FROM, IMPORTS_NAME}; use super::{graphs::Graph, *}; -use tracing::instrument; use tree_sitter::QueryCursor; pub fn node_data_finder( @@ -24,7 +23,6 @@ pub fn node_data_finder( ) } -#[instrument(skip(graph), fields(func_name, current_file))] pub fn func_target_file_finder( func_name: &str, operand: &Option, @@ -34,6 +32,7 @@ pub fn func_target_file_finder( source_node_type: NodeType, import_names: Option)>>, ) -> Option { + let start_time = std::time::Instant::now(); log_cmd(format!( "func_target_file_finder {:?} from file {:?}", func_name, current_file @@ -80,19 +79,27 @@ pub fn func_target_file_finder( // Sixth try: Check if function is nested in a variable (e.g., authOptions.callbacks.signIn) if let Some(ref operand) = operand { if let Some(tf) = find_nested_function_in_variable(operand, func_name, graph, current_file) { + let duration = start_time.elapsed(); + if duration.as_millis() > 100 { + tracing::warn!("[PERF] func_target_file_finder for '{}' took {}ms (found via nested)", func_name, duration.as_millis()); + } return Some(tf); } } + let duration = start_time.elapsed(); + if duration.as_millis() > 100 { + tracing::warn!("[PERF] func_target_file_finder for '{}' took {}ms (not found)", func_name, duration.as_millis()); + } None } -#[instrument(skip(graph, lang), fields(current_file))] pub fn get_imports_for_file( current_file: &str, lang: &Lang, graph: &G, ) -> Option)>> { + let start_time = std::time::Instant::now(); let import_nodes = graph.find_nodes_by_file_ends_with(NodeType::Import, current_file); let import_node = import_nodes.first()?; let code = import_node.body.as_str(); @@ -149,6 +156,11 @@ pub fn get_imports_for_file( } } + let duration = start_time.elapsed(); + if duration.as_millis() > 50 { + tracing::warn!("[PERF] get_imports_for_file for '{}' took {}ms", current_file, duration.as_millis()); + } + if results.is_empty() { None } else { @@ -156,7 +168,6 @@ pub fn get_imports_for_file( } } -#[instrument(skip(graph), fields(func_name))] fn find_function_by_import( func_name: &str, import_names: Vec<(String, Vec)>, @@ -183,7 +194,6 @@ fn find_function_by_import( None } -#[instrument(skip(graph), fields(func_name, current_file))] fn find_only_one_function_file( func_name: &str, graph: &G, @@ -191,6 +201,7 @@ fn find_only_one_function_file( current_file: &str, source_node_type: NodeType, ) -> Option { + let start_time = std::time::Instant::now(); let mut target_files_starts = Vec::new(); let nodes = graph.find_nodes_by_name(NodeType::Function, func_name); if nodes.len() == 0 { @@ -215,12 +226,19 @@ fn find_only_one_function_file( target_files_starts.retain(|x| !x.file.contains("mock")); if target_files_starts.len() == 1 { log_cmd(format!("::: discluded mocks for!!! {:?}", func_name)); + let duration = start_time.elapsed(); + if duration.as_millis() > 50 { + tracing::warn!("[PERF] find_only_one_function_file for '{}' took {}ms", func_name, duration.as_millis()); + } return Some(target_files_starts[0].clone()); } + let duration = start_time.elapsed(); + if duration.as_millis() > 50 { + tracing::warn!("[PERF] find_only_one_function_file for '{}' took {}ms", func_name, duration.as_millis()); + } None } -#[instrument(skip(graph), fields(operand, func_name))] fn find_function_with_operand( operand: &str, func_name: &str, @@ -248,7 +266,6 @@ fn find_function_with_operand( target_file } -#[instrument(skip(graph), fields(var_name, func_name))] fn find_nested_function_in_variable( var_name: &str, func_name: &str, @@ -276,7 +293,6 @@ fn find_nested_function_in_variable( None } -#[instrument(skip(graph), fields(func_name, current_file))] fn find_function_in_same_file( func_name: &str, current_file: &str, @@ -302,7 +318,6 @@ fn find_function_in_same_file( None } -#[instrument(skip(graph), fields(func_name, current_file))] fn find_function_in_same_directory( func_name: &str, current_file: &str, diff --git a/ast/src/lang/linker.rs b/ast/src/lang/linker.rs index c0d47ce2d..91dbff38e 100644 --- a/ast/src/lang/linker.rs +++ b/ast/src/lang/linker.rs @@ -330,6 +330,7 @@ api.get(...), api.post(...), etc. (common API client pattern) fetch(..., { method: "POST" }) pattern with explicit method option */ +#[instrument] pub fn extract_http_verbs_from_test(body: &str) -> Vec { let mut verbs = Vec::new(); diff --git a/ast/src/lang/queries/react.rs b/ast/src/lang/queries/react.rs index 5e8727587..1b0655dd4 100644 --- a/ast/src/lang/queries/react.rs +++ b/ast/src/lang/queries/react.rs @@ -1030,7 +1030,6 @@ impl Stack for ReactTs { fn is_test(&self, _func_name: &str, func_file: &str, _func_body: &str) -> bool { if self.is_test_file(func_file) { - println!("Identified test file: {}", func_file); true } else { false diff --git a/ast/src/repo.rs b/ast/src/repo.rs index 3931ece7e..5ebc9937d 100644 --- a/ast/src/repo.rs +++ b/ast/src/repo.rs @@ -86,7 +86,6 @@ impl Repos { let streaming = std::env::var("STREAM_UPLOAD").is_ok(); self.build_graphs_inner_impl(streaming).await } - #[instrument(skip(self))] async fn build_graphs_inner_impl(&self, streaming: bool) -> Result { if self.0.is_empty() { return Err(Error::Custom("Language is not supported".into())); diff --git a/standalone/Cargo.toml b/standalone/Cargo.toml index 5beb83762..9a37cf15b 100644 --- a/standalone/Cargo.toml +++ b/standalone/Cargo.toml @@ -13,7 +13,7 @@ serde_json = "1.0.129" tokio = { version = "1", features = ["macros", "tracing", "rt-multi-thread"] } tracing = { version = "0.1.37" } tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } -console-subscriber = "0.5" + tower-http = { version = "0.5", features = ["fs", "cors", "timeout", "trace"] } axum = { version = "0.7", features = ["ws", "multipart", "macros"] } futures = "0.3.31" diff --git a/standalone/src/main.rs b/standalone/src/main.rs index 74914175c..3ac85c61b 100644 --- a/standalone/src/main.rs +++ b/standalone/src/main.rs @@ -34,7 +34,7 @@ use tracing_subscriber::{filter::LevelFilter, EnvFilter}; .with_env_filter(filter) .init(); - console_subscriber::init(); + // console_subscriber::init(); // Commented out due to Send safety issues let mut graph_ops = ast::lang::graphs::graph_ops::GraphOps::new(); if let Err(e) = graph_ops.check_connection().await { From f14a0763602df3430d00dccecb7f87178a9c3f65 Mon Sep 17 00:00:00 2001 From: kelmith Date: Thu, 25 Dec 2025 02:39:00 +0530 Subject: [PATCH 3/6] feat: flame graph for graph-update --- flamegraph.svg | 491 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 491 insertions(+) create mode 100644 flamegraph.svg diff --git a/flamegraph.svg b/flamegraph.svg new file mode 100644 index 000000000..d6f4ce2e9 --- /dev/null +++ b/flamegraph.svg @@ -0,0 +1,491 @@ +Flame Graph Reset ZoomSearch dyld4::JustInTimeLoader::runInitializers(dyld4::RuntimeState&) const (2 samples, 0.02%)dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const (2 samples, 0.02%)dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const (2 samples, 0.02%)dyld3::MachOFile::forEachInitializerPointerSection(Diagnostics&, void (unsigned int, unsigned int, bool&) block_pointer) const (2 samples, 0.02%)mach_o::Header::forEachSection(void (mach_o::Header::SectionInfo const&, bool&) block_pointer) const (2 samples, 0.02%)mach_o::Header::forEachLoadCommand(void (load_command const*, bool&) block_pointer) const (2 samples, 0.02%)invocation function for block in mach_o::Header::forEachSection(void (mach_o::Header::SectionInfo const&, bool&) block_pointer) const (2 samples, 0.02%)invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const (2 samples, 0.02%)invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const (2 samples, 0.02%)dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const (4 samples, 0.04%)dyld4::Loader::runInitializersBottomUpPlusUpwardLinks(dyld4::RuntimeState&) const::$_0::operator()() const (4 samples, 0.04%)dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&, dyld3::Array<dyld4::Loader const*>&) const (4 samples, 0.04%)dyld4::Loader::runInitializersBottomUp(dyld4::RuntimeState&, dyld3::Array<dyld4::Loader const*>&, dyld3::Array<dyld4::Loader const*>&) const (2 samples, 0.02%)dyld4::APIs::runAllInitializersForMain() (8 samples, 0.07%)dyld4::PrebuiltLoader::runInitializers(dyld4::RuntimeState&) const (4 samples, 0.04%)dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const (4 samples, 0.04%)dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const (4 samples, 0.04%)mach_o::Header::forEachSection(void (mach_o::Header::SectionInfo const&, bool&) block_pointer) const (4 samples, 0.04%)mach_o::Header::forEachLoadCommand(void (load_command const*, bool&) block_pointer) const (4 samples, 0.04%)invocation function for block in mach_o::Header::forEachSection(void (mach_o::Header::SectionInfo const&, bool&) block_pointer) const (4 samples, 0.04%)invocation function for block in dyld3::MachOAnalyzer::forEachInitializer(Diagnostics&, dyld3::MachOAnalyzer::VMAddrConverter const&, void (unsigned int) block_pointer, void const*) const (4 samples, 0.04%)invocation function for block in dyld4::Loader::findAndRunAllInitializers(dyld4::RuntimeState&) const (4 samples, 0.04%)libSystem_initializer (4 samples, 0.04%)libdispatch_init (2 samples, 0.02%)_os_object_init (2 samples, 0.02%)_objc_init (2 samples, 0.02%)_dyld_objc_register_callbacks (2 samples, 0.02%)dyld4::APIs::_dyld_objc_register_callbacks(dyld4::ObjCCallbacks const*) (2 samples, 0.02%)dyld4::RuntimeState::setObjCNotifiers(dyld4::ReadOnlyCallback<void (*)(char const*, mach_header const*)>, dyld4::ReadOnlyCallback<void (*)(mach_header const*, void*, mach_header const*, void const*)>, dyld4::ReadOnlyCallback<void (*)(_dyld_objc_notify_mapped_info const*)>, dyld4::ReadOnlyCallback<void (*)(unsigned int, _dyld_objc_notify_mapped_info const*, void (unsigned int) block_pointer)>) (2 samples, 0.02%)dyld4::RuntimeLocks::withLoadersReadLock(void () block_pointer) (2 samples, 0.02%)invocation function for block in dyld4::RuntimeState::setObjCNotifiers(dyld4::ReadOnlyCallback<void (*)(char const*, mach_header const*)>, dyld4::ReadOnlyCallback<void (*)(mach_header const*, void*, mach_header const*, void const*)>, dyld4::ReadOnlyCallback<void (*)(_dyld_objc_notify_mapped_info const*)>, dyld4::ReadOnlyCallback<void (*)(unsigned int, _dyld_objc_notify_mapped_info const*, void (unsigned int) block_pointer)>)::$_0::operator()() const (2 samples, 0.02%)map_images (2 samples, 0.02%)map_images_nolock (2 samples, 0.02%)dyld4::APIs::_dyld_lookup_section_info(mach_header const*, _dyld_section_location_info_s*, _dyld_section_location_kind) (2 samples, 0.02%)dyld4::JustInTimeLoader::parseSectionLocations(mach_o::Header const*, dyld4::SectionLocations&) (2 samples, 0.02%)dyld3::MachOAnalyzer::forEachRebase_Opcodes(Diagnostics&, dyld3::MachOLoaded::LinkEditInfo const&, mach_o::Header::SegmentInfo const*, void (char const*, dyld3::MachOLoaded::LinkEditInfo const&, mach_o::Header::SegmentInfo const*, bool, unsigned int, unsigned char, unsigned long long, dyld3::MachOAnalyzer::Rebase, bool&) block_pointer) const (3 samples, 0.03%)invocation function for block in dyld4::Loader::applyFixupsGeneric(Diagnostics&, dyld4::RuntimeState&, unsigned long long, dyld3::Array<void const*> const&, dyld3::Array<void const*> const&, bool, dyld3::Array<dyld4::Loader::MissingFlatLazySymbol> const&) const (3 samples, 0.03%)dyld4::Loader::applyFixupsGeneric(Diagnostics&, dyld4::RuntimeState&, unsigned long long, dyld3::Array<void const*> const&, dyld3::Array<void const*> const&, bool, dyld3::Array<dyld4::Loader::MissingFlatLazySymbol> const&) const (4 samples, 0.04%)dyld3::MachOAnalyzer::forEachRebaseLocation_Opcodes(Diagnostics&, void (unsigned long long, bool&) block_pointer) const (4 samples, 0.04%)dyld3::MachOFile::trieWalk(Diagnostics&, unsigned char const*, unsigned char const*, char const*) (2 samples, 0.02%)mach_o::Fixups::forEachBindTarget_ChainedFixups(Diagnostics&, void (mach_o::Fixups::BindTargetInfo const&, bool&) block_pointer) const (3 samples, 0.03%)dyld3::MachOFile::forEachChainedFixupTarget(Diagnostics&, dyld_chained_fixups_header const*, linkedit_data_command const*, void (int, char const*, unsigned long long, bool, bool&) block_pointer) (3 samples, 0.03%)invocation function for block in mach_o::Fixups::forEachBindTarget_ChainedFixups(Diagnostics&, void (mach_o::Fixups::BindTargetInfo const&, bool&) block_pointer) const (3 samples, 0.03%)invocation function for block in dyld4::Loader::forEachBindTarget(Diagnostics&, dyld4::RuntimeState&, void (unsigned int, unsigned int, dyld4::Loader::ResolvedSymbol const&) block_pointer, bool, void (dyld4::Loader::ResolvedSymbol const&, bool&) block_pointer, void (dyld4::Loader::ResolvedSymbol const&, bool&) block_pointer) const (3 samples, 0.03%)dyld4::Loader::resolveSymbol(Diagnostics&, dyld4::RuntimeState&, int, char const*, bool, bool, void (unsigned int, unsigned int, dyld4::Loader::ResolvedSymbol const&) block_pointer, bool) const (3 samples, 0.03%)dyld4::Loader::hasExportedSymbol(Diagnostics&, dyld4::RuntimeState&, char const*, dyld4::Loader::ExportedSymbolMode, dyld4::Loader::ResolverMode, dyld4::Loader::ResolvedSymbol*, dyld3::Array<dyld4::Loader const*>*) const (3 samples, 0.03%)dyld4::JustInTimeLoader::applyFixups(Diagnostics&, dyld4::RuntimeState&, dyld4::DyldCacheDataConstLazyScopedWriter&, bool, lsl::Vector<std::__1::pair<dyld4::Loader const*, char const*>>*) const (9 samples, 0.08%)dyld4::Loader::forEachBindTarget(Diagnostics&, dyld4::RuntimeState&, void (unsigned int, unsigned int, dyld4::Loader::ResolvedSymbol const&) block_pointer, bool, void (dyld4::Loader::ResolvedSymbol const&, bool&) block_pointer, void (dyld4::Loader::ResolvedSymbol const&, bool&) block_pointer) const (5 samples, 0.05%)dyld3::MachOAnalyzer::withVMLayout(Diagnostics&, void (mach_o::Layout const&) block_pointer) const (5 samples, 0.05%)invocation function for block in dyld4::Loader::forEachBindTarget(Diagnostics&, dyld4::RuntimeState&, void (unsigned int, unsigned int, dyld4::Loader::ResolvedSymbol const&) block_pointer, bool, void (dyld4::Loader::ResolvedSymbol const&, bool&) block_pointer, void (dyld4::Loader::ResolvedSymbol const&, bool&) block_pointer) const (5 samples, 0.05%)mach_o::Fixups::forEachBindTarget_Opcodes(Diagnostics&, bool, void (mach_o::Fixups::BindTargetInfo const&, bool&) block_pointer, void (mach_o::Fixups::BindTargetInfo const&, bool&) block_pointer) const (2 samples, 0.02%)mach_o::Fixups::forEachBindUnified_Opcodes(Diagnostics&, bool, void (unsigned long long, unsigned int, mach_o::Fixups::BindTargetInfo const&, bool&) block_pointer, void (unsigned long long, unsigned int, mach_o::Fixups::BindTargetInfo const&, bool&) block_pointer) const (2 samples, 0.02%)dyld4::prepare(dyld4::APIs&, mach_o::Header const*) (21 samples, 0.20%)start (25 samples, 0.23%)main (3 samples, 0.03%)std::rt::lang_start_internal (3 samples, 0.03%)std::rt::lang_start::_{{closure}} (3 samples, 0.03%)core::ops::function::FnOnce::call_once (3 samples, 0.03%)standalone::main (3 samples, 0.03%)tokio::runtime::scheduler::multi_thread::MultiThread::block_on (2 samples, 0.02%)tokio::runtime::context::blocking::BlockingRegionGuard::block_on (2 samples, 0.02%)tokio::runtime::park::CachedParkThread::block_on::_{{closure}} (2 samples, 0.02%)nw_path_libinfo_path_check (4 samples, 0.04%)<(&str,u16) as std::net::socket_addr::ToSocketAddrs>::to_socket_addrs (6 samples, 0.06%)std::net::socket_addr::lookup_host (6 samples, 0.06%)std::sys::net::connection::socket::lookup_host::_{{closure}} (6 samples, 0.06%)getaddrinfo (6 samples, 0.06%)si_addrinfo (6 samples, 0.06%)search_addrinfo (2 samples, 0.02%)std::time::Instant::elapsed (2 samples, 0.02%)std::sys::pal::unix::time::Timespec::now (2 samples, 0.02%)clock_gettime (2 samples, 0.02%)parking_lot::condvar::Condvar::wait_until_internal (2 samples, 0.02%)std::sys::pal::unix::time::Timespec::now (4 samples, 0.04%)clock_gettime (4 samples, 0.04%)clock_gettime_nsec_np (2 samples, 0.02%)mio::poll::Poll::poll (22 samples, 0.21%)kevent (20 samples, 0.19%)tokio::runtime::io::driver::Driver::turn (30 samples, 0.28%)tokio::runtime::io::scheduled_io::ScheduledIo::wake (6 samples, 0.06%)tokio::runtime::task::waker::wake_by_val (5 samples, 0.05%)tokio::runtime::scheduler::multi_thread::handle::_<impl tokio::runtime::task::Schedule for alloc::sync::Arc<tokio::runtime::scheduler::multi_thread::handle::Handle>>::schedule (3 samples, 0.03%)tokio::runtime::context::with_scheduler (2 samples, 0.02%)tokio::runtime::scheduler::multi_thread::worker::Context::park_timeout (44 samples, 0.41%)tokio::runtime::scheduler::multi_thread::park::Parker::park (43 samples, 0.40%)tokio::runtime::time::Driver::park_internal (39 samples, 0.36%)tokio::runtime::time::wheel::Wheel::next_expiration (2 samples, 0.02%)0x100f3decf (2 samples, 0.02%)<axum::serve::Serve<M,S> as core::future::into_future::IntoFuture>::into_future::_{{closure}}::_{{closure}} (2 samples, 0.02%)<hyper::proto::h1::dispatch::Dispatcher<D,Bs,I,T> as core::future::future::Future>::poll (2 samples, 0.02%)<hyper_util::service::glue::TowerToHyperServiceFuture<S,R> as core::future::future::Future>::poll (2 samples, 0.02%)<hyper_util::service::oneshot::Oneshot<S,Req> as core::future::future::Future>::poll (2 samples, 0.02%)<axum::routing::route::RouteFuture<E> as core::future::future::Future>::poll (2 samples, 0.02%)<core::pin::Pin<P> as core::future::future::Future>::poll (2 samples, 0.02%)<futures_util::future::future::Map<Fut,F> as core::future::future::Future>::poll (2 samples, 0.02%)<futures_util::future::future::Map<Fut,F> as core::future::future::Future>::poll (2 samples, 0.02%)<tower_http::trace::future::ResponseFuture<Fut,C,OnResponseT,OnBodyChunkT,OnEosT,OnFailureT> as core::future::future::Future>::poll (2 samples, 0.02%)<axum::routing::route::RouteFuture<E> as core::future::future::Future>::poll (2 samples, 0.02%)<core::pin::Pin<P> as core::future::future::Future>::poll (2 samples, 0.02%)<futures_util::future::future::Map<Fut,F> as core::future::future::Future>::poll (2 samples, 0.02%)<futures_util::future::future::Map<Fut,F> as core::future::future::Future>::poll (2 samples, 0.02%)<F as futures_core::future::TryFuture>::try_poll (2 samples, 0.02%)<axum::routing::route::RouteFuture<E> as core::future::future::Future>::poll (2 samples, 0.02%)<core::pin::Pin<P> as core::future::future::Future>::poll (2 samples, 0.02%)<futures_util::future::future::Map<Fut,F> as core::future::future::Future>::poll (2 samples, 0.02%)<core::pin::Pin<P> as core::future::future::Future>::poll (2 samples, 0.02%)<F as axum::handler::Handler<(M,T1,T2),S>>::call::_{{closure}} (2 samples, 0.02%)ast::builder::core::_<impl ast::repo::Repo>::add_repository_and_language_nodes::_{{closure}} (7 samples, 0.07%)lsp::git::get_commit_hash::_{{closure}} (6 samples, 0.06%)lsp::utils::run_res_in_dir::_{{closure}} (6 samples, 0.06%)async_process::Command::output (6 samples, 0.06%)async_process::Child::new (6 samples, 0.06%)std::process::Command::spawn (6 samples, 0.06%)std::sys::process::unix::unix::_<impl std::sys::process::unix::common::Command>::spawn (6 samples, 0.06%)posix_spawnp (5 samples, 0.05%)posix_spawn (5 samples, 0.05%)__posix_spawn (5 samples, 0.05%)<ast::lang::graphs::btreemap_graph::BTreeMapGraph as ast::lang::graphs::graph::Graph>::get_all_nodes (5 samples, 0.05%)<alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter (5 samples, 0.05%)<ast::lang::asg::NodeData as core::clone::Clone>::clone (4 samples, 0.04%)<alloc::string::String as core::clone::Clone>::clone (4 samples, 0.04%)_platform_memmove (4 samples, 0.04%)<walkdir::IntoIter as core::iter::traits::iterator::Iterator>::next (2 samples, 0.02%)walkdir::IntoIter::handle_entry (2 samples, 0.02%)walkdir::IntoIter::push (2 samples, 0.02%)std::sys::fs::read_dir (2 samples, 0.02%)__opendir2 (2 samples, 0.02%)open$NOCANCEL (2 samples, 0.02%)__open_nocancel (2 samples, 0.02%)ignore::dir::create_gitignore (2 samples, 0.02%)ignore::gitignore::GitignoreBuilder::build (2 samples, 0.02%)ignore::dir::Ignore::add_child (3 samples, 0.03%)ignore::dir::Ignore::add_child_path (3 samples, 0.03%)ast::repo::Repo::collect_all_files (8 samples, 0.07%)ignore::walk::WalkBuilder::build (2 samples, 0.02%)ignore::dir::IgnoreBuilder::build (2 samples, 0.02%)ignore::gitignore::GitignoreBuilder::build_global (2 samples, 0.02%)ast::builder::core::_<impl ast::repo::Repo>::collect_and_add_directories (10 samples, 0.09%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (4 samples, 0.04%)tree_sitter::Query::new (4 samples, 0.04%)ts_query_new (4 samples, 0.04%)<ast::lang::queries::react::ReactTs as ast::lang::queries::Stack>::q (39 samples, 0.36%)tree_sitter::Query::new (39 samples, 0.36%)ts_query_new (39 samples, 0.36%)ast::lang::parse::collect::_<impl ast::lang::Lang>::collect_classes (6 samples, 0.06%)<ast::lang::queries::ruby::Ruby as ast::lang::queries::Stack>::parse (5 samples, 0.05%)ts_parser_parse_with_options (4 samples, 0.04%)ts_parser_parse (4 samples, 0.04%)ts_lex (2 samples, 0.02%)ast::builder::core::_<impl ast::repo::Repo>::process_classes (51 samples, 0.48%)streaming_iterator::StreamingIterator::next (2 samples, 0.02%)<tree_sitter::QueryMatches<T,I> as streaming_iterator::StreamingIterator>::advance (2 samples, 0.02%)ts_query_cursor_next_match (2 samples, 0.02%)ts_query_cursor__advance (2 samples, 0.02%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (4 samples, 0.04%)tree_sitter::Query::new (4 samples, 0.04%)ts_query_new (4 samples, 0.04%)ts_calloc_default (2 samples, 0.02%)_xzm_malloc_large_huge (2 samples, 0.02%)xzm_segment_group_alloc_chunk (2 samples, 0.02%)__bzero (2 samples, 0.02%)analysis_state_set__insert_sorted (8 samples, 0.07%)ts_query__perform_analysis (65 samples, 0.61%)<ast::lang::queries::react::ReactTs as ast::lang::queries::Stack>::q (107 samples, 1.00%)tree_sitter::Query::new (107 samples, 1.00%)ts_query_new (107 samples, 1.00%)ast::lang::Lang::get_query_opt (115 samples, 1.07%)ast::lang::parse::collect::_<impl ast::lang::Lang>::collect (4 samples, 0.04%)<ast::lang::queries::ruby::Ruby as ast::lang::queries::Stack>::parse (3 samples, 0.03%)ts_parser_parse_with_options (3 samples, 0.03%)ts_parser_parse (3 samples, 0.03%)ts_parser__do_all_potential_reductions (2 samples, 0.02%)ast::builder::core::_<impl ast::repo::Repo>::process_data_models (117 samples, 1.09%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (12 samples, 0.11%)tree_sitter::Query::new (12 samples, 0.11%)ts_query_new (12 samples, 0.11%)ts_query__perform_analysis (9 samples, 0.08%)analysis_state_set__insert_sorted (3 samples, 0.03%)ast::lang::Lang::get_query_opt (14 samples, 0.13%)ast::lang::parse::collect::_<impl ast::lang::Lang>::collect (2 samples, 0.02%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::parse (3 samples, 0.03%)ts_parser_parse_with_options (3 samples, 0.03%)ts_parser_parse (3 samples, 0.03%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (15 samples, 0.14%)tree_sitter::Query::new (15 samples, 0.14%)ts_query_new (14 samples, 0.13%)ts_query__perform_analysis (11 samples, 0.10%)regex_automata::nfa::thompson::nfa::Inner::add (2 samples, 0.02%)regex_automata::meta::strategy::new (5 samples, 0.05%)regex_automata::nfa::thompson::compiler::Compiler::compile (3 samples, 0.03%)regex_automata::nfa::thompson::builder::Builder::build (3 samples, 0.03%)regex_syntax::ast::parse::Parser::parse (3 samples, 0.03%)regex_syntax::ast::parse::ParserI<P>::parse_with_comments (3 samples, 0.03%)regex_syntax::ast::parse::ParserI<P>::push_alternate (2 samples, 0.02%)tree_sitter::Query::from_raw_parts (10 samples, 0.09%)regex::regex::bytes::Regex::new (10 samples, 0.09%)regex::builders::bytes::RegexBuilder::build (10 samples, 0.09%)regex_automata::meta::regex::Builder::build (10 samples, 0.09%)regex_syntax::hir::translate::Translator::translate (2 samples, 0.02%)regex_syntax::ast::visitor::visit (2 samples, 0.02%)<regex_syntax::hir::translate::TranslatorI as regex_syntax::ast::visitor::Visitor>::visit_post (2 samples, 0.02%)query_analysis__delete (2 samples, 0.02%)_xzm_free (2 samples, 0.02%)ts_malloc_default (2 samples, 0.02%)ts_query__perform_analysis (93 samples, 0.87%)analysis_state_set__insert_sorted (8 samples, 0.07%)_malloc_zone_realloc (3 samples, 0.03%)xzm_realloc (3 samples, 0.03%)<ast::lang::queries::react::ReactTs as ast::lang::queries::Stack>::q (162 samples, 1.51%)tree_sitter::Query::new (162 samples, 1.51%)ts_query_new (152 samples, 1.42%)ts_realloc_default (5 samples, 0.05%)_realloc (4 samples, 0.04%)<ast::lang::queries::ruby::Ruby as ast::lang::queries::Stack>::parse (6 samples, 0.06%)ts_parser_parse_with_options (6 samples, 0.06%)ts_parser_parse (6 samples, 0.06%)ast::lang::parse::collect::_<impl ast::lang::Lang>::collect_endpoints (189 samples, 1.76%)ast::lang::parse::format::_<impl ast::lang::Lang>::format_endpoint (3 samples, 0.03%)ast::lang::call_finder::get_imports_for_file (3 samples, 0.03%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (3 samples, 0.03%)tree_sitter::Query::new (3 samples, 0.03%)ts_query_new (3 samples, 0.03%)streaming_iterator::StreamingIterator::next (2 samples, 0.02%)<tree_sitter::QueryMatches<T,I> as streaming_iterator::StreamingIterator>::advance (2 samples, 0.02%)ts_query_cursor_next_match (2 samples, 0.02%)ts_query_cursor__advance (2 samples, 0.02%)ast::builder::core::_<impl ast::repo::Repo>::process_endpoints (208 samples, 1.94%)a..<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (8 samples, 0.07%)tree_sitter::Query::new (8 samples, 0.07%)ts_query_new (8 samples, 0.07%)ts_calloc_default (2 samples, 0.02%)_xzm_malloc_large_huge (2 samples, 0.02%)xzm_segment_group_alloc_chunk (2 samples, 0.02%)__bzero (2 samples, 0.02%)ts_query__perform_analysis (10 samples, 0.09%)_malloc_zone_realloc (2 samples, 0.02%)<ast::lang::queries::react::ReactTs as ast::lang::queries::Stack>::q (61 samples, 0.57%)tree_sitter::Query::new (61 samples, 0.57%)ts_query_new (60 samples, 0.56%)ts_realloc_default (4 samples, 0.04%)_realloc (4 samples, 0.04%)_platform_memmove (2 samples, 0.02%)ts_malloc_default (2 samples, 0.02%)stack__iter (24 samples, 0.22%)summarize_stack_callback (9 samples, 0.08%)stack_node_release (4 samples, 0.04%)ts_subtree_release (4 samples, 0.04%)_xzm_free (4 samples, 0.04%)stack_node_release (6 samples, 0.06%)summarize_stack_callback (2 samples, 0.02%)ts_lex (21 samples, 0.20%)ts_lexer__do_advance (3 samples, 0.03%)ts_decode_utf8 (2 samples, 0.02%)ts_lex_keywords (4 samples, 0.04%)ts_lexer_start (2 samples, 0.02%)ts_parser__breakdown_top_of_stack (3 samples, 0.03%)stack__iter (3 samples, 0.03%)ts_parser__can_reuse_first_leaf (2 samples, 0.02%)_platform_memmove (2 samples, 0.02%)stack__iter (11 samples, 0.10%)ts_malloc_default (3 samples, 0.03%)stack_node_add_link (2 samples, 0.02%)ts_language_next_state (6 samples, 0.06%)ts_subtree_array_remove_trailing_extras (2 samples, 0.02%)ts_realloc_default (3 samples, 0.03%)_realloc (3 samples, 0.03%)_malloc_zone_realloc (3 samples, 0.03%)xzm_realloc (3 samples, 0.03%)ts_parser__reduce (38 samples, 0.35%)ts_subtree_new_node (10 samples, 0.09%)ts_subtree_summarize_children (6 samples, 0.06%)ts_parser__do_all_potential_reductions (333 samples, 3.11%)ts_..ts_stack_renumber_version (2 samples, 0.02%)stack_node_release (2 samples, 0.02%)_platform_memmove (2 samples, 0.02%)stack__iter (16 samples, 0.15%)ts_malloc_default (3 samples, 0.03%)ts_realloc_default (2 samples, 0.02%)_realloc (2 samples, 0.02%)_malloc_zone_realloc (2 samples, 0.02%)xzm_realloc (2 samples, 0.02%)ts_stack_pop_error (2 samples, 0.02%)ts_parser__recover (30 samples, 0.28%)ts_subtree_summarize_children (2 samples, 0.02%)_platform_memmove (3 samples, 0.03%)stack__iter (9 samples, 0.08%)ts_malloc_default (3 samples, 0.03%)ts_language_next_state (5 samples, 0.05%)ts_parser__reduce (22 samples, 0.21%)ts_subtree_new_node (4 samples, 0.04%)stack_node_add_link (2 samples, 0.02%)ts_stack_merge (3 samples, 0.03%)ts_stack_push (3 samples, 0.03%)ts_stack_remove_version (2 samples, 0.02%)stack_node_release (2 samples, 0.02%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::parse (695 samples, 6.48%)<ast::la..ts_parser_parse_with_options (695 samples, 6.48%)ts_parse..ts_parser_parse (695 samples, 6.48%)ts_parse..ts_stack_renumber_version (4 samples, 0.04%)stack_node_release (3 samples, 0.03%)ts_subtree_release (2 samples, 0.02%)scan_closing_comment (2 samples, 0.02%)stack__iter (9 samples, 0.08%)summarize_stack_callback (3 samples, 0.03%)ts_realloc_default (3 samples, 0.03%)_realloc (3 samples, 0.03%)_malloc_zone_realloc (3 samples, 0.03%)xzm_realloc (3 samples, 0.03%)_xzm_xzone_malloc_tiny (2 samples, 0.02%)stack_node_release (2 samples, 0.02%)ts_subtree_release (2 samples, 0.02%)stack_node_release (5 samples, 0.05%)ts_lexer__do_advance (6 samples, 0.06%)ts_lex (22 samples, 0.21%)ts_lex_keywords (4 samples, 0.04%)ts_lexer__do_advance (2 samples, 0.02%)ts_parser__breakdown_top_of_stack (2 samples, 0.02%)stack__iter (2 samples, 0.02%)_malloc_zone_malloc (2 samples, 0.02%)_xzm_xzone_thread_cache_fill_and_malloc (2 samples, 0.02%)stack__iter (13 samples, 0.12%)ts_malloc_default (8 samples, 0.07%)ts_parser__reduce (28 samples, 0.26%)ts_subtree_new_node (5 samples, 0.05%)ts_subtree_summarize_children (4 samples, 0.04%)ts_parser__do_all_potential_reductions (509 samples, 4.75%)ts_par.._platform_memmove (3 samples, 0.03%)_xzm_xzone_malloc (3 samples, 0.03%)ts_calloc_default (7 samples, 0.07%)_xzm_xzone_thread_cache_fill_and_malloc (2 samples, 0.02%)stack__iter (14 samples, 0.13%)ts_malloc_default (2 samples, 0.02%)ts_realloc_default (2 samples, 0.02%)_realloc (2 samples, 0.02%)ts_subtree_release (2 samples, 0.02%)ts_parser__recover (40 samples, 0.37%)_malloc_zone_malloc (2 samples, 0.02%)_xzm_xzone_malloc (3 samples, 0.03%)_xzm_xzone_malloc_freelist_outlined (2 samples, 0.02%)stack__iter (20 samples, 0.19%)ts_malloc_default (11 samples, 0.10%)_xzm_xzone_thread_cache_fill_and_malloc (4 samples, 0.04%)ts_stack_push (6 samples, 0.06%)ts_subtree_array_remove_trailing_extras (3 samples, 0.03%)ts_parser__reduce (41 samples, 0.38%)ts_subtree_new_node (6 samples, 0.06%)ts_subtree_summarize_children (6 samples, 0.06%)ts_stack_merge (2 samples, 0.02%)ts_stack_remove_version (2 samples, 0.02%)ts_stack_remove_version (5 samples, 0.05%)stack_node_release (5 samples, 0.05%)ts_subtree_release (5 samples, 0.05%)_xzm_free (3 samples, 0.03%)ts_stack_renumber_version (4 samples, 0.04%)stack_node_release (2 samples, 0.02%)ts_subtree_compress (3 samples, 0.03%)ts_parser_parse (984 samples, 9.18%)ts_parser_par..ts_subtree_new_leaf (2 samples, 0.02%)<ast::lang::queries::ruby::Ruby as ast::lang::queries::Stack>::parse (985 samples, 9.19%)<ast::lang::q..ts_parser_parse_with_options (985 samples, 9.19%)ts_parser_par..ts_query__pattern_map_search (3 samples, 0.03%)ts_tree_cursor_current_status (4 samples, 0.04%)ts_tree_cursor_goto_first_child_internal (2 samples, 0.02%)<tree_sitter::QueryMatches<T,I> as streaming_iterator::StreamingIterator>::advance (22 samples, 0.21%)ts_query_cursor_next_match (22 samples, 0.21%)ts_query_cursor__advance (22 samples, 0.21%)ts_tree_cursor_goto_sibling_internal (5 samples, 0.05%)ts_tree_cursor_child_iterator_next (4 samples, 0.04%)ast::builder::core::_<impl ast::repo::Repo>::process_import_sections (1,776 samples, 16.56%)ast::builder::core::_<impl..ast::lang::Lang::get_imports (1,776 samples, 16.56%)ast::lang::Lang::get_impor..ast::lang::parse::collect::_<impl ast::lang::Lang>::collect (1,707 samples, 15.92%)ast::lang::parse::collec..ts_tree_delete (5 samples, 0.05%)ts_subtree_release (4 samples, 0.04%)_xzm_free (3 samples, 0.03%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (4 samples, 0.04%)tree_sitter::Query::new (4 samples, 0.04%)ts_query_new (4 samples, 0.04%)ast::lang::Lang::get_query_opt (6 samples, 0.06%)ast::lang::parse::collect::_<impl ast::lang::Lang>::collect (2 samples, 0.02%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::parse (2 samples, 0.02%)ts_parser_parse_with_options (2 samples, 0.02%)ts_parser_parse (2 samples, 0.02%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (4 samples, 0.04%)tree_sitter::Query::new (4 samples, 0.04%)ts_query_new (4 samples, 0.04%)ast::builder::core::_<impl ast::repo::Repo>::process_instances_and_traits (11 samples, 0.10%)ast::lang::Lang::get_traits (5 samples, 0.05%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (8 samples, 0.07%)tree_sitter::Query::new (8 samples, 0.07%)ts_query_new (8 samples, 0.07%)ts_query__perform_analysis (2 samples, 0.02%)<ast::lang::queries::react::ReactTs as ast::lang::queries::Stack>::q (9 samples, 0.08%)tree_sitter::Query::new (9 samples, 0.08%)ts_query_new (9 samples, 0.08%)ts_query__perform_analysis (3 samples, 0.03%)ast::builder::core::_<impl ast::repo::Repo>::process_libraries (20 samples, 0.19%)ast::lang::Lang::get_libs (18 samples, 0.17%)ts_query__perform_analysis (71 samples, 0.66%)analysis_state_set__insert_sorted (3 samples, 0.03%)ast::lang::Lang::get_pages (132 samples, 1.23%)<ast::lang::queries::react::ReactTs as ast::lang::queries::Stack>::q (132 samples, 1.23%)tree_sitter::Query::new (132 samples, 1.23%)ts_query_new (131 samples, 1.22%)stack__iter (8 samples, 0.07%)summarize_stack_callback (4 samples, 0.04%)stack_node_release (4 samples, 0.04%)ts_subtree_release (3 samples, 0.03%)_xzm_free (2 samples, 0.02%)ts_lexer__advance (2 samples, 0.02%)ts_lexer__do_advance (7 samples, 0.07%)ts_lex (18 samples, 0.17%)ts_lex_keywords (2 samples, 0.02%)ts_lexer_start (2 samples, 0.02%)pop_pending_callback (2 samples, 0.02%)ts_parser__breakdown_top_of_stack (4 samples, 0.04%)stack__iter (4 samples, 0.04%)ts_malloc_default (2 samples, 0.02%)_xzm_xzone_malloc_tiny (2 samples, 0.02%)pop_count_callback (2 samples, 0.02%)stack__iter (9 samples, 0.08%)ts_malloc_default (4 samples, 0.04%)ts_stack_push (2 samples, 0.02%)ts_realloc_default (2 samples, 0.02%)ts_parser__do_all_potential_reductions (514 samples, 4.79%)ts_par..ts_parser__reduce (20 samples, 0.19%)ts_subtree_new_node (6 samples, 0.06%)ts_subtree_summarize_children (3 samples, 0.03%)_xzm_free (2 samples, 0.02%)ts_calloc_default (5 samples, 0.05%)_xzm_xzone_malloc_tiny (3 samples, 0.03%)stack__iter (9 samples, 0.08%)ts_parser__better_version_exists (3 samples, 0.03%)_malloc_zone_realloc (2 samples, 0.02%)ts_realloc_default (4 samples, 0.04%)_realloc (4 samples, 0.04%)xzm_malloc_zone_size (2 samples, 0.02%)ts_stack_pop_error (2 samples, 0.02%)ts_stack_push (2 samples, 0.02%)ts_parser__recover (36 samples, 0.34%)ts_subtree_summarize_children (4 samples, 0.04%)_xzm_xzone_malloc (4 samples, 0.04%)stack__iter (12 samples, 0.11%)ts_malloc_default (9 samples, 0.08%)_xzm_xzone_thread_cache_fill_and_malloc (5 samples, 0.05%)ts_stack_push (2 samples, 0.02%)ts_parser__reduce (31 samples, 0.29%)ts_subtree_new_node (8 samples, 0.07%)ts_subtree_summarize_children (7 samples, 0.07%)ts_stack_merge (2 samples, 0.02%)stack_node_add_link (2 samples, 0.02%)ts_stack_push (3 samples, 0.03%)_xzm_free (2 samples, 0.02%)ts_stack_remove_version (8 samples, 0.07%)stack_node_release (8 samples, 0.07%)ts_subtree_release (6 samples, 0.06%)ts_stack_renumber_version (4 samples, 0.04%)stack_node_release (4 samples, 0.04%)ts_subtree_release (2 samples, 0.02%)ts_subtree_compress (3 samples, 0.03%)ts_subtree_summarize_children (2 samples, 0.02%)ts_subtree_new_leaf (2 samples, 0.02%)ts_parser_parse (946 samples, 8.82%)ts_parser_pa..ast::lang::parse::collect::_<impl ast::lang::Lang>::collect_pages (947 samples, 8.83%)ast::lang::p..<ast::lang::queries::ruby::Ruby as ast::lang::queries::Stack>::parse (947 samples, 8.83%)<ast::lang::..ts_parser_parse_with_options (947 samples, 8.83%)ts_parser_pa..core::ptr::drop_in_place<tree_sitter::Tree> (3 samples, 0.03%)ts_tree_delete (3 samples, 0.03%)ts_subtree_release (3 samples, 0.03%)ts_tree_cursor_current_status (4 samples, 0.04%)ts_tree_cursor_goto_first_child_internal (2 samples, 0.02%)ast::builder::core::_<impl ast::repo::Repo>::process_pages_and_templates (1,096 samples, 10.22%)ast::builder::c..streaming_iterator::StreamingIterator::next (14 samples, 0.13%)<tree_sitter::QueryMatches<T,I> as streaming_iterator::StreamingIterator>::advance (14 samples, 0.13%)ts_query_cursor_next_match (14 samples, 0.13%)ts_query_cursor__advance (14 samples, 0.13%)ts_tree_cursor_goto_sibling_internal (4 samples, 0.04%)ts_tree_cursor_child_iterator_next (2 samples, 0.02%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (5 samples, 0.05%)tree_sitter::Query::new (5 samples, 0.05%)ts_query_new (5 samples, 0.05%)ts_query__perform_analysis (4 samples, 0.04%)ts_query__perform_analysis (35 samples, 0.33%)analysis_state_set__insert_sorted (3 samples, 0.03%)<ast::lang::queries::react::ReactTs as ast::lang::queries::Stack>::q (75 samples, 0.70%)tree_sitter::Query::new (75 samples, 0.70%)ts_query_new (75 samples, 0.70%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::parse (2 samples, 0.02%)ts_parser_parse_with_options (2 samples, 0.02%)ts_parser_parse (2 samples, 0.02%)ast::builder::core::_<impl ast::repo::Repo>::process_variables (87 samples, 0.81%)ast::lang::Lang::get_vars (87 samples, 0.81%)ast::lang::parse::collect::_<impl ast::lang::Lang>::collect (7 samples, 0.07%)<ast::lang::queries::ruby::Ruby as ast::lang::queries::Stack>::parse (5 samples, 0.05%)ts_parser_parse_with_options (5 samples, 0.05%)ts_parser_parse (5 samples, 0.05%)<core::pin::Pin<P> as core::future::future::Future>::poll (2 samples, 0.02%)<neo4rs::pool::ConnectionManager as deadpool::managed::Manager>::recycle::_{{closure}} (2 samples, 0.02%)neo4rs::connection::Connection::send_recv::_{{closure}} (2 samples, 0.02%)<hashbrown::raw::RawTable<T,A> as hashbrown::raw::RawTableClone>::clone_from_spec (2 samples, 0.02%)hashbrown::raw::RawTable<T,A>::clone_from_impl (2 samples, 0.02%)<neo4rs::types::list::BoltList as core::clone::Clone>::clone (4 samples, 0.04%)<std::collections::hash::map::HashMap<K,V,S> as core::clone::Clone>::clone (4 samples, 0.04%)neo4rs::query::Query::try_request::_{{closure}} (4 samples, 0.04%)neo4rs::connection::Connection::send_recv::_{{closure}} (4 samples, 0.04%)<tokio::io::util::buf_writer::BufWriter<W> as tokio::io::async_write::AsyncWrite>::poll_flush (2 samples, 0.02%)tokio::io::util::buf_writer::BufWriter<W>::flush_buf (2 samples, 0.02%)tokio::io::poll_evented::PollEvented<E>::poll_write (2 samples, 0.02%)<&mio::net::tcp::stream::TcpStream as std::io::Write>::write (2 samples, 0.02%)<&std::net::tcp::TcpStream as std::io::Write>::write (2 samples, 0.02%)__sendto (2 samples, 0.02%)neo4rs::query::Query::try_run::_{{closure}} (2 samples, 0.02%)<tokio::io::util::buf_writer::BufWriter<W> as tokio::io::async_write::AsyncWrite>::poll_flush (2 samples, 0.02%)tokio::io::util::buf_writer::BufWriter<W>::flush_buf (2 samples, 0.02%)tokio::io::poll_evented::PollEvented<E>::poll_write (2 samples, 0.02%)neo4rs::txn::Txn::commit::_{{closure}} (3 samples, 0.03%)neo4rs::connection::Connection::send_recv::_{{closure}} (3 samples, 0.03%)ast::lang::graphs::neo4j::executor::TransactionManager::execute::_{{closure}} (20 samples, 0.19%)neo4rs::txn::Txn::new::_{{closure}} (4 samples, 0.04%)neo4rs::connection::Connection::send_recv::_{{closure}} (3 samples, 0.03%)<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_read::AsyncRead>::poll_read (3 samples, 0.03%)<tokio::io::util::buf_writer::BufWriter<W> as tokio::io::async_read::AsyncRead>::poll_read (3 samples, 0.03%)tokio::io::poll_evented::PollEvented<E>::poll_read (3 samples, 0.03%)<&mio::net::tcp::stream::TcpStream as std::io::Read>::read (3 samples, 0.03%)<&std::net::tcp::TcpStream as std::io::Read>::read (3 samples, 0.03%)__recvfrom (3 samples, 0.03%)ast::lang::graphs::neo4j::executor::execute_queries_simple::_{{closure}} (23 samples, 0.21%)std::io::stdio::_print (2 samples, 0.02%)<&std::io::stdio::Stdout as std::io::Write>::write_fmt (2 samples, 0.02%)core::fmt::write (2 samples, 0.02%)<std::io::default_write_fmt::Adapter<T> as core::fmt::Write>::write_str (2 samples, 0.02%)<std::io::stdio::StdoutLock as std::io::Write>::write_all (2 samples, 0.02%)std::io::buffered::bufwriter::BufWriter<W>::flush_buf (2 samples, 0.02%)write (2 samples, 0.02%)ast::builder::streaming::GraphStreamingUploader::flush_edges_stage::_{{closure}} (24 samples, 0.22%)<std::collections::hash::map::HashMap<K,V,S> as core::clone::Clone>::clone (4 samples, 0.04%)<hashbrown::raw::RawTable<T,A> as hashbrown::raw::RawTableClone>::clone_from_spec (4 samples, 0.04%)hashbrown::raw::RawTable<T,A>::clone_from_impl (4 samples, 0.04%)<neo4rs::types::string::BoltString as core::clone::Clone>::clone (3 samples, 0.03%)<alloc::string::String as core::clone::Clone>::clone (3 samples, 0.03%)_platform_memmove (3 samples, 0.03%)<T as core::convert::Into<U>>::into (2 samples, 0.02%)neo4rs::messages::BoltRequest::into_bytes (2 samples, 0.02%)<core::pin::Pin<P> as core::future::future::Future>::poll (5 samples, 0.05%)<neo4rs::pool::ConnectionManager as deadpool::managed::Manager>::recycle::_{{closure}} (5 samples, 0.05%)neo4rs::connection::Connection::send_recv::_{{closure}} (5 samples, 0.05%)tokio::io::util::buf_writer::BufWriter<W>::flush_buf (2 samples, 0.02%)tokio::io::poll_evented::PollEvented<E>::poll_write (2 samples, 0.02%)<&mio::net::tcp::stream::TcpStream as std::io::Write>::write (2 samples, 0.02%)<&std::net::tcp::TcpStream as std::io::Write>::write (2 samples, 0.02%)__sendto (2 samples, 0.02%)core::fmt::Formatter::write_formatted_parts (3 samples, 0.03%)<alloc::string::String as core::fmt::Write>::write_str (3 samples, 0.03%)alloc::raw_vec::RawVecInner<A>::reserve::do_reserve_and_handle (3 samples, 0.03%)alloc::raw_vec::RawVecInner<A>::finish_grow (2 samples, 0.02%)_realloc (2 samples, 0.02%)_malloc_zone_realloc (2 samples, 0.02%)xzm_realloc (2 samples, 0.02%)_xzm_xzone_malloc_tiny (2 samples, 0.02%)alloc::fmt::format::_{{closure}} (4 samples, 0.04%)alloc::fmt::format::format_inner (4 samples, 0.04%)core::fmt::write (4 samples, 0.04%)core::fmt::float::float_to_decimal_common_exact (4 samples, 0.04%)ast::lang::graphs::neo4j::executor::TransactionManager::execute::_{{closure}} (5 samples, 0.05%)core::str::pattern::TwoWaySearcher::next (2 samples, 0.02%)neo4rs::query::Query::run::_{{closure}} (3 samples, 0.03%)neo4rs::messages::BoltRequest::run (3 samples, 0.03%)neo4rs::messages::run::Run::new (3 samples, 0.03%)_xzm_xzone_malloc_tiny (2 samples, 0.02%)__recvfrom (10 samples, 0.09%)<&mio::net::tcp::stream::TcpStream as std::io::Read>::read (11 samples, 0.10%)<&std::net::tcp::TcpStream as std::io::Read>::read (11 samples, 0.10%)<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_read::AsyncRead>::poll_read (13 samples, 0.12%)<tokio::io::util::buf_writer::BufWriter<W> as tokio::io::async_read::AsyncRead>::poll_read (12 samples, 0.11%)tokio::io::poll_evented::PollEvented<E>::poll_read (12 samples, 0.11%)<&mio::net::tcp::stream::TcpStream as std::io::Write>::write (10 samples, 0.09%)<&std::net::tcp::TcpStream as std::io::Write>::write (10 samples, 0.09%)__sendto (10 samples, 0.09%)<tokio::io::util::buf_writer::BufWriter<W> as tokio::io::async_write::AsyncWrite>::poll_flush (11 samples, 0.10%)tokio::io::util::buf_writer::BufWriter<W>::flush_buf (11 samples, 0.10%)tokio::io::poll_evented::PollEvented<E>::poll_write (11 samples, 0.10%)_malloc_zone_malloc (2 samples, 0.02%)bytes::bytes_mut::BytesMut::reserve (3 samples, 0.03%)bytes::bytes_mut::BytesMut::reserve_inner (3 samples, 0.03%)alloc::raw_vec::RawVecInner<A>::reserve::do_reserve_and_handle (3 samples, 0.03%)alloc::raw_vec::RawVecInner<A>::finish_grow (3 samples, 0.03%)<neo4rs::types::string::BoltString as neo4rs::types::wire::BoltWireFormat>::parse (2 samples, 0.02%)hashbrown::map::HashMap<K,V,S,A>::insert (2 samples, 0.02%)hashbrown::raw::RawTable<T,A>::reserve_rehash (2 samples, 0.02%)_xzm_xzone_malloc_tiny (2 samples, 0.02%)<neo4rs::types::integer::BoltInteger as neo4rs::types::wire::BoltWireFormat>::parse (2 samples, 0.02%)<neo4rs::types::map::BoltMap as neo4rs::types::wire::BoltWireFormat>::parse (10 samples, 0.09%)neo4rs::types::BoltType::parse (6 samples, 0.06%)<neo4rs::types::list::BoltList as neo4rs::types::wire::BoltWireFormat>::parse (3 samples, 0.03%)neo4rs::connection::Connection::recv::_{{closure}} (11 samples, 0.10%)neo4rs::messages::BoltResponse::parse (11 samples, 0.10%)tokio::io::poll_evented::PollEvented<E>::poll_write (6 samples, 0.06%)<&mio::net::tcp::stream::TcpStream as std::io::Write>::write (6 samples, 0.06%)<&std::net::tcp::TcpStream as std::io::Write>::write (6 samples, 0.06%)__sendto (6 samples, 0.06%)<tokio::io::util::buf_writer::BufWriter<W> as tokio::io::async_write::AsyncWrite>::poll_write (7 samples, 0.07%)<bytes::bytes_mut::BytesMut as bytes::buf::buf_mut::BufMut>::put_slice (5 samples, 0.05%)_platform_memmove (5 samples, 0.05%)<neo4rs::types::map::BoltMap as neo4rs::types::wire::BoltWireFormat>::write_into (6 samples, 0.06%)<neo4rs::types::string::BoltString as neo4rs::types::wire::BoltWireFormat>::write_into (6 samples, 0.06%)<neo4rs::types::map::BoltMap as neo4rs::types::wire::BoltWireFormat>::write_into (7 samples, 0.07%)<neo4rs::messages::run::Run as neo4rs::types::wire::BoltWireFormat>::write_into (9 samples, 0.08%)neo4rs::query::Query::try_request::_{{closure}} (58 samples, 0.54%)neo4rs::connection::Connection::send_recv::_{{closure}} (58 samples, 0.54%)neo4rs::connection::Connection::send::_{{closure}} (20 samples, 0.19%)neo4rs::messages::BoltRequest::into_bytes (12 samples, 0.11%)neo4rs::types::wire::BoltWireFormat::into_bytes (12 samples, 0.11%)core::ptr::drop_in_place<neo4rs::messages::run::Run> (3 samples, 0.03%)core::ptr::drop_in_place<neo4rs::types::BoltType> (3 samples, 0.03%)_xzm_free (3 samples, 0.03%)__recvfrom (13 samples, 0.12%)<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_read::AsyncRead>::poll_read (14 samples, 0.13%)<tokio::io::util::buf_writer::BufWriter<W> as tokio::io::async_read::AsyncRead>::poll_read (14 samples, 0.13%)tokio::io::poll_evented::PollEvented<E>::poll_read (14 samples, 0.13%)<&mio::net::tcp::stream::TcpStream as std::io::Read>::read (14 samples, 0.13%)<&std::net::tcp::TcpStream as std::io::Read>::read (14 samples, 0.13%)<tokio::io::util::buf_writer::BufWriter<W> as tokio::io::async_write::AsyncWrite>::poll_flush (12 samples, 0.11%)tokio::io::util::buf_writer::BufWriter<W>::flush_buf (12 samples, 0.11%)tokio::io::poll_evented::PollEvented<E>::poll_write (12 samples, 0.11%)<&mio::net::tcp::stream::TcpStream as std::io::Write>::write (12 samples, 0.11%)<&std::net::tcp::TcpStream as std::io::Write>::write (12 samples, 0.11%)__sendto (12 samples, 0.11%)bytes::bytes_mut::BytesMut::reserve (2 samples, 0.02%)bytes::bytes_mut::BytesMut::reserve_inner (2 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::reserve::do_reserve_and_handle (2 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::finish_grow (2 samples, 0.02%)neo4rs::connection::Connection::recv::_{{closure}} (4 samples, 0.04%)neo4rs::messages::BoltResponse::parse (3 samples, 0.03%)<neo4rs::types::map::BoltMap as neo4rs::types::wire::BoltWireFormat>::parse (3 samples, 0.03%)<bytes::bytes::Bytes as core::convert::From<alloc::vec::Vec<u8>>>::from (2 samples, 0.02%)_xzm_xzone_malloc_tiny (2 samples, 0.02%)neo4rs::query::Query::try_run::_{{closure}} (39 samples, 0.36%)neo4rs::connection::Connection::send_recv::_{{closure}} (37 samples, 0.35%)neo4rs::connection::Connection::send::_{{closure}} (5 samples, 0.05%)neo4rs::messages::BoltRequest::into_bytes (5 samples, 0.05%)neo4rs::types::wire::BoltWireFormat::into_bytes (5 samples, 0.05%)<neo4rs::types::map::BoltMap as neo4rs::types::wire::BoltWireFormat>::write_into (3 samples, 0.03%)ast::builder::streaming::GraphStreamingUploader::flush_stage::_{{closure}}::_{{closure}} (124 samples, 1.16%)ast::lang::graphs::neo4j::executor::execute_batch::_{{closure}} (123 samples, 1.15%)tracing::span::Span::do_enter (5 samples, 0.05%)<tracing_subscriber::layer::layered::Layered<L,S> as tracing_core::subscriber::Subscriber>::enter (5 samples, 0.05%)<tracing_subscriber::layer::layered::Layered<L,S> as tracing_core::subscriber::Subscriber>::enter (5 samples, 0.05%)<tracing_subscriber::registry::sharded::Registry as tracing_core::subscriber::Subscriber>::enter (4 samples, 0.04%)<tracing_subscriber::registry::sharded::Registry as tracing_core::subscriber::Subscriber>::clone_span (2 samples, 0.02%)<tracing_subscriber::layer::layered::Layered<L,S> as tracing_core::subscriber::Subscriber>::try_close (3 samples, 0.03%)<tracing_subscriber::layer::layered::Layered<L,S> as tracing_core::subscriber::Subscriber>::try_close (4 samples, 0.04%)ast::builder::streaming::GraphStreamingUploader::flush_stage::_{{closure}} (140 samples, 1.31%)tracing::span::Span::do_exit (7 samples, 0.07%)<tracing_subscriber::layer::layered::Layered<L,S> as tracing_core::subscriber::Subscriber>::exit (6 samples, 0.06%)<tracing_subscriber::layer::layered::Layered<L,S> as tracing_core::subscriber::Subscriber>::exit (6 samples, 0.06%)<tracing_subscriber::registry::sharded::Registry as tracing_core::subscriber::Subscriber>::exit (6 samples, 0.06%)_platform_memmove (5 samples, 0.05%)<ast::lang::asg::NodeData as core::clone::Clone>::clone (6 samples, 0.06%)<alloc::string::String as core::clone::Clone>::clone (6 samples, 0.06%)<ast::lang::asg::NodeData as core::clone::Clone>::clone (2 samples, 0.02%)<alloc::string::String as core::clone::Clone>::clone (2 samples, 0.02%)_platform_memmove (2 samples, 0.02%)ast::lang::asg::_<impl core::convert::From<&ast::lang::asg::NodeData> for neo4rs::types::map::BoltMap>::from (3 samples, 0.03%)hashbrown::map::HashMap<K,V,S,A>::insert (2 samples, 0.02%)hashbrown::raw::RawTable<T,A>::reserve_rehash (2 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::reserve::do_reserve_and_handle (2 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::finish_grow (2 samples, 0.02%)ast::utils::sanitize_string (3 samples, 0.03%)ast::utils::create_node_key (4 samples, 0.04%)<core::str::pattern::CharSearcher as core::str::pattern::Searcher>::next_match (8 samples, 0.07%)core::slice::memchr::memchr_aligned (2 samples, 0.02%)<base64::engine::general_purpose::GeneralPurpose as base64::engine::Engine>::internal_decode (3 samples, 0.03%)base64::engine::general_purpose::decode_suffix::decode_suffix (3 samples, 0.03%)base64::engine::Engine::decode::inner (4 samples, 0.04%)hashbrown::map::HashMap<K,V,S,A>::insert (16 samples, 0.15%)hashbrown::raw::RawTable<T,A>::reserve_rehash (4 samples, 0.04%)<alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter (4 samples, 0.04%)_platform_memcmp (2 samples, 0.02%)_platform_memcmp (3 samples, 0.03%)core::slice::sort::stable::driftsort_main (20 samples, 0.19%)core::slice::sort::stable::drift::sort (20 samples, 0.19%)core::slice::sort::stable::quicksort::quicksort (20 samples, 0.19%)core::slice::sort::stable::quicksort::quicksort (17 samples, 0.16%)core::slice::sort::stable::quicksort::quicksort (13 samples, 0.12%)core::slice::sort::stable::quicksort::quicksort (9 samples, 0.08%)core::slice::sort::stable::quicksort::quicksort (5 samples, 0.05%)core::slice::sort::stable::quicksort::quicksort (4 samples, 0.04%)core::slice::sort::stable::quicksort::quicksort (3 samples, 0.03%)fancy_regex::compile::Compiler::compile_delegates (2 samples, 0.02%)fancy_regex::compile::compile_inner (2 samples, 0.02%)regex_automata::meta::regex::Builder::build (2 samples, 0.02%)regex_automata::meta::strategy::new (2 samples, 0.02%)regex_automata::util::prefilter::prefixes (2 samples, 0.02%)fancy_regex::Regex::new (5 samples, 0.05%)fancy_regex::Regex::new_options (5 samples, 0.05%)fancy_regex::compile::compile (5 samples, 0.05%)fancy_regex::compile::Compiler::visit (5 samples, 0.05%)fancy_regex::compile::Compiler::visit (5 samples, 0.05%)fancy_regex::compile::Compiler::visit (5 samples, 0.05%)fancy_regex::compile::Compiler::visit (5 samples, 0.05%)fancy_regex::compile::Compiler::visit (4 samples, 0.04%)fancy_regex::compile::Compiler::compile_repeat (2 samples, 0.02%)fancy_regex::compile::Compiler::visit (2 samples, 0.02%)fancy_regex::compile::Compiler::compile_delegate (2 samples, 0.02%)fancy_regex::compile::compile_inner (2 samples, 0.02%)regex_automata::meta::regex::Builder::build (2 samples, 0.02%)regex_automata::meta::strategy::new (2 samples, 0.02%)regex_automata::nfa::thompson::compiler::Compiler::compile (2 samples, 0.02%)<core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::next (2 samples, 0.02%)_platform_memmove (2 samples, 0.02%)std::sys::sync::once::queue::Once::call (70 samples, 0.65%)std::sync::once::Once::call_once::_{{closure}} (70 samples, 0.65%)tiktoken_rs::api::get_bpe_from_model (70 samples, 0.65%)tiktoken_rs::tiktoken_ext::openai_public::cl100k_base (70 samples, 0.65%)tiktoken_rs::patched_tiktoken::_<impl tiktoken_rs::vendor_tiktoken::CoreBPE>::new (38 samples, 0.35%)hashbrown::raw::RawIterRange<T>::fold_impl (8 samples, 0.07%)<fancy_regex::Matches as core::iter::traits::iterator::Iterator>::next (3 samples, 0.03%)_xzm_free (5 samples, 0.05%)<regex_automata::meta::strategy::Core as regex_automata::meta::strategy::Strategy>::search_half (32 samples, 0.30%)_free (11 samples, 0.10%)DYLD-STUB$$_platform_bzero (2 samples, 0.02%)_xzm_free (50 samples, 0.47%)_platform_memset (16 samples, 0.15%)alloc::raw_vec::RawVec<T,A>::grow_one (2 samples, 0.02%)fancy_regex::vm::State::save (8 samples, 0.07%)<deduplicated_symbol> (18 samples, 0.17%)regex_automata::dfa::automaton::Automaton::start_state_forward (33 samples, 0.31%)regex_automata::dfa::search::find_fwd (261 samples, 2.43%)re..regex_automata::dfa::automaton::Automaton::start_state_forward (106 samples, 0.99%)<regex_automata::meta::strategy::Core as regex_automata::meta::strategy::Strategy>::search_half (741 samples, 6.91%)<regex_au..regex_automata::hybrid::search::find_fwd (334 samples, 3.11%)reg..<regex_automata::meta::strategy::Pre<P> as regex_automata::meta::strategy::Strategy>::search_half (7 samples, 0.07%)DYLD-STUB$$free (9 samples, 0.08%)DYLD-STUB$$malloc (4 samples, 0.04%)__rustc::__rdl_alloc (3 samples, 0.03%)_free (19 samples, 0.18%)_malloc_zone_malloc (10 samples, 0.09%)_platform_memcmp (4 samples, 0.04%)_platform_memset (23 samples, 0.21%)DYLD-STUB$$_platform_bzero (4 samples, 0.04%)__bzero (10 samples, 0.09%)_xzm_free (79 samples, 0.74%)_platform_memset (14 samples, 0.13%)_xzm_xzone_malloc (35 samples, 0.33%)_xzm_xzone_malloc_tiny (5 samples, 0.05%)_realloc (2 samples, 0.02%)<deduplicated_symbol> (17 samples, 0.16%)__rustc::__rdl_alloc (3 samples, 0.03%)__rustc::__rdl_realloc (3 samples, 0.03%)__rustc::__rust_no_alloc_shim_is_unstable_v2 (2 samples, 0.02%)_malloc_zone_malloc (16 samples, 0.15%)default_zone_realloc (2 samples, 0.02%)<deduplicated_symbol> (9 samples, 0.08%)_platform_memmove (4 samples, 0.04%)_xzm_free (24 samples, 0.22%)_xzm_malloc_large_huge (2 samples, 0.02%)xzm_segment_group_alloc_chunk (2 samples, 0.02%)_xzm_segment_group_find_and_allocate_chunk (2 samples, 0.02%)_xzm_xzone_malloc (10 samples, 0.09%)_malloc_zone_realloc (79 samples, 0.74%)xzm_realloc (72 samples, 0.67%)_xzm_xzone_malloc_tiny (9 samples, 0.08%)xzm_malloc_zone_size (13 samples, 0.12%)_realloc (102 samples, 0.95%)_xzm_xzone_malloc (14 samples, 0.13%)alloc::raw_vec::RawVec<T,A>::grow_one (175 samples, 1.63%)alloc::raw_vec::RawVecInner<A>::finish_grow (170 samples, 1.59%)alloc::raw_vec::RawVecInner<A>::finish_grow (6 samples, 0.06%)<deduplicated_symbol> (43 samples, 0.40%)_malloc_zone_malloc (10 samples, 0.09%)alloc::raw_vec::RawVec<T,A>::grow_one (88 samples, 0.82%)alloc::raw_vec::RawVecInner<A>::finish_grow (86 samples, 0.80%)_xzm_xzone_malloc (26 samples, 0.24%)fancy_regex::vm::State::save (125 samples, 1.17%)alloc::raw_vec::RawVecInner<A>::finish_grow (6 samples, 0.06%)malloc (2 samples, 0.02%)regex_automata::dfa::search::find_fwd (28 samples, 0.26%)regex_automata::hybrid::search::find_fwd (15 samples, 0.14%)<fancy_regex::Matches as core::iter::traits::iterator::Iterator>::next (2,417 samples, 22.54%)<fancy_regex::Matches as core::iter:..fancy_regex::Regex::find_from_pos_with_option_flags (2,395 samples, 22.33%)fancy_regex::Regex::find_from_pos_w..fancy_regex::vm::run (2,270 samples, 21.17%)fancy_regex::vm::runDYLD-STUB$$free (3 samples, 0.03%)_free (2 samples, 0.02%)_platform_memcmp (24 samples, 0.22%)_platform_memmove (6 samples, 0.06%)_xzm_free (7 samples, 0.07%)alloc::raw_vec::RawVec<T,A>::grow_one (2 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::grow_amortized (2 samples, 0.02%)alloc::raw_vec::RawVecInner<A>::finish_grow (2 samples, 0.02%)_realloc (2 samples, 0.02%)_malloc_zone_realloc (2 samples, 0.02%)fancy_regex::Regex::find_from_pos_with_option_flags (3 samples, 0.03%)<core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::fold (42 samples, 0.39%)_platform_memcmp (14 samples, 0.13%)_xzm_xzone_malloc (7 samples, 0.07%)<alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter (58 samples, 0.54%)_xzm_xzone_malloc_tiny (4 samples, 0.04%)_free (4 samples, 0.04%)__bzero (2 samples, 0.02%)_platform_memset (2 samples, 0.02%)_xzm_free (25 samples, 0.23%)mach_absolute_time (4 samples, 0.04%)DYLD-STUB$$memcmp (3 samples, 0.03%)DYLD-STUB$$memmove (4 samples, 0.04%)_platform_memcmp (22 samples, 0.21%)_platform_memmove (28 samples, 0.26%)_xzm_xzone_malloc (5 samples, 0.05%)tiktoken_rs::vendor_tiktoken::byte_pair_encode (527 samples, 4.91%)tiktok..tiktoken_rs::vendor_tiktoken::_byte_pair_merge (436 samples, 4.07%)tikt.._xzm_xzone_malloc_tiny (15 samples, 0.14%)tiktoken_rs::vendor_tiktoken::CoreBPE::encode_with_special_tokens (3,095 samples, 28.86%)tiktoken_rs::vendor_tiktoken::CoreBPE::encode_..tiktoken_rs::vendor_tiktoken::CoreBPE::encode (3,092 samples, 28.83%)tiktoken_rs::vendor_tiktoken::CoreBPE::encodeuuid::fmt::_<impl core::fmt::Display for uuid::Uuid>::fmt (2 samples, 0.02%)ast::builder::streaming::nodes_to_bolt_format (3,191 samples, 29.76%)ast::builder::streaming::nodes_to_bolt_formatast::lang::graphs::neo4j::queries::nodes::NodeQueryBuilder::build_stream (3,185 samples, 29.70%)ast::lang::graphs::neo4j::queries::nodes::NodeQu..uuid::v4::_<impl uuid::Uuid>::new_v4 (4 samples, 0.04%)getentropy (4 samples, 0.04%)ast::repo::walk_files_arbitrary (2 samples, 0.02%)core::ptr::drop_in_place<hashbrown::raw::RawTable<(neo4rs::types::string::BoltString,neo4rs::types::BoltType)>> (2 samples, 0.02%)ast::builder::core::_<impl ast::repo::Repo>::build_graph_inner_with_streaming::_{{closure}} (6,744 samples, 62.89%)ast::builder::core::_<impl ast::repo::Repo>::build_graph_inner_with_streaming::_{{closure}}<ast::lang::queries::go::Go as ast::lang::queries::Stack>::parse (2 samples, 0.02%)ts_parser_parse_with_options (2 samples, 0.02%)ts_parser_parse (2 samples, 0.02%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (8 samples, 0.07%)tree_sitter::Query::new (8 samples, 0.07%)ts_query_new (8 samples, 0.07%)regex_automata::meta::wrappers::DFA::new (2 samples, 0.02%)regex_automata::dfa::dense::Builder::build_from_nfa (2 samples, 0.02%)tree_sitter::Query::from_raw_parts (4 samples, 0.04%)regex::regex::bytes::Regex::new (4 samples, 0.04%)regex::builders::bytes::RegexBuilder::build (4 samples, 0.04%)regex_automata::meta::regex::Builder::build (4 samples, 0.04%)regex_automata::meta::strategy::new (4 samples, 0.04%)regex_automata::nfa::thompson::compiler::Compiler::compile (2 samples, 0.02%)_platform_memmove (10 samples, 0.09%)analysis_state_set__insert_sorted (3 samples, 0.03%)ts_query__parse_pattern (5 samples, 0.05%)ts_query__parse_pattern (4 samples, 0.04%)ts_query__parse_pattern (4 samples, 0.04%)ts_query__parse_pattern (4 samples, 0.04%)ts_query__parse_pattern (3 samples, 0.03%)_array__splice (2 samples, 0.02%)_platform_memmove (2 samples, 0.02%)_platform_memmove (5 samples, 0.05%)_malloc_zone_realloc (3 samples, 0.03%)xzm_realloc (3 samples, 0.03%)ts_query__perform_analysis (759 samples, 7.08%)ts_query_..analysis_state_set__insert_sorted (113 samples, 1.05%)ts_realloc_default (4 samples, 0.04%)_realloc (4 samples, 0.04%)_xzm_free (2 samples, 0.02%)_malloc_zone_realloc (8 samples, 0.07%)xzm_realloc (8 samples, 0.07%)<ast::lang::queries::react::ReactTs as ast::lang::queries::Stack>::q (909 samples, 8.48%)<ast::lang::..tree_sitter::Query::new (909 samples, 8.48%)tree_sitter:..ts_query_new (905 samples, 8.44%)ts_query_newts_realloc_default (10 samples, 0.09%)_realloc (9 samples, 0.08%)ts_lex (2 samples, 0.02%)ts_parser__do_all_potential_reductions (4 samples, 0.04%)<ast::lang::queries::ruby::Ruby as ast::lang::queries::Stack>::parse (11 samples, 0.10%)ts_parser_parse_with_options (11 samples, 0.10%)ts_parser_parse (11 samples, 0.10%)<tree_sitter::QueryMatches<T,I> as streaming_iterator::StreamingIterator>::advance (2 samples, 0.02%)ts_query_cursor_next_match (2 samples, 0.02%)ts_query_cursor__advance (2 samples, 0.02%)ts_lex (2 samples, 0.02%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::parse (3 samples, 0.03%)ts_parser_parse_with_options (3 samples, 0.03%)ts_parser_parse (3 samples, 0.03%)ast::lang::parse::collect::_<impl ast::lang::Lang>::collect_import_edges (8 samples, 0.07%)<ast::lang::queries::ruby::Ruby as ast::lang::queries::Stack>::parse (4 samples, 0.04%)ts_parser_parse_with_options (4 samples, 0.04%)ts_parser_parse (4 samples, 0.04%)ts_parser__do_all_potential_reductions (2 samples, 0.02%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (21 samples, 0.20%)tree_sitter::Query::new (21 samples, 0.20%)ts_query_new (21 samples, 0.20%)ts_query__perform_analysis (12 samples, 0.11%)analysis_state_set__insert_sorted (3 samples, 0.03%)regex_automata::meta::wrappers::DFA::new (2 samples, 0.02%)regex_automata::dfa::dense::Builder::build_from_nfa (2 samples, 0.02%)regex_automata::dfa::determinize::Config::run (2 samples, 0.02%)regex_automata::meta::strategy::new (4 samples, 0.04%)regex::builders::bytes::RegexBuilder::build (5 samples, 0.05%)regex_automata::meta::regex::Builder::build (5 samples, 0.05%)tree_sitter::Query::from_raw_parts (6 samples, 0.06%)regex::regex::bytes::Regex::new (6 samples, 0.06%)_platform_memmove (2 samples, 0.02%)_platform_memmove (2 samples, 0.02%)ts_query__perform_analysis (390 samples, 3.64%)ts_q..analysis_state_set__insert_sorted (62 samples, 0.58%)<ast::lang::queries::react::ReactTs as ast::lang::queries::Stack>::q (496 samples, 4.63%)<ast:..tree_sitter::Query::new (496 samples, 4.63%)tree_..ts_query_new (490 samples, 4.57%)ts_qu..ts_realloc_default (2 samples, 0.02%)_realloc (2 samples, 0.02%)ast::lang::call_finder::node_data_finder (4 samples, 0.04%)ast::lang::call_finder::find_only_one_function_file (2 samples, 0.02%)<ast::lang::graphs::btreemap_graph::BTreeMapGraph as ast::lang::graphs::graph::Graph>::find_nodes_by_name (2 samples, 0.02%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::parse (2 samples, 0.02%)ts_parser_parse_with_options (2 samples, 0.02%)ts_parser_parse (2 samples, 0.02%)ts_calloc_default (2 samples, 0.02%)_xzm_malloc_large_huge (2 samples, 0.02%)xzm_segment_group_alloc_chunk (2 samples, 0.02%)madvise (2 samples, 0.02%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (49 samples, 0.46%)tree_sitter::Query::new (49 samples, 0.46%)ts_query_new (49 samples, 0.46%)ts_query__perform_analysis (4 samples, 0.04%)_platform_memmove (2 samples, 0.02%)ts_calloc_default (6 samples, 0.06%)_xzm_malloc_large_huge (6 samples, 0.06%)xzm_segment_group_alloc_chunk (5 samples, 0.05%)__bzero (5 samples, 0.05%)<deduplicated_symbol> (2 samples, 0.02%)ts_malloc_default (3 samples, 0.03%)ts_query__perform_analysis (41 samples, 0.38%)analysis_state_set__insert_sorted (2 samples, 0.02%)_realloc (4 samples, 0.04%)_malloc_zone_realloc (3 samples, 0.03%)xzm_realloc (2 samples, 0.02%)<ast::lang::queries::react::ReactTs as ast::lang::queries::Stack>::q (244 samples, 2.28%)<..tree_sitter::Query::new (244 samples, 2.28%)t..ts_query_new (244 samples, 2.28%)t..ts_realloc_default (5 samples, 0.05%)ast::lang::call_finder::get_imports_for_file (300 samples, 2.80%)as..<ast::lang::queries::ruby::Ruby as ast::lang::queries::Stack>::parse (3 samples, 0.03%)ts_parser_parse_with_options (3 samples, 0.03%)ts_parser_parse (3 samples, 0.03%)ast::lang::parse::format::_<impl ast::lang::Lang>::format_function_call (305 samples, 2.84%)as..streaming_iterator::StreamingIterator::next (4 samples, 0.04%)<tree_sitter::QueryMatches<T,I> as streaming_iterator::StreamingIterator>::advance (4 samples, 0.04%)ts_query_cursor_next_match (4 samples, 0.04%)ts_query_cursor__advance (4 samples, 0.04%)ast::lang::parse::utils::_<impl ast::lang::Lang>::loop_captures (829 samples, 7.73%)ast::lang::..ast::lang::Lang::get_function_calls::_{{closure}}::_{{closure}} (829 samples, 7.73%)ast::lang::..streaming_iterator::StreamingIterator::next (3 samples, 0.03%)<tree_sitter::QueryMatches<T,I> as streaming_iterator::StreamingIterator>::advance (3 samples, 0.03%)ts_query_cursor_next_match (3 samples, 0.03%)ts_query_cursor__advance (3 samples, 0.03%)ts_tree_cursor_goto_first_child_internal (2 samples, 0.02%)ast::builder::core::_<impl ast::repo::Repo>::finalize_graph::_{{closure}} (1,772 samples, 16.52%)ast::builder::core::_<impl..<tracing::instrument::Instrumented<T> as core::future::future::Future>::poll (1,772 samples, 16.52%)<tracing::instrument::Inst..ast::builder::core::_<impl ast::repo::Repo>::finalize_graph::_{{closure}}::_{{closure}} (1,772 samples, 16.52%)ast::builder::core::_<impl..ast::builder::core::_<impl ast::repo::Repo>::process_and_add_files::_{{closure}} (5 samples, 0.05%)ast::builder::utils::_<impl ast::repo::Repo>::prepare_file_data (5 samples, 0.05%)sha2::sha256::compress256 (4 samples, 0.04%)<ast::lang::graphs::btreemap_graph::BTreeMapGraph as ast::lang::graphs::graph::Graph>::add_functions (2 samples, 0.02%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (3 samples, 0.03%)tree_sitter::Query::new (3 samples, 0.03%)ts_query_new (3 samples, 0.03%)tree_sitter::Query::from_raw_parts (4 samples, 0.04%)regex::regex::bytes::Regex::new (3 samples, 0.03%)regex::builders::bytes::RegexBuilder::build (3 samples, 0.03%)regex_automata::meta::regex::Builder::build (3 samples, 0.03%)regex_automata::meta::strategy::new (3 samples, 0.03%)regex_automata::meta::wrappers::DFA::new (3 samples, 0.03%)regex_automata::dfa::dense::Builder::build_from_nfa (3 samples, 0.03%)regex_automata::dfa::determinize::Config::run (3 samples, 0.03%)regex_automata::dfa::determinize::Runner::maybe_add_state (2 samples, 0.02%)_platform_memmove (9 samples, 0.08%)_array__splice (2 samples, 0.02%)_platform_memmove (11 samples, 0.10%)ts_query__perform_analysis (770 samples, 7.18%)ts_query__..analysis_state_set__insert_sorted (140 samples, 1.31%)ts_realloc_default (4 samples, 0.04%)_realloc (4 samples, 0.04%)xzm_malloc_zone_size (3 samples, 0.03%)_malloc_zone_realloc (3 samples, 0.03%)xzm_realloc (3 samples, 0.03%)<ast::lang::queries::react::ReactTs as ast::lang::queries::Stack>::q (885 samples, 8.25%)<ast::lang:..tree_sitter::Query::new (885 samples, 8.25%)tree_sitter..ts_query_new (881 samples, 8.22%)ts_query_newts_realloc_default (6 samples, 0.06%)_realloc (6 samples, 0.06%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (2 samples, 0.02%)tree_sitter::Query::new (2 samples, 0.02%)ts_query_new (2 samples, 0.02%)<ast::lang::queries::react::ReactTs as ast::lang::queries::Stack>::q (19 samples, 0.18%)tree_sitter::Query::new (19 samples, 0.18%)ts_query_new (19 samples, 0.18%)ast::lang::Lang::attach_function_comments (24 samples, 0.22%)ast::lang::parse::collect::_<impl ast::lang::Lang>::collect_functions (9 samples, 0.08%)<ast::lang::queries::ruby::Ruby as ast::lang::queries::Stack>::parse (8 samples, 0.07%)ts_parser_parse_with_options (8 samples, 0.07%)ts_parser_parse (8 samples, 0.07%)ts_parser__reduce (2 samples, 0.02%)ts_query__perform_analysis (8 samples, 0.07%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (15 samples, 0.14%)tree_sitter::Query::new (15 samples, 0.14%)ts_query_new (14 samples, 0.13%)tree_sitter::Query::from_raw_parts (3 samples, 0.03%)regex::regex::bytes::Regex::new (3 samples, 0.03%)regex::builders::bytes::RegexBuilder::build (3 samples, 0.03%)regex_automata::meta::regex::Builder::build (3 samples, 0.03%)_platform_memmove (4 samples, 0.04%)ts_query__perform_analysis (85 samples, 0.79%)analysis_state_set__insert_sorted (9 samples, 0.08%)<ast::lang::queries::react::ReactTs as ast::lang::queries::Stack>::q (132 samples, 1.23%)tree_sitter::Query::new (132 samples, 1.23%)ts_query_new (129 samples, 1.20%)ast::lang::parse::collect::_<impl ast::lang::Lang>::collect_router_arrow_functions (155 samples, 1.45%)<ast::lang::queries::ruby::Ruby as ast::lang::queries::Stack>::parse (7 samples, 0.07%)ts_parser_parse_with_options (6 samples, 0.06%)ts_parser_parse (6 samples, 0.06%)tree_sitter::Query::from_raw_parts (3 samples, 0.03%)regex::regex::bytes::Regex::new (3 samples, 0.03%)regex::builders::bytes::RegexBuilder::build (3 samples, 0.03%)regex_automata::meta::regex::Builder::build (3 samples, 0.03%)regex_automata::meta::strategy::new (3 samples, 0.03%)regex_automata::meta::wrappers::DFA::new (2 samples, 0.02%)regex_automata::dfa::dense::Builder::build_from_nfa (2 samples, 0.02%)regex_automata::dfa::determinize::Config::run (2 samples, 0.02%)<ast::lang::queries::go::Go as ast::lang::queries::Stack>::q (18 samples, 0.17%)tree_sitter::Query::new (18 samples, 0.17%)ts_query_new (15 samples, 0.14%)regex_automata::dfa::determinize::Runner::maybe_add_state (3 samples, 0.03%)regex_automata::meta::wrappers::DFA::new (6 samples, 0.06%)regex_automata::dfa::dense::Builder::build_from_nfa (6 samples, 0.06%)regex_automata::dfa::determinize::Config::run (6 samples, 0.06%)regex_automata::nfa::thompson::compiler::Compiler::c_at_least (2 samples, 0.02%)<core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::next (4 samples, 0.04%)regex_automata::nfa::thompson::compiler::Compiler::c_cap (3 samples, 0.03%)regex_automata::nfa::thompson::compiler::Compiler::c (3 samples, 0.03%)regex::regex::bytes::Regex::new (14 samples, 0.13%)regex::builders::bytes::RegexBuilder::build (14 samples, 0.13%)regex_automata::meta::regex::Builder::build (14 samples, 0.13%)regex_automata::meta::strategy::new (14 samples, 0.13%)regex_automata::nfa::thompson::compiler::Compiler::compile (6 samples, 0.06%)regex_automata::nfa::thompson::builder::Builder::build (2 samples, 0.02%)tree_sitter::Query::from_raw_parts (15 samples, 0.14%)_platform_memmove (4 samples, 0.04%)ts_calloc_default (4 samples, 0.04%)_xzm_malloc_large_huge (4 samples, 0.04%)xzm_segment_group_alloc_chunk (4 samples, 0.04%)__bzero (4 samples, 0.04%)ts_query__parse_pattern (2 samples, 0.02%)_platform_memmove (2 samples, 0.02%)ts_query__perform_analysis (306 samples, 2.85%)ts..analysis_state_set__insert_sorted (47 samples, 0.44%)_xzm_free (2 samples, 0.02%)ast::lang::parse::format::_<impl ast::lang::Lang>::format_function::_{{closure}} (520 samples, 4.85%)ast::l..<ast::lang::queries::react::ReactTs as ast::lang::queries::Stack>::q (502 samples, 4.68%)<ast:..tree_sitter::Query::new (502 samples, 4.68%)tree_..ts_query_new (487 samples, 4.54%)ts_qu..ts_realloc_default (8 samples, 0.07%)_realloc (8 samples, 0.07%)_malloc_zone_realloc (6 samples, 0.06%)xzm_realloc (6 samples, 0.06%)ast::lang::parse::format::_<impl ast::lang::Lang>::format_function (526 samples, 4.90%)ast::l..streaming_iterator::StreamingIterator::next (3 samples, 0.03%)<tree_sitter::QueryMatches<T,I> as streaming_iterator::StreamingIterator>::advance (3 samples, 0.03%)ts_query_cursor_next_match (3 samples, 0.03%)ts_query_cursor__advance (3 samples, 0.03%)core::ptr::drop_in_place<tree_sitter::Tree> (2 samples, 0.02%)ts_tree_delete (2 samples, 0.02%)ts_subtree_release (2 samples, 0.02%)ts_tree_cursor_current_status (2 samples, 0.02%)ast::lang::Lang::get_functions_and_tests (1,609 samples, 15.00%)ast::lang::Lang::get_fu..streaming_iterator::StreamingIterator::next (4 samples, 0.04%)<tree_sitter::QueryMatches<T,I> as streaming_iterator::StreamingIterator>::advance (4 samples, 0.04%)ts_query_cursor_next_match (4 samples, 0.04%)ts_query_cursor__advance (4 samples, 0.04%)ts_tree_cursor_goto_sibling_internal (2 samples, 0.02%)ts_parser__do_all_potential_reductions (2 samples, 0.02%)ast::lang::parse::collect::_<impl ast::lang::Lang>::collect_tests (9 samples, 0.08%)<ast::lang::queries::ruby::Ruby as ast::lang::queries::Stack>::parse (9 samples, 0.08%)ts_parser_parse_with_options (9 samples, 0.08%)ts_parser_parse (8 samples, 0.07%)ast::builder::core::_<impl ast::repo::Repo>::process_functions_and_tests::_{{closure}} (1,622 samples, 15.12%)ast::builder::core::_<i..ast::builder::core::_<impl ast::repo::Repo>::process_functions_and_tests::_{{closure}}::_{{closure}} (1,622 samples, 15.12%)ast::builder::core::_<i..ast::builder::streaming::GraphStreamingUploader::flush_edges_stage::_{{closure}} (2 samples, 0.02%)ast::lang::graphs::neo4j::executor::execute_queries_simple::_{{closure}} (2 samples, 0.02%)ast::lang::graphs::neo4j::executor::TransactionManager::execute::_{{closure}} (2 samples, 0.02%)<T as core::convert::Into<U>>::into (2 samples, 0.02%)<neo4rs::types::string::BoltString as core::convert::From<&str>>::from (2 samples, 0.02%)_xzm_xzone_malloc_tiny (2 samples, 0.02%)ast::lang::graphs::neo4j::executor::TransactionManager::execute::_{{closure}} (2 samples, 0.02%)<&str as core::str::pattern::Pattern>::into_searcher (2 samples, 0.02%)core::str::pattern::StrSearcher::new (2 samples, 0.02%)<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_read::AsyncRead>::poll_read (2 samples, 0.02%)<tokio::io::util::buf_writer::BufWriter<W> as tokio::io::async_read::AsyncRead>::poll_read (2 samples, 0.02%)tokio::io::poll_evented::PollEvented<E>::poll_read (2 samples, 0.02%)<&mio::net::tcp::stream::TcpStream as std::io::Read>::read (2 samples, 0.02%)<&std::net::tcp::TcpStream as std::io::Read>::read (2 samples, 0.02%)__recvfrom (2 samples, 0.02%)<&mio::net::tcp::stream::TcpStream as std::io::Write>::write (7 samples, 0.07%)<&std::net::tcp::TcpStream as std::io::Write>::write (7 samples, 0.07%)__sendto (7 samples, 0.07%)<tokio::io::util::buf_writer::BufWriter<W> as tokio::io::async_write::AsyncWrite>::poll_flush (8 samples, 0.07%)tokio::io::util::buf_writer::BufWriter<W>::flush_buf (8 samples, 0.07%)tokio::io::poll_evented::PollEvented<E>::poll_write (8 samples, 0.07%)bytes::bytes_mut::BytesMut::reserve (3 samples, 0.03%)bytes::bytes_mut::BytesMut::reserve_inner (3 samples, 0.03%)alloc::raw_vec::RawVecInner<A>::reserve::do_reserve_and_handle (3 samples, 0.03%)alloc::raw_vec::RawVecInner<A>::finish_grow (3 samples, 0.03%)neo4rs::query::Query::try_request::_{{closure}} (17 samples, 0.16%)neo4rs::connection::Connection::send_recv::_{{closure}} (17 samples, 0.16%)neo4rs::connection::Connection::send::_{{closure}} (3 samples, 0.03%)neo4rs::messages::BoltRequest::into_bytes (2 samples, 0.02%)neo4rs::types::wire::BoltWireFormat::into_bytes (2 samples, 0.02%)<neo4rs::messages::run::Run as neo4rs::types::wire::BoltWireFormat>::write_into (2 samples, 0.02%)<neo4rs::types::map::BoltMap as neo4rs::types::wire::BoltWireFormat>::write_into (2 samples, 0.02%)<tokio::io::util::buf_stream::BufStream<RW> as tokio::io::async_read::AsyncRead>::poll_read (3 samples, 0.03%)<tokio::io::util::buf_writer::BufWriter<W> as tokio::io::async_read::AsyncRead>::poll_read (3 samples, 0.03%)tokio::io::poll_evented::PollEvented<E>::poll_read (3 samples, 0.03%)<&mio::net::tcp::stream::TcpStream as std::io::Read>::read (3 samples, 0.03%)<&std::net::tcp::TcpStream as std::io::Read>::read (3 samples, 0.03%)__recvfrom (3 samples, 0.03%)<tokio::io::util::buf_writer::BufWriter<W> as tokio::io::async_write::AsyncWrite>::poll_flush (3 samples, 0.03%)tokio::io::util::buf_writer::BufWriter<W>::flush_buf (3 samples, 0.03%)tokio::io::poll_evented::PollEvented<E>::poll_write (3 samples, 0.03%)<&mio::net::tcp::stream::TcpStream as std::io::Write>::write (3 samples, 0.03%)<&std::net::tcp::TcpStream as std::io::Write>::write (3 samples, 0.03%)__sendto (3 samples, 0.03%)neo4rs::connection::Connection::send_recv::_{{closure}} (10 samples, 0.09%)neo4rs::query::Query::try_run::_{{closure}} (11 samples, 0.10%)ast::builder::streaming::GraphStreamingUploader::flush_stage::_{{closure}} (36 samples, 0.34%)ast::builder::streaming::GraphStreamingUploader::flush_stage::_{{closure}}::_{{closure}} (35 samples, 0.33%)ast::lang::graphs::neo4j::executor::execute_batch::_{{closure}} (34 samples, 0.32%)_xzm_free (2 samples, 0.02%)<regex_automata::meta::strategy::Core as regex_automata::meta::strategy::Strategy>::search_half (2 samples, 0.02%)_xzm_free (5 samples, 0.05%)_platform_memset (2 samples, 0.02%)<deduplicated_symbol> (2 samples, 0.02%)regex_automata::dfa::automaton::Automaton::start_state_forward (6 samples, 0.06%)regex_automata::dfa::search::find_fwd (32 samples, 0.30%)regex_automata::dfa::automaton::Automaton::start_state_forward (14 samples, 0.13%)<regex_automata::meta::strategy::Core as regex_automata::meta::strategy::Strategy>::search_half (107 samples, 1.00%)regex_automata::hybrid::search::find_fwd (60 samples, 0.56%)<regex_automata::meta::strategy::Pre<P> as regex_automata::meta::strategy::Strategy>::search_half (2 samples, 0.02%)_free (7 samples, 0.07%)_platform_memcmp (3 samples, 0.03%)_platform_memset (3 samples, 0.03%)_xzm_free (8 samples, 0.07%)_xzm_xzone_malloc (4 samples, 0.04%)<deduplicated_symbol> (2 samples, 0.02%)_malloc_zone_malloc (2 samples, 0.02%)<deduplicated_symbol> (2 samples, 0.02%)_xzm_xzone_malloc (2 samples, 0.02%)_malloc_zone_realloc (13 samples, 0.12%)xzm_realloc (11 samples, 0.10%)_realloc (16 samples, 0.15%)xzm_malloc_zone_size (2 samples, 0.02%)alloc::raw_vec::RawVec<T,A>::grow_one (26 samples, 0.24%)alloc::raw_vec::RawVecInner<A>::finish_grow (25 samples, 0.23%)_xzm_xzone_malloc (2 samples, 0.02%)<deduplicated_symbol> (10 samples, 0.09%)__rustc::__rdl_alloc (2 samples, 0.02%)__rustc::__rust_no_alloc_shim_is_unstable_v2 (2 samples, 0.02%)_malloc_zone_malloc (2 samples, 0.02%)fancy_regex::vm::State::save (25 samples, 0.23%)alloc::raw_vec::RawVec<T,A>::grow_one (22 samples, 0.21%)alloc::raw_vec::RawVecInner<A>::finish_grow (22 samples, 0.21%)_xzm_xzone_malloc (6 samples, 0.06%)<fancy_regex::Matches as core::iter::traits::iterator::Iterator>::next (315 samples, 2.94%)<f..fancy_regex::Regex::find_from_pos_with_option_flags (313 samples, 2.92%)fa..fancy_regex::vm::run (305 samples, 2.84%)fa..regex_automata::hybrid::search::find_fwd (3 samples, 0.03%)<core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::fold (6 samples, 0.06%)_platform_memcmp (2 samples, 0.02%)<alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter (8 samples, 0.07%)_xzm_free (2 samples, 0.02%)_platform_memcmp (5 samples, 0.05%)_platform_memmove (3 samples, 0.03%)ast::builder::streaming::nodes_to_bolt_format (394 samples, 3.67%)ast:..ast::lang::graphs::neo4j::queries::nodes::NodeQueryBuilder::build_stream (394 samples, 3.67%)ast:..tiktoken_rs::vendor_tiktoken::CoreBPE::encode_with_special_tokens (392 samples, 3.66%)tikt..tiktoken_rs::vendor_tiktoken::CoreBPE::encode (392 samples, 3.66%)tikt..tiktoken_rs::vendor_tiktoken::byte_pair_encode (64 samples, 0.60%)tiktoken_rs::vendor_tiktoken::_byte_pair_merge (54 samples, 0.50%)_xzm_xzone_malloc_tiny (2 samples, 0.02%)regex_automata::meta::wrappers::DFA::new (4 samples, 0.04%)regex_automata::dfa::dense::Builder::build_from_nfa (4 samples, 0.04%)regex_automata::dfa::determinize::Config::run (4 samples, 0.04%)regex_automata::dfa::determinize::Runner::maybe_add_state (4 samples, 0.04%)ast::lang::linker::normalize_backend_path (7 samples, 0.07%)regex::regex::string::Regex::new (7 samples, 0.07%)regex::builders::Builder::build_one_string (7 samples, 0.07%)regex_automata::meta::regex::Builder::build (7 samples, 0.07%)regex_automata::meta::strategy::new (7 samples, 0.07%)regex_automata::nfa::thompson::compiler::Compiler::compile (2 samples, 0.02%)ast::lang::linker::link_api_nodes (8 samples, 0.07%)std::io::default_read_to_end (2 samples, 0.02%)read (2 samples, 0.02%)ast::repo::Repos::build_graphs_inner_impl::_{{closure}} (10,598 samples, 98.83%)ast::repo::Repos::build_graphs_inner_impl::_{{closure}}std::fs::read_to_string (5 samples, 0.05%)std::fs::read_to_string::inner (5 samples, 0.05%)std::sys::fs::unix::File::open_c (3 samples, 0.03%)open (3 samples, 0.03%)__open (3 samples, 0.03%)<walkdir::FilterEntry<walkdir::IntoIter,P> as core::iter::traits::iterator::Iterator>::next (5 samples, 0.05%)<walkdir::IntoIter as core::iter::traits::iterator::Iterator>::next (5 samples, 0.05%)walkdir::IntoIter::handle_entry (4 samples, 0.04%)walkdir::IntoIter::push (4 samples, 0.04%)std::sys::fs::read_dir (4 samples, 0.04%)__opendir2 (4 samples, 0.04%)open$NOCANCEL (4 samples, 0.04%)__open_nocancel (4 samples, 0.04%)ast::repo::walk_files (7 samples, 0.07%)std::path::Path::is_file (2 samples, 0.02%)stat (2 samples, 0.02%)lsp::utils::run::_{{closure}} (3 samples, 0.03%)async_process::Command::output (3 samples, 0.03%)async_process::Child::new (3 samples, 0.03%)std::process::Command::spawn (3 samples, 0.03%)std::sys::process::unix::unix::_<impl std::sys::process::unix::common::Command>::spawn (3 samples, 0.03%)posix_spawnp (3 samples, 0.03%)posix_spawn (3 samples, 0.03%)__posix_spawn (3 samples, 0.03%)std::sys::fs::unix::remove_dir_impl::remove_dir_all_recursive (2 samples, 0.02%)unlinkat (2 samples, 0.02%)__unlinkat (2 samples, 0.02%)std::sys::fs::unix::remove_dir_impl::remove_dir_all_recursive (6 samples, 0.06%)unlinkat (4 samples, 0.04%)__unlinkat (4 samples, 0.04%)std::sys::fs::unix::remove_dir_impl::remove_dir_all_recursive (8 samples, 0.07%)unlinkat (2 samples, 0.02%)__unlinkat (2 samples, 0.02%)ast::repo::Repo::new_clone_multi_detect::_{{closure}} (22 samples, 0.21%)<tracing::instrument::Instrumented<T> as core::future::future::Future>::poll (22 samples, 0.21%)ast::repo::Repo::new_clone_multi_detect::_{{closure}}::_{{closure}} (22 samples, 0.21%)std::sys::fs::remove_dir_all (12 samples, 0.11%)std::sys::fs::unix::remove_dir_impl::remove_dir_all_recursive (12 samples, 0.11%)unlinkat (4 samples, 0.04%)__unlinkat (4 samples, 0.04%)system_configuration::dynamic_store::SCDynamicStore::get_proxies (2 samples, 0.02%)SCDynamicStoreCopyProxiesWithOptions (2 samples, 0.02%)_CFPreferencesCopyAppValueWithContainerAndConfiguration (2 samples, 0.02%)-[_CFXPreferences copyAppValueForKey:identifier:container:configurationURL:] (2 samples, 0.02%)-[_CFXPreferences withSearchListForIdentifier:container:cloudConfigurationURL:perform:] (2 samples, 0.02%)__108-[_CFXPreferences(SearchListAdditions) withSearchListForIdentifier:container:cloudConfigurationURL:perform:]_block_invoke (2 samples, 0.02%)__76-[_CFXPreferences copyAppValueForKey:identifier:container:configurationURL:]_block_invoke (2 samples, 0.02%)-[CFPrefsSource copyValueForKey:] (2 samples, 0.02%)-[CFPrefsSearchListSource alreadylocked_copyValueForKey:] (2 samples, 0.02%)-[CFPrefsSearchListSource alreadylocked_getDictionary:] (2 samples, 0.02%)-[CFPrefsSearchListSource alreadylocked_generationCountFromListOfSources:count:] (2 samples, 0.02%)hyper_util::client::proxy::matcher::Matcher::from_system (4 samples, 0.04%)hyper_util::client::proxy::matcher::mac::with_system (4 samples, 0.04%)system_configuration::dynamic_store::SCDynamicStoreBuilder<T>::build (2 samples, 0.02%)system_configuration::dynamic_store::SCDynamicStore::create (2 samples, 0.02%)SCDynamicStoreCreateWithOptions (2 samples, 0.02%)<reqwest::async_impl::client::Client as core::default::Default>::default (6 samples, 0.06%)reqwest::async_impl::client::ClientBuilder::build (6 samples, 0.06%)standalone::utils::call_mcp_mocks::_{{closure}} (7 samples, 0.07%)0x100f3ea13 (10,633 samples, 99.15%)0x100f3ea13standalone::handlers::ingest::ingest_async::_{{closure}}::_{{closure}} (10,633 samples, 99.15%)standalone::handlers::ingest::ingest_async::_{{closure}}::_{{closure}}standalone::service::graph_service::ingest::_{{closure}} (33 samples, 0.31%)all (10,724 samples, 100%)thread_start (10,699 samples, 99.77%)thread_start_pthread_start (10,699 samples, 99.77%)_pthread_startstd::sys::thread::unix::Thread::new::thread_start (10,699 samples, 99.77%)std::sys::thread::unix::Thread::new::thread_startcore::ops::function::FnOnce::call_once{{vtable.shim}} (10,699 samples, 99.77%)core::ops::function::FnOnce::call_once{{vtable.shim}}std::sys::backtrace::__rust_begin_short_backtrace (10,699 samples, 99.77%)std::sys::backtrace::__rust_begin_short_backtracetokio::runtime::blocking::pool::Inner::run (10,698 samples, 99.76%)tokio::runtime::blocking::pool::Inner::runtokio::runtime::task::harness::Harness<T,S>::poll (10,697 samples, 99.75%)tokio::runtime::task::harness::Harness<T,S>::polltokio::runtime::task::core::Core<T,S>::poll (10,697 samples, 99.75%)tokio::runtime::task::core::Core<T,S>::poll<tokio::runtime::blocking::task::BlockingTask<T> as core::future::future::Future>::poll (10,697 samples, 99.75%)<tokio::runtime::blocking::task::BlockingTask<T> as core::future::future::Future>::polltokio::runtime::scheduler::multi_thread::worker::run (10,691 samples, 99.69%)tokio::runtime::scheduler::multi_thread::worker::runtokio::runtime::context::runtime::enter_runtime (10,691 samples, 99.69%)tokio::runtime::context::runtime::enter_runtimetokio::runtime::context::scoped::Scoped<T>::set (10,691 samples, 99.69%)tokio::runtime::context::scoped::Scoped<T>::settokio::runtime::scheduler::multi_thread::worker::Context::run (10,690 samples, 99.68%)tokio::runtime::scheduler::multi_thread::worker::Context::runtokio::runtime::scheduler::multi_thread::worker::Context::run_task (10,639 samples, 99.21%)tokio::runtime::scheduler::multi_thread::worker::Context::run_tasktokio::runtime::task::harness::poll_future::_{{closure}} (10,636 samples, 99.18%)tokio::runtime::task::harness::poll_future::_{{closure}} \ No newline at end of file From f5e7803d9379ece7af2a4d43f4efdeeb388a3488 Mon Sep 17 00:00:00 2001 From: kelmith Date: Thu, 25 Dec 2025 20:37:58 +0530 Subject: [PATCH 4/6] fix: add timing to critical functions --- ast/src/builder/core.rs | 37 ++++++++------ ast/src/builder/utils.rs | 17 ++++++ ast/src/lang/call_finder.rs | 17 +++--- ast/src/lang/graphs/graph_ops.rs | 10 ++-- ast/src/lang/graphs/neo4j/executor.rs | 15 +++--- ast/src/repo.rs | 10 ++-- ast/src/utils.rs | 74 ++++++++++++++++++++++++++- 7 files changed, 135 insertions(+), 45 deletions(-) diff --git a/ast/src/builder/core.rs b/ast/src/builder/core.rs index 44bed76da..f68564d1c 100644 --- a/ast/src/builder/core.rs +++ b/ast/src/builder/core.rs @@ -1,6 +1,6 @@ #[cfg(feature = "neo4j")] use super::streaming::{nodes_to_bolt_format, StreamingUploadContext}; -use super::utils::*; +use super::utils::{timed_stage, timed_stage_async, *}; #[cfg(feature = "neo4j")] use crate::lang::graphs::Neo4jGraph; use crate::lang::{ @@ -107,7 +107,7 @@ impl Repo { .collect::>(); info!("Starting parse stage: libraries"); - self.process_libraries(&mut graph, &allowed_files)?; + timed_stage("libraries", || self.process_libraries(&mut graph, &allowed_files))?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -122,7 +122,7 @@ impl Repo { } info!("Starting parse stage: imports"); - self.process_import_sections(&mut graph, &filez)?; + timed_stage("imports", || self.process_import_sections(&mut graph, &filez))?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -137,7 +137,7 @@ impl Repo { } info!("Starting parse stage: variables"); - self.process_variables(&mut graph, &allowed_files)?; + timed_stage("variables", || self.process_variables(&mut graph, &allowed_files))?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -152,7 +152,7 @@ impl Repo { } info!("Starting parse stage: classes"); - let impl_relationships = self.process_classes(&mut graph, &allowed_files)?; + let impl_relationships = timed_stage("classes", || self.process_classes(&mut graph, &allowed_files))?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -167,7 +167,7 @@ impl Repo { } info!("Starting parse stage: instances_traits"); - self.process_instances_and_traits(&mut graph, &allowed_files)?; + timed_stage("instances_traits", || self.process_instances_and_traits(&mut graph, &allowed_files))?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -181,7 +181,7 @@ impl Repo { .await?; } info!("Starting parse stage: implements"); - self.resolve_implements_edges(&mut graph, impl_relationships)?; + timed_stage("implements", || self.resolve_implements_edges(&mut graph, impl_relationships))?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -196,7 +196,7 @@ impl Repo { } info!("Starting parse stage: data_models"); - self.process_data_models(&mut graph, &allowed_files)?; + timed_stage("data_models", || self.process_data_models(&mut graph, &allowed_files))?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -211,8 +211,9 @@ impl Repo { } info!("Starting parse stage: functions_tests"); - self.process_functions_and_tests(&mut graph, &allowed_files) - .await?; + timed_stage_async("functions_tests", + self.process_functions_and_tests(&mut graph, &allowed_files) + ).await?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -227,7 +228,7 @@ impl Repo { } info!("Starting parse stage: pages_templates"); - self.process_pages_and_templates(&mut graph, &filez)?; + timed_stage("pages_templates", || self.process_pages_and_templates(&mut graph, &filez))?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -242,7 +243,7 @@ impl Repo { } info!("Starting parse stage: endpoints"); - self.process_endpoints(&mut graph, &allowed_files)?; + timed_stage("endpoints", || self.process_endpoints(&mut graph, &allowed_files))?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -257,8 +258,9 @@ impl Repo { } info!("Starting parse stage: finalize"); - self.finalize_graph(&mut graph, &allowed_files, &mut stats) - .await?; + timed_stage_async("finalize", + self.finalize_graph(&mut graph, &allowed_files, &mut stats) + ).await?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -287,6 +289,7 @@ impl Repo { stats.insert("total_nodes".to_string(), num_of_nodes as usize); stats.insert("total_edges".to_string(), num_of_edges as usize); self.send_status_with_stats(stats); + crate::utils::log_and_reset_call_finder_stats(); Ok(graph) } @@ -825,7 +828,7 @@ impl Repo { Ok(()) } - #[instrument(skip(self, graph), fields(files=filez.len()))] + #[instrument(skip(self, graph, filez), fields(files=filez.len()))] async fn process_functions_and_tests( &self, graph: &mut G, @@ -989,7 +992,7 @@ impl Repo { Ok(()) } - #[instrument(skip(self, graph), fields(files=filez.len()))] + #[instrument(skip(self, graph, filez), fields(files=filez.len()))] fn process_endpoints(&self, graph: &mut G, filez: &[(String, String)]) -> Result<()> { self.send_status_update("process_endpoints", 11); let mut _i = 0; @@ -1050,7 +1053,7 @@ impl Repo { Ok(()) } - #[instrument(skip(self, graph, stats), fields(files=filez.len()))] + #[instrument(skip(self, graph, stats, filez), fields(files=filez.len()))] async fn finalize_graph( &self, graph: &mut G, diff --git a/ast/src/builder/utils.rs b/ast/src/builder/utils.rs index 1e7df0e55..9860a7daf 100644 --- a/ast/src/builder/utils.rs +++ b/ast/src/builder/utils.rs @@ -5,9 +5,26 @@ use crate::utils::create_node_key; use lsp::{strip_tmp, Language}; use std::collections::HashSet; use std::path::PathBuf; +use tracing::info; pub const MAX_FILE_SIZE: u64 = 500_000; +// Usage: `timed_stage("classes", || self.process_classes(&mut graph, &files))?;` +pub fn timed_stage T>(stage_name: &str, f: F) -> T { + let start = std::time::Instant::now(); + let result = f(); + info!("[perf][stage] {} took {}ms", stage_name, start.elapsed().as_millis()); + result +} + +// Usage: `timed_stage_async("finalize", self.finalize_graph(&mut graph, &files, &mut stats)).await?;` +pub async fn timed_stage_async>(stage_name: &str, f: F) -> T { + let start = std::time::Instant::now(); + let result = f.await; + info!("[perf][stage] {} took {}ms", stage_name, start.elapsed().as_millis()); + result +} + #[cfg(feature = "openssl")] pub fn filter_by_revs(root: &str, revs: Vec, graph: G, lang_kind: Language) -> G { if revs.is_empty() { diff --git a/ast/src/lang/call_finder.rs b/ast/src/lang/call_finder.rs index a3f90832c..0a6406793 100644 --- a/ast/src/lang/call_finder.rs +++ b/ast/src/lang/call_finder.rs @@ -1,6 +1,7 @@ use super::parse::utils::trim_quotes; use super::queries::consts::{IMPORTS_ALIAS, IMPORTS_FROM, IMPORTS_NAME}; use super::{graphs::Graph, *}; +use crate::utils::{record_call_finder_lookup, CallFinderStrategy}; use tree_sitter::QueryCursor; pub fn node_data_finder( @@ -46,16 +47,19 @@ pub fn func_target_file_finder( current_file, source_node_type, ) { + record_call_finder_lookup(start_time.elapsed().as_millis(), CallFinderStrategy::OnlyOne); return Some(tf); } // Second try: find in the same file if let Some(tf) = find_function_in_same_file(func_name, current_file, graph, source_start) { + record_call_finder_lookup(start_time.elapsed().as_millis(), CallFinderStrategy::SameFile); return Some(tf); } if let Some(import_names) = import_names { if let Some(tf) = find_function_by_import(func_name, import_names, graph) { + record_call_finder_lookup(start_time.elapsed().as_millis(), CallFinderStrategy::Import); return Some(tf); } } @@ -63,6 +67,7 @@ pub fn func_target_file_finder( // Fourth try: find in the same directory if let Some(tf) = find_function_in_same_directory(func_name, current_file, graph, source_start) { + record_call_finder_lookup(start_time.elapsed().as_millis(), CallFinderStrategy::SameDir); return Some(tf); } @@ -70,7 +75,7 @@ pub fn func_target_file_finder( if let Some(ref operand) = operand { if let Some(target_file) = find_function_with_operand(operand, func_name, graph) { if let Some(tf) = graph.find_node_by_name_and_file_contains(NodeType::Function, func_name, &target_file) { - println!("[OPERAND] resolved {}.{} in {}", operand, func_name, target_file); + record_call_finder_lookup(start_time.elapsed().as_millis(), CallFinderStrategy::Operand); return Some(tf); } } @@ -79,18 +84,12 @@ pub fn func_target_file_finder( // Sixth try: Check if function is nested in a variable (e.g., authOptions.callbacks.signIn) if let Some(ref operand) = operand { if let Some(tf) = find_nested_function_in_variable(operand, func_name, graph, current_file) { - let duration = start_time.elapsed(); - if duration.as_millis() > 100 { - tracing::warn!("[PERF] func_target_file_finder for '{}' took {}ms (found via nested)", func_name, duration.as_millis()); - } + record_call_finder_lookup(start_time.elapsed().as_millis(), CallFinderStrategy::NestedVar); return Some(tf); } } - let duration = start_time.elapsed(); - if duration.as_millis() > 100 { - tracing::warn!("[PERF] func_target_file_finder for '{}' took {}ms (not found)", func_name, duration.as_millis()); - } + record_call_finder_lookup(start_time.elapsed().as_millis(), CallFinderStrategy::NotFound); None } diff --git a/ast/src/lang/graphs/graph_ops.rs b/ast/src/lang/graphs/graph_ops.rs index e60a6c152..cc0459169 100644 --- a/ast/src/lang/graphs/graph_ops.rs +++ b/ast/src/lang/graphs/graph_ops.rs @@ -463,13 +463,13 @@ impl GraphOps { return Ok(vec![]); } - println!("collect_muted_nodes_for_files - input files: {:?}", files); + debug!("collect_muted_nodes_for_files - input files: {:?}", files); let muted_nodes = self.graph.get_muted_nodes_for_files_async(files).await?; if muted_nodes.is_empty() { - println!("No muted nodes found in {} files", files.len()); + debug!("No muted nodes found in {} files", files.len()); } else { - println!("Found {} muted nodes in {} files to preserve", muted_nodes.len(), files.len()); + debug!("Found {} muted nodes in {} files to preserve", muted_nodes.len(), files.len()); } Ok(muted_nodes) @@ -483,9 +483,9 @@ impl GraphOps { let restored_count = self.graph.restore_muted_nodes_async(&identifiers).await?; if restored_count > 0 { - println!("Successfully restored muted status for {} nodes after rebuild", restored_count); + info!("Restored muted status for {} nodes after rebuild", restored_count); } else { - println!("No nodes matched for muted status restoration ({} identifiers provided)", identifiers.len()); + debug!("No nodes matched for muted status restoration ({} identifiers provided)", identifiers.len()); } Ok(restored_count) diff --git a/ast/src/lang/graphs/neo4j/executor.rs b/ast/src/lang/graphs/neo4j/executor.rs index 757bad805..885fd9df1 100644 --- a/ast/src/lang/graphs/neo4j/executor.rs +++ b/ast/src/lang/graphs/neo4j/executor.rs @@ -3,6 +3,7 @@ use shared::Result; use crate::lang::{Edge, NodeData, NodeType, graphs::{queries::*, helpers::*}}; use crate::lang::graphs::helpers::MutedNodeIdentifier; use std::str::FromStr; +use tracing::debug; fn bind_parameters(query_str: &str, params: BoltMap) -> Query { let mut query_obj = query(query_str); @@ -161,7 +162,7 @@ pub async fn execute_batch(conn: &Neo4jConnection, queries: Vec<(String, BoltMap .collect(); for (i, chunk) in chunked_queries.into_iter().enumerate() { - println!("Processing chunk {}/{}", i + 1, total_chunks); + debug!("Processing chunk {}/{}", i + 1, total_chunks); let mut txn_manager = TransactionManager::new(conn); for query in chunk { @@ -169,11 +170,11 @@ pub async fn execute_batch(conn: &Neo4jConnection, queries: Vec<(String, BoltMap } if let Err(e) = txn_manager.execute().await { - println!("Error executing batch chunk {}: {:?}", i + 1, e); + tracing::error!("Error executing batch chunk {}: {:?}", i + 1, e); return Err(e); } - println!("Successfully committed chunk {}/{}", i + 1, total_chunks); + debug!("Successfully committed chunk {}/{}", i + 1, total_chunks); } Ok(()) } @@ -184,13 +185,13 @@ pub async fn execute_queries_simple( ) -> Result<()> { let total_queries = queries.len(); for (i, query) in queries.into_iter().enumerate() { - println!("Processing query {}/{}", i + 1, total_queries); + debug!("Processing query {}/{}", i + 1, total_queries); let mut txn_manager = TransactionManager::new(conn); txn_manager.add_query(query); txn_manager.execute().await?; - println!("Successfully executed query {}/{}", i + 1, total_queries); + debug!("Successfully executed query {}/{}", i + 1, total_queries); } Ok(()) } @@ -203,7 +204,7 @@ pub async fn execute_node_query( execute_query(conn, query_str, params, extract_node_data) .await .unwrap_or_else(|e| { - println!("Error executing query: {}", e); + debug!("Error executing query: {}", e); Vec::new() }) } @@ -216,7 +217,7 @@ pub async fn execute_nodes_with_coverage_query( execute_query(conn, query_str, params, extract_coverage_data) .await .unwrap_or_else(|e| { - eprintln!("Error executing nodes with coverage query: {}", e); + debug!("Error executing nodes with coverage query: {}", e); Vec::new() }) } diff --git a/ast/src/repo.rs b/ast/src/repo.rs index 5ebc9937d..145992474 100644 --- a/ast/src/repo.rs +++ b/ast/src/repo.rs @@ -13,7 +13,7 @@ use shared::{Context, Error, Result}; use std::str::FromStr; use std::{fs, path::PathBuf}; use tokio::sync::broadcast::Sender; -use tracing::{info, instrument, warn}; +use tracing::{debug, info, instrument, warn}; use walkdir::{DirEntry, WalkDir}; const CONF_FILE_PATH: &str = ".ast.json"; @@ -141,7 +141,7 @@ impl Repos { } let (nodes_size, edges_size) = graph.get_graph_size(); - println!("Final Graph: {} nodes and {} edges", nodes_size, edges_size); + info!("Final Graph: {} nodes and {} edges", nodes_size, edges_size); Ok(graph) } @@ -229,7 +229,7 @@ impl Repo { Error::Custom(format!("Failed to parse Git URL for {}: {}", url, e)) })?; let root = format!("/tmp/{}", gurl.fullname); - println!( + info!( "Cloning repo to {:?} with branch {}...", &root, branch.unwrap_or("default") @@ -341,7 +341,7 @@ impl Repo { skip_calls: false, }); } - println!("REPOS!!! {:?}", repos); + debug!("REPOS detected: {:?}", repos); Ok(Repos(repos)) } pub async fn new_clone_to_tmp( @@ -358,7 +358,7 @@ impl Repo { let gurl = GitUrl::parse(url)?; let root = format!("/tmp/{}", gurl.fullname); - println!("Cloning to {:?}... lsp: {}", &root, lsp); + info!("Cloning to {:?}... lsp: {}", &root, lsp); clone_repo(url, &root, username, pat, None, branch).await?; // if let Some(new_files) = check_revs(&root, revs) { // files_filter = new_files; diff --git a/ast/src/utils.rs b/ast/src/utils.rs index e25912729..e7c7fa711 100644 --- a/ast/src/utils.rs +++ b/ast/src/utils.rs @@ -9,6 +9,37 @@ use std::fs::File; use std::io::{BufWriter, Write}; use tracing_subscriber::filter::LevelFilter; use tracing_subscriber::EnvFilter; +use std::cell::RefCell; + +#[derive(Debug, Clone, Copy)] +pub enum CallFinderStrategy { + OnlyOne, + SameFile, + Import, + SameDir, + Operand, + NestedVar, + NotFound, +} + +#[derive(Default, Debug)] +pub struct CallFinderStats { + pub total_lookups: usize, + pub total_time_ms: u128, + pub only_one_hits: usize, + pub same_file_hits: usize, + pub import_hits: usize, + pub same_dir_hits: usize, + pub operand_hits: usize, + pub nested_var_hits: usize, + pub not_found: usize, +} + +thread_local! { + static CALL_FINDER_STATS: RefCell = RefCell::new(CallFinderStats::default()); +} + + pub fn print_json(graph: &G, name: &str) -> Result<()> { let print_root = std::env::var("PRINT_ROOT").unwrap_or_else(|_| "ast/examples".to_string()); @@ -119,8 +150,6 @@ pub fn create_node_key(node: &Node) -> String { } pub fn get_use_lsp() -> bool { - println!("===-==> Getting use LSP"); - unsafe { env::set_var("LSP_SKIP_POST_CLONE", "true") }; delete_react_testing_node_modules().ok(); @@ -228,3 +257,44 @@ where { tokio::task::block_in_place(|| tokio::runtime::Handle::current().block_on(async_fn())) } + +pub fn record_call_finder_lookup(elapsed_ms: u128, strategy: CallFinderStrategy) { + CALL_FINDER_STATS.with(|stats| { + let mut s = stats.borrow_mut(); + s.total_lookups += 1; + s.total_time_ms += elapsed_ms; + match strategy { + CallFinderStrategy::OnlyOne => s.only_one_hits += 1, + CallFinderStrategy::SameFile => s.same_file_hits += 1, + CallFinderStrategy::Import => s.import_hits += 1, + CallFinderStrategy::SameDir => s.same_dir_hits += 1, + CallFinderStrategy::Operand => s.operand_hits += 1, + CallFinderStrategy::NestedVar => s.nested_var_hits += 1, + CallFinderStrategy::NotFound => s.not_found += 1, + } + }); +} + + + +pub fn log_and_reset_call_finder_stats() { + CALL_FINDER_STATS.with(|stats| { + let s = stats.borrow(); + if s.total_lookups > 0 { + tracing::info!( + "[perf][call_finder] lookups={} time_ms={} only_one={} same_file={} import={} same_dir={} operand={} nested={} not_found={}", + s.total_lookups, + s.total_time_ms, + s.only_one_hits, + s.same_file_hits, + s.import_hits, + s.same_dir_hits, + s.operand_hits, + s.nested_var_hits, + s.not_found + ); + } + drop(s); + *stats.borrow_mut() = CallFinderStats::default(); + }); +} From 2253a2fc1917545d66c8c8d1572089336006e563 Mon Sep 17 00:00:00 2001 From: kelmith Date: Thu, 25 Dec 2025 22:42:10 +0530 Subject: [PATCH 5/6] detailed analysis of call_finder methods --- ast/src/builder/core.rs | 64 ++++++---- ast/src/lang/call_finder.rs | 86 ++++++++++--- ast/src/lang/graphs/graph_ops.rs | 1 - ast/src/lang/parse/format.rs | 83 ++++++++---- ast/src/utils.rs | 209 +++++++++++++++++++++++++++---- 5 files changed, 354 insertions(+), 89 deletions(-) diff --git a/ast/src/builder/core.rs b/ast/src/builder/core.rs index f68564d1c..1b90daee5 100644 --- a/ast/src/builder/core.rs +++ b/ast/src/builder/core.rs @@ -107,7 +107,9 @@ impl Repo { .collect::>(); info!("Starting parse stage: libraries"); - timed_stage("libraries", || self.process_libraries(&mut graph, &allowed_files))?; + timed_stage("libraries", || { + self.process_libraries(&mut graph, &allowed_files) + })?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -122,7 +124,9 @@ impl Repo { } info!("Starting parse stage: imports"); - timed_stage("imports", || self.process_import_sections(&mut graph, &filez))?; + timed_stage("imports", || { + self.process_import_sections(&mut graph, &filez) + })?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -137,7 +141,9 @@ impl Repo { } info!("Starting parse stage: variables"); - timed_stage("variables", || self.process_variables(&mut graph, &allowed_files))?; + timed_stage("variables", || { + self.process_variables(&mut graph, &allowed_files) + })?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -152,7 +158,9 @@ impl Repo { } info!("Starting parse stage: classes"); - let impl_relationships = timed_stage("classes", || self.process_classes(&mut graph, &allowed_files))?; + let impl_relationships = timed_stage("classes", || { + self.process_classes(&mut graph, &allowed_files) + })?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -167,7 +175,9 @@ impl Repo { } info!("Starting parse stage: instances_traits"); - timed_stage("instances_traits", || self.process_instances_and_traits(&mut graph, &allowed_files))?; + timed_stage("instances_traits", || { + self.process_instances_and_traits(&mut graph, &allowed_files) + })?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -181,7 +191,9 @@ impl Repo { .await?; } info!("Starting parse stage: implements"); - timed_stage("implements", || self.resolve_implements_edges(&mut graph, impl_relationships))?; + timed_stage("implements", || { + self.resolve_implements_edges(&mut graph, impl_relationships) + })?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -196,7 +208,9 @@ impl Repo { } info!("Starting parse stage: data_models"); - timed_stage("data_models", || self.process_data_models(&mut graph, &allowed_files))?; + timed_stage("data_models", || { + self.process_data_models(&mut graph, &allowed_files) + })?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -211,9 +225,11 @@ impl Repo { } info!("Starting parse stage: functions_tests"); - timed_stage_async("functions_tests", - self.process_functions_and_tests(&mut graph, &allowed_files) - ).await?; + timed_stage_async( + "functions_tests", + self.process_functions_and_tests(&mut graph, &allowed_files), + ) + .await?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -228,7 +244,9 @@ impl Repo { } info!("Starting parse stage: pages_templates"); - timed_stage("pages_templates", || self.process_pages_and_templates(&mut graph, &filez))?; + timed_stage("pages_templates", || { + self.process_pages_and_templates(&mut graph, &filez) + })?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -243,7 +261,9 @@ impl Repo { } info!("Starting parse stage: endpoints"); - timed_stage("endpoints", || self.process_endpoints(&mut graph, &allowed_files))?; + timed_stage("endpoints", || { + self.process_endpoints(&mut graph, &allowed_files) + })?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -258,9 +278,11 @@ impl Repo { } info!("Starting parse stage: finalize"); - timed_stage_async("finalize", - self.finalize_graph(&mut graph, &allowed_files, &mut stats) - ).await?; + timed_stage_async( + "finalize", + self.finalize_graph(&mut graph, &allowed_files, &mut stats), + ) + .await?; #[cfg(feature = "neo4j")] if let Some(ctx) = &mut streaming_ctx { let all_nodes = graph.get_all_nodes(); @@ -289,7 +311,6 @@ impl Repo { stats.insert("total_nodes".to_string(), num_of_nodes as usize); stats.insert("total_edges".to_string(), num_of_edges as usize); self.send_status_with_stats(stats); - crate::utils::log_and_reset_call_finder_stats(); Ok(graph) } @@ -719,7 +740,7 @@ impl Repo { let classes = graph.find_nodes_by_type(NodeType::Class); let traits = graph.find_nodes_by_type(NodeType::Trait); - + let mut classes_by_file: HashMap<&str, Vec<&NodeData>> = HashMap::new(); for class in &classes { classes_by_file @@ -756,9 +777,7 @@ impl Repo { let trait_node = traits_by_file .get(rel.file_path.as_str()) .and_then(|traits| traits.iter().find(|t| t.name == rel.trait_name).copied()) - .or_else(|| { - traits.iter().find(|t| t.name == rel.trait_name) - }); + .or_else(|| traits.iter().find(|t| t.name == rel.trait_name)); if let (Some(class), Some(trait_)) = (class_node, trait_node) { graph.add_edge(Edge::implements(class, trait_)); @@ -856,7 +875,7 @@ impl Repo { function_count += funcs.len(); graph.add_functions(funcs); - + test_count += tests.len(); graph.add_tests(tests); } @@ -1146,6 +1165,9 @@ impl Repo { graph.filter_out_nodes_without_children(parent_type, child_type, child_meta_key); }); + crate::utils::log_and_reset_call_finder_stats(); + crate::utils::log_and_reset_import_stats(); + Ok(()) } } diff --git a/ast/src/lang/call_finder.rs b/ast/src/lang/call_finder.rs index 0a6406793..53cba988c 100644 --- a/ast/src/lang/call_finder.rs +++ b/ast/src/lang/call_finder.rs @@ -40,6 +40,7 @@ pub fn func_target_file_finder( )); // First try: find only one function file + let strategy_start = std::time::Instant::now(); if let Some(tf) = find_only_one_function_file( func_name, graph, @@ -47,35 +48,68 @@ pub fn func_target_file_finder( current_file, source_node_type, ) { - record_call_finder_lookup(start_time.elapsed().as_millis(), CallFinderStrategy::OnlyOne); + let strategy_time = strategy_start.elapsed().as_millis(); + record_call_finder_lookup( + start_time.elapsed().as_millis(), + CallFinderStrategy::OnlyOne, + strategy_time, + ); return Some(tf); } // Second try: find in the same file + let strategy_start = std::time::Instant::now(); if let Some(tf) = find_function_in_same_file(func_name, current_file, graph, source_start) { - record_call_finder_lookup(start_time.elapsed().as_millis(), CallFinderStrategy::SameFile); + let strategy_time = strategy_start.elapsed().as_millis(); + record_call_finder_lookup( + start_time.elapsed().as_millis(), + CallFinderStrategy::SameFile, + strategy_time, + ); return Some(tf); } if let Some(import_names) = import_names { + let strategy_start = std::time::Instant::now(); if let Some(tf) = find_function_by_import(func_name, import_names, graph) { - record_call_finder_lookup(start_time.elapsed().as_millis(), CallFinderStrategy::Import); + let strategy_time = strategy_start.elapsed().as_millis(); + record_call_finder_lookup( + start_time.elapsed().as_millis(), + CallFinderStrategy::Import, + strategy_time, + ); return Some(tf); } } // Fourth try: find in the same directory + let strategy_start = std::time::Instant::now(); if let Some(tf) = find_function_in_same_directory(func_name, current_file, graph, source_start) { - record_call_finder_lookup(start_time.elapsed().as_millis(), CallFinderStrategy::SameDir); + let strategy_time = strategy_start.elapsed().as_millis(); + record_call_finder_lookup( + start_time.elapsed().as_millis(), + CallFinderStrategy::SameDir, + strategy_time, + ); return Some(tf); } // Fifth try: If operand exists, try operand-based resolution if let Some(ref operand) = operand { + let strategy_start = std::time::Instant::now(); if let Some(target_file) = find_function_with_operand(operand, func_name, graph) { - if let Some(tf) = graph.find_node_by_name_and_file_contains(NodeType::Function, func_name, &target_file) { - record_call_finder_lookup(start_time.elapsed().as_millis(), CallFinderStrategy::Operand); + if let Some(tf) = graph.find_node_by_name_and_file_contains( + NodeType::Function, + func_name, + &target_file, + ) { + let strategy_time = strategy_start.elapsed().as_millis(); + record_call_finder_lookup( + start_time.elapsed().as_millis(), + CallFinderStrategy::Operand, + strategy_time, + ); return Some(tf); } } @@ -83,13 +117,21 @@ pub fn func_target_file_finder( // Sixth try: Check if function is nested in a variable (e.g., authOptions.callbacks.signIn) if let Some(ref operand) = operand { - if let Some(tf) = find_nested_function_in_variable(operand, func_name, graph, current_file) { - record_call_finder_lookup(start_time.elapsed().as_millis(), CallFinderStrategy::NestedVar); + let strategy_start = std::time::Instant::now(); + if let Some(tf) = find_nested_function_in_variable(operand, func_name, graph, current_file) + { + let strategy_time = strategy_start.elapsed().as_millis(); + record_call_finder_lookup( + start_time.elapsed().as_millis(), + CallFinderStrategy::NestedVar, + strategy_time, + ); return Some(tf); } } - record_call_finder_lookup(start_time.elapsed().as_millis(), CallFinderStrategy::NotFound); + let total_time = start_time.elapsed().as_millis(); + record_call_finder_lookup(total_time, CallFinderStrategy::NotFound, total_time); None } @@ -157,9 +199,13 @@ pub fn get_imports_for_file( let duration = start_time.elapsed(); if duration.as_millis() > 50 { - tracing::warn!("[PERF] get_imports_for_file for '{}' took {}ms", current_file, duration.as_millis()); + tracing::warn!( + "[PERF] get_imports_for_file for '{}' took {}ms", + current_file, + duration.as_millis() + ); } - + if results.is_empty() { None } else { @@ -227,13 +273,21 @@ fn find_only_one_function_file( log_cmd(format!("::: discluded mocks for!!! {:?}", func_name)); let duration = start_time.elapsed(); if duration.as_millis() > 50 { - tracing::warn!("[PERF] find_only_one_function_file for '{}' took {}ms", func_name, duration.as_millis()); + tracing::warn!( + "[PERF] find_only_one_function_file for '{}' took {}ms", + func_name, + duration.as_millis() + ); } return Some(target_files_starts[0].clone()); } let duration = start_time.elapsed(); if duration.as_millis() > 50 { - tracing::warn!("[PERF] find_only_one_function_file for '{}' took {}ms", func_name, duration.as_millis()); + tracing::warn!( + "[PERF] find_only_one_function_file for '{}' took {}ms", + func_name, + duration.as_millis() + ); } None } @@ -275,12 +329,12 @@ fn find_nested_function_in_variable( if var_nodes.is_empty() { return None; } - + let func_nodes = graph.find_nodes_by_name(NodeType::Function, func_name); if func_nodes.is_empty() { return None; } - + for func in func_nodes.clone() { if let Some(nested_in) = func.meta.get("nested_in") { if nested_in == var_name { @@ -288,7 +342,7 @@ fn find_nested_function_in_variable( } } } - + None } diff --git a/ast/src/lang/graphs/graph_ops.rs b/ast/src/lang/graphs/graph_ops.rs index cc0459169..b8adbe417 100644 --- a/ast/src/lang/graphs/graph_ops.rs +++ b/ast/src/lang/graphs/graph_ops.rs @@ -5,7 +5,6 @@ use shared::error::{Error, Result}; use tokio::sync::broadcast::Sender; use tracing::{debug, error, info, instrument}; - use crate::lang::embedding::{vectorize_code_document, vectorize_query}; use crate::lang::graphs::{graph::Graph, helpers::MutedNodeIdentifier }; use crate::lang::graphs::{BTreeMapGraph, Neo4jGraph}; diff --git a/ast/src/lang/parse/format.rs b/ast/src/lang/parse/format.rs index b68d832db..c3954bafb 100644 --- a/ast/src/lang/parse/format.rs +++ b/ast/src/lang/parse/format.rs @@ -346,9 +346,14 @@ impl Lang { let p = node.start_position(); handler_position = Some(Position::new(file, p.row as u32, p.column as u32)?); - let method = endp.meta.get("verb").unwrap_or(&"unknown".to_string()).clone(); + let method = endp + .meta + .get("verb") + .unwrap_or(&"unknown".to_string()) + .clone(); let path = endp.name.clone(); - if let Some(generated_name) = self.lang.generate_arrow_handler_name(&method, &path) { + if let Some(generated_name) = self.lang.generate_arrow_handler_name(&method, &path) + { endp.add_handler(&generated_name); } } else if o == HANDLER_ACTIONS_ARRAY { @@ -370,7 +375,8 @@ impl Lang { params.item = Some(HandlerItem::new_resource_member(trim_quotes(&body))); } else if o == SINGULAR_RESOURCE { // Singular resource: mark endpoint to omit :id in paths - endp.meta.insert("is_singular".to_string(), "true".to_string()); + endp.meta + .insert("is_singular".to_string(), "true".to_string()); let handler_name = trim_quotes(&body); endp.add_handler(&handler_name); } @@ -517,7 +523,7 @@ impl Lang { } } } - + Ok(vec![(endp, handler)]) } pub fn format_data_model( @@ -587,12 +593,12 @@ impl Lang { Ok(Some(( func, - None, // parent - Vec::new(), // requests_within - Vec::new(), // models - None, // trait_operand - Vec::new(), // return_types - Vec::new(), // nested_in + None, // parent + Vec::new(), // requests_within + Vec::new(), // models + None, // trait_operand + Vec::new(), // return_types + Vec::new(), // nested_in ))) } else { Ok(None) @@ -881,11 +887,11 @@ impl Lang { lsp_tx, )?; } - + if is_macro { func.add_macro(); } - + log_cmd(format!("found function {} in file {}", func.name, file)); Ok(Some(( func, @@ -940,7 +946,7 @@ impl Lang { let mut class_call = None; let mut call_name_and_point = None; let mut is_variable_call = false; - + Self::loop_captures(q, &m, code, |body, node, o| { if o == FUNCTION_NAME { call_name_and_point = Some((body, node.start_position())); @@ -978,7 +984,7 @@ impl Lang { // REMOVED: is_variable_call gate that was blocking lowercase operand calls // Now we'll try to resolve them via operand-based resolution - + if self.lang.should_skip_function_call(&called, &fc.operand) { return Ok(None); } @@ -1010,10 +1016,16 @@ impl Lang { external_func = Some(t); } } else { - let import_names = get_imports_for_file(file, self, graph); - if let Some(one_func) = - node_data_finder(&called, &fc.operand, graph, file, fc.source.start, NodeType::Function, import_names) - { + let import_names = get_imports_for_file(file, self, graph); + if let Some(one_func) = node_data_finder( + &called, + &fc.operand, + graph, + file, + fc.source.start, + NodeType::Function, + import_names, + ) { log_cmd(format!( "==> ? ONE target for {:?} {}", called, &one_func.file @@ -1068,23 +1080,44 @@ impl Lang { // } else if let Some(tf) = func_target_file_finder(&body, &fc.operand, graph) { // fc.target = NodeKeys::new(&body, &tf); } else if allow_unverified { + tracing::debug!("[call_resolution] Using allow_unverified for {}", called); fc.target = NodeKeys::new(&called, "unverified", call_point.row as usize); } else { // FALLBACK to find? - let import_names = get_imports_for_file(file, self, graph); - if let Some(tf) = - node_data_finder(&called, &fc.operand, graph, file, fc.source.start, NodeType::Function, import_names) - { + tracing::debug!( + "[call_resolution] No LSP, allow_unverified=false, calling node_data_finder for {}", + called + ); + let import_start = std::time::Instant::now(); + let import_names = get_imports_for_file(file, self, graph); + crate::utils::record_import_parse(file, import_start.elapsed().as_millis()); + if let Some(tf) = node_data_finder( + &called, + &fc.operand, + graph, + file, + fc.source.start, + NodeType::Function, + import_names, + ) { log_cmd(format!( "==> ? (no lsp) ONE target for {:?} {}", called, &tf.file )); fc.target = tf.into(); } else if let Some(ref operand) = fc.operand { + let import_start = std::time::Instant::now(); let import_names_for_operand = get_imports_for_file(file, self, graph); - if let Some(base_func) = - node_data_finder(operand, &None, graph, file, fc.source.start, NodeType::Function, import_names_for_operand) - { + crate::utils::record_import_parse(file, import_start.elapsed().as_millis()); + if let Some(base_func) = node_data_finder( + operand, + &None, + graph, + file, + fc.source.start, + NodeType::Function, + import_names_for_operand, + ) { log_cmd(format!( "==> ? (member expr) resolved base object {:?} in {}", operand, &base_func.file diff --git a/ast/src/utils.rs b/ast/src/utils.rs index e7c7fa711..fc9cdf8a1 100644 --- a/ast/src/utils.rs +++ b/ast/src/utils.rs @@ -5,11 +5,11 @@ use crate::lang::graphs::{ArrayGraph, Node}; use crate::lang::{BTreeMapGraph, Graph, NodeRef}; use serde::Serialize; use shared::Result; +use std::cell::RefCell; use std::fs::File; use std::io::{BufWriter, Write}; use tracing_subscriber::filter::LevelFilter; use tracing_subscriber::EnvFilter; -use std::cell::RefCell; #[derive(Debug, Clone, Copy)] pub enum CallFinderStrategy { @@ -26,21 +26,36 @@ pub enum CallFinderStrategy { pub struct CallFinderStats { pub total_lookups: usize, pub total_time_ms: u128, + // Per-strategy hits and timing pub only_one_hits: usize, + pub only_one_time_ms: u128, pub same_file_hits: usize, + pub same_file_time_ms: u128, pub import_hits: usize, + pub import_time_ms: u128, pub same_dir_hits: usize, + pub same_dir_time_ms: u128, pub operand_hits: usize, + pub operand_time_ms: u128, pub nested_var_hits: usize, + pub nested_var_time_ms: u128, pub not_found: usize, + pub not_found_time_ms: u128, +} + +// Track import parsing separately +#[derive(Default, Debug)] +pub struct ImportParseStats { + pub total_calls: usize, + pub total_time_ms: u128, + pub file_times: std::collections::HashMap, // (call_count, total_ms) } thread_local! { static CALL_FINDER_STATS: RefCell = RefCell::new(CallFinderStats::default()); + static IMPORT_PARSE_STATS: RefCell = RefCell::new(ImportParseStats::default()); } - - pub fn print_json(graph: &G, name: &str) -> Result<()> { let print_root = std::env::var("PRINT_ROOT").unwrap_or_else(|_| "ast/examples".to_string()); use serde_jsonlines::write_json_lines; @@ -130,12 +145,12 @@ pub fn create_node_key(node: &Node) -> String { truncated_result.push_str(&sanitize_string(file)); truncated_result.push('-'); truncated_result.push_str(&sanitize_string(&start)); - + if let Some(v) = meta.get("verb") { truncated_result.push('-'); truncated_result.push_str(&sanitize_string(v)); } - + if truncated_result.len() > 5000 { truncated_result.truncate(5000); } @@ -151,7 +166,7 @@ pub fn create_node_key(node: &Node) -> String { pub fn get_use_lsp() -> bool { unsafe { env::set_var("LSP_SKIP_POST_CLONE", "true") }; - + delete_react_testing_node_modules().ok(); let lsp = env::var("USE_LSP").unwrap_or_else(|_| "false".to_string()); if lsp == "true" || lsp == "1" { @@ -213,12 +228,12 @@ pub fn create_node_key_from_ref(node_ref: &NodeRef) -> String { truncated_result.push_str(&sanitize_string(file)); truncated_result.push('-'); truncated_result.push_str(&sanitize_string(&start)); - + if let Some(v) = &node_ref.node_data.verb { truncated_result.push('-'); truncated_result.push_str(&sanitize_string(v)); } - + if truncated_result.len() > 5000 { truncated_result.truncate(5000); } @@ -258,43 +273,185 @@ where tokio::task::block_in_place(|| tokio::runtime::Handle::current().block_on(async_fn())) } -pub fn record_call_finder_lookup(elapsed_ms: u128, strategy: CallFinderStrategy) { +pub fn record_call_finder_lookup( + total_elapsed_ms: u128, + strategy: CallFinderStrategy, + strategy_time_ms: u128, +) { CALL_FINDER_STATS.with(|stats| { let mut s = stats.borrow_mut(); s.total_lookups += 1; - s.total_time_ms += elapsed_ms; + s.total_time_ms += total_elapsed_ms; match strategy { - CallFinderStrategy::OnlyOne => s.only_one_hits += 1, - CallFinderStrategy::SameFile => s.same_file_hits += 1, - CallFinderStrategy::Import => s.import_hits += 1, - CallFinderStrategy::SameDir => s.same_dir_hits += 1, - CallFinderStrategy::Operand => s.operand_hits += 1, - CallFinderStrategy::NestedVar => s.nested_var_hits += 1, - CallFinderStrategy::NotFound => s.not_found += 1, + CallFinderStrategy::OnlyOne => { + s.only_one_hits += 1; + s.only_one_time_ms += strategy_time_ms; + } + CallFinderStrategy::SameFile => { + s.same_file_hits += 1; + s.same_file_time_ms += strategy_time_ms; + } + CallFinderStrategy::Import => { + s.import_hits += 1; + s.import_time_ms += strategy_time_ms; + } + CallFinderStrategy::SameDir => { + s.same_dir_hits += 1; + s.same_dir_time_ms += strategy_time_ms; + } + CallFinderStrategy::Operand => { + s.operand_hits += 1; + s.operand_time_ms += strategy_time_ms; + } + CallFinderStrategy::NestedVar => { + s.nested_var_hits += 1; + s.nested_var_time_ms += strategy_time_ms; + } + CallFinderStrategy::NotFound => { + s.not_found += 1; + s.not_found_time_ms += strategy_time_ms; + } } }); } +pub fn record_import_parse(file: &str, elapsed_ms: u128) { + IMPORT_PARSE_STATS.with(|stats| { + let mut s = stats.borrow_mut(); + s.total_calls += 1; + s.total_time_ms += elapsed_ms; + // Extract just the filename for cleaner output + let filename = file.rsplit('/').next().unwrap_or(file); + let entry = s.file_times.entry(filename.to_string()).or_insert((0, 0)); + entry.0 += 1; + entry.1 += elapsed_ms; + }); +} pub fn log_and_reset_call_finder_stats() { CALL_FINDER_STATS.with(|stats| { let s = stats.borrow(); if s.total_lookups > 0 { tracing::info!( - "[perf][call_finder] lookups={} time_ms={} only_one={} same_file={} import={} same_dir={} operand={} nested={} not_found={}", + "[perf][call_finder] Analyzed {} function calls in {}ms", s.total_lookups, - s.total_time_ms, - s.only_one_hits, - s.same_file_hits, - s.import_hits, - s.same_dir_hits, - s.operand_hits, - s.nested_var_hits, - s.not_found + s.total_time_ms ); + + // Helper to calculate percentage + let pct = |ms: u128| { + if s.total_time_ms > 0 { + (ms as f64 / s.total_time_ms as f64 * 100.0) as u32 + } else { + 0 + } + }; + + // Show each strategy with timing + if s.only_one_hits > 0 { + tracing::info!( + "[perf][call_finder] • only_one: {} hits ({}ms, {}%)", + s.only_one_hits, + s.only_one_time_ms, + pct(s.only_one_time_ms) + ); + } + if s.same_file_hits > 0 { + tracing::info!( + "[perf][call_finder] • same_file: {} hits ({}ms, {}%)", + s.same_file_hits, + s.same_file_time_ms, + pct(s.same_file_time_ms) + ); + } + if s.import_hits > 0 { + tracing::info!( + "[perf][call_finder] • import: {} hits ({}ms, {}%)", + s.import_hits, + s.import_time_ms, + pct(s.import_time_ms) + ); + } + if s.same_dir_hits > 0 { + tracing::info!( + "[perf][call_finder] • same_dir: {} hits ({}ms, {}%)", + s.same_dir_hits, + s.same_dir_time_ms, + pct(s.same_dir_time_ms) + ); + } + if s.operand_hits > 0 { + tracing::info!( + "[perf][call_finder] • operand: {} hits ({}ms, {}%)", + s.operand_hits, + s.operand_time_ms, + pct(s.operand_time_ms) + ); + } + if s.nested_var_hits > 0 { + tracing::info!( + "[perf][call_finder] • nested_var: {} hits ({}ms, {}%)", + s.nested_var_hits, + s.nested_var_time_ms, + pct(s.nested_var_time_ms) + ); + } + if s.not_found > 0 { + let marker = if pct(s.not_found_time_ms) > 50 { + " ← bottleneck" + } else { + "" + }; + tracing::info!( + "[perf][call_finder] • not_found: {} hits ({}ms, {}%){}", + s.not_found, + s.not_found_time_ms, + pct(s.not_found_time_ms), + marker + ); + } } drop(s); *stats.borrow_mut() = CallFinderStats::default(); }); } + +pub fn log_and_reset_import_stats() { + IMPORT_PARSE_STATS.with(|stats| { + let s = stats.borrow(); + if s.total_calls > 0 { + let unique_count = s.file_times.len(); + tracing::info!( + "[perf][imports] Parsed {} files ({} unique) in {}ms", + s.total_calls, + unique_count, + s.total_time_ms + ); + + // Sort files by total time descending + let mut files: Vec<_> = s.file_times.iter().collect(); + files.sort_by(|a, b| b.1 .1.cmp(&a.1 .1)); + + // Show top 5 files + for (filename, (count, total_ms)) in files.iter().take(5) { + let pct = if s.total_time_ms > 0 { + (*total_ms as f64 / s.total_time_ms as f64 * 100.0) as u32 + } else { + 0 + }; + let marker = if pct > 30 { " ← bottleneck" } else { "" }; + tracing::info!( + "[perf][imports] • {}: {}× calls, {}ms ({}%){}", + filename, + count, + total_ms, + pct, + marker + ); + } + } + drop(s); + *stats.borrow_mut() = ImportParseStats::default(); + }); +} From 912bcd64805235e7f6c060dd77d0dac68b428a86 Mon Sep 17 00:00:00 2001 From: kelmith Date: Thu, 25 Dec 2025 23:51:38 +0530 Subject: [PATCH 6/6] fix: cache the get_import_for_file results --- Cargo.lock | 21 ++++++++++++++++++++ ast/Cargo.toml | 1 + ast/src/lang/call_finder.rs | 38 +++++++++++++++++++++++++----------- ast/src/lang/parse/format.rs | 4 ---- ast/src/utils.rs | 34 +++++++++++++++++++++++++------- 5 files changed, 76 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3acd389b3..ee07e80c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -149,6 +149,7 @@ version = "0.1.0" dependencies = [ "anyhow", "convert_case", + "dashmap", "fastembed", "futures", "git-url-parse", @@ -1410,6 +1411,20 @@ dependencies = [ "serde", ] +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "data-encoding" version = "2.9.0" @@ -2114,6 +2129,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "hashbrown" version = "0.15.5" diff --git a/ast/Cargo.toml b/ast/Cargo.toml index 4f26b0b87..397064dc2 100644 --- a/ast/Cargo.toml +++ b/ast/Cargo.toml @@ -67,6 +67,7 @@ futures = "0.3.31" tiktoken-rs = "0.7.0" ignore = "0.4.23" fastembed = { version = "5.2.0", optional = true } +dashmap = "6.1.0" [[example]] diff --git a/ast/src/lang/call_finder.rs b/ast/src/lang/call_finder.rs index 53cba988c..791548bc8 100644 --- a/ast/src/lang/call_finder.rs +++ b/ast/src/lang/call_finder.rs @@ -1,9 +1,14 @@ use super::parse::utils::trim_quotes; use super::queries::consts::{IMPORTS_ALIAS, IMPORTS_FROM, IMPORTS_NAME}; use super::{graphs::Graph, *}; -use crate::utils::{record_call_finder_lookup, CallFinderStrategy}; +use crate::utils::{record_call_finder_lookup, record_import_parse, CallFinderStrategy}; +use dashmap::DashMap; +use std::sync::LazyLock; use tree_sitter::QueryCursor; +static IMPORT_CACHE: LazyLock)>>>> = + LazyLock::new(|| DashMap::new()); + pub fn node_data_finder( func_name: &str, operand: &Option, @@ -140,7 +145,27 @@ pub fn get_imports_for_file( lang: &Lang, graph: &G, ) -> Option)>> { - let start_time = std::time::Instant::now(); + let cache_start = std::time::Instant::now(); + + if let Some(cached) = IMPORT_CACHE.get(current_file) { + record_import_parse(current_file, cache_start.elapsed().as_millis(), true); + return cached.clone(); + } + + let result = parse_imports_for_file(current_file, lang, graph); + let total_time = cache_start.elapsed().as_millis(); + + IMPORT_CACHE.insert(current_file.to_string(), result.clone()); + record_import_parse(current_file, total_time, false); + + result +} + +fn parse_imports_for_file( + current_file: &str, + lang: &Lang, + graph: &G, +) -> Option)>> { let import_nodes = graph.find_nodes_by_file_ends_with(NodeType::Import, current_file); let import_node = import_nodes.first()?; let code = import_node.body.as_str(); @@ -197,15 +222,6 @@ pub fn get_imports_for_file( } } - let duration = start_time.elapsed(); - if duration.as_millis() > 50 { - tracing::warn!( - "[PERF] get_imports_for_file for '{}' took {}ms", - current_file, - duration.as_millis() - ); - } - if results.is_empty() { None } else { diff --git a/ast/src/lang/parse/format.rs b/ast/src/lang/parse/format.rs index c3954bafb..1d3558eaf 100644 --- a/ast/src/lang/parse/format.rs +++ b/ast/src/lang/parse/format.rs @@ -1088,9 +1088,7 @@ impl Lang { "[call_resolution] No LSP, allow_unverified=false, calling node_data_finder for {}", called ); - let import_start = std::time::Instant::now(); let import_names = get_imports_for_file(file, self, graph); - crate::utils::record_import_parse(file, import_start.elapsed().as_millis()); if let Some(tf) = node_data_finder( &called, &fc.operand, @@ -1106,9 +1104,7 @@ impl Lang { )); fc.target = tf.into(); } else if let Some(ref operand) = fc.operand { - let import_start = std::time::Instant::now(); let import_names_for_operand = get_imports_for_file(file, self, graph); - crate::utils::record_import_parse(file, import_start.elapsed().as_millis()); if let Some(base_func) = node_data_finder( operand, &None, diff --git a/ast/src/utils.rs b/ast/src/utils.rs index fc9cdf8a1..9d3e4b563 100644 --- a/ast/src/utils.rs +++ b/ast/src/utils.rs @@ -48,7 +48,7 @@ pub struct CallFinderStats { pub struct ImportParseStats { pub total_calls: usize, pub total_time_ms: u128, - pub file_times: std::collections::HashMap, // (call_count, total_ms) + pub file_times: std::collections::HashMap, // (call_count, total_ms, cache_hits) } thread_local! { @@ -315,17 +315,22 @@ pub fn record_call_finder_lookup( }); } -pub fn record_import_parse(file: &str, elapsed_ms: u128) { +pub fn record_import_parse(file: &str, elapsed_ms: u128, is_cache_hit: bool) { IMPORT_PARSE_STATS.with(|stats| { let mut s = stats.borrow_mut(); s.total_calls += 1; s.total_time_ms += elapsed_ms; - // Extract just the filename for cleaner output let filename = file.rsplit('/').next().unwrap_or(file); - let entry = s.file_times.entry(filename.to_string()).or_insert((0, 0)); + let entry = s + .file_times + .entry(filename.to_string()) + .or_insert((0, 0, 0)); entry.0 += 1; entry.1 += elapsed_ms; + if is_cache_hit { + entry.2 += 1; + } }); } @@ -422,10 +427,18 @@ pub fn log_and_reset_import_stats() { let s = stats.borrow(); if s.total_calls > 0 { let unique_count = s.file_times.len(); + let total_cache_hits: usize = s.file_times.values().map(|(_, _, hits)| hits).sum(); + let cache_hit_pct = if s.total_calls > 0 { + (total_cache_hits as f64 / s.total_calls as f64 * 100.0) as u32 + } else { + 0 + }; + tracing::info!( - "[perf][imports] Parsed {} files ({} unique) in {}ms", + "[perf][imports] Parsed {} files ({} unique, {}% cache hit) in {}ms", s.total_calls, unique_count, + cache_hit_pct, s.total_time_ms ); @@ -434,17 +447,24 @@ pub fn log_and_reset_import_stats() { files.sort_by(|a, b| b.1 .1.cmp(&a.1 .1)); // Show top 5 files - for (filename, (count, total_ms)) in files.iter().take(5) { + for (filename, (count, total_ms, cache_hits)) in files.iter().take(5) { let pct = if s.total_time_ms > 0 { (*total_ms as f64 / s.total_time_ms as f64 * 100.0) as u32 } else { 0 }; + let hit_pct = if *count > 0 { + (*cache_hits as f64 / *count as f64 * 100.0) as u32 + } else { + 0 + }; let marker = if pct > 30 { " ← bottleneck" } else { "" }; tracing::info!( - "[perf][imports] • {}: {}× calls, {}ms ({}%){}", + "[perf][imports] • {}: {}× calls ({} cached, {}% hit), {}ms ({}%{})", filename, count, + cache_hits, + hit_pct, total_ms, pct, marker