⚡ Bolt: [performance improvement] Optimize Tarjan DFS allocations#234
⚡ Bolt: [performance improvement] Optimize Tarjan DFS allocations#234bashandbone wants to merge 1 commit into
Conversation
Eliminates unnecessary `PathBuf` heap allocations during DAG traversals in `crates/flow/src/incremental/invalidation.rs`. - Cached `v.to_path_buf()` into `v_buf` for required insertions. - Replaced map lookups `get(&v.to_path_buf())` with direct borrowed reference `get(v)`. - Replaced `get_mut(&v.to_path_buf())` with `get_mut(v)`. - Fixed implicit lifetimes in `crates/rule-engine/src/check_var.rs` to satisfy clippy `needless_lifetimes`. Co-authored-by: bashandbone <89049923+bashandbone@users.noreply.github.com>
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
Reviewer's GuideOptimizes Tarjan DFS by reusing a cached PathBuf and switching map lookups to borrow-based access, while also applying minor Clippy-driven cleanup and formatting changes across AST and rule-engine modules. File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="crates/flow/src/incremental/invalidation.rs" line_range="348-350" />
<code_context>
/// DFS helper for Tarjan's algorithm
fn tarjan_dfs(&self, v: &Path, state: &mut TarjanState, sccs: &mut Vec<Vec<PathBuf>>) {
+ let v_buf = v.to_path_buf();
// Initialize node
let index = state.index_counter;
- state.indices.insert(v.to_path_buf(), index);
- state.lowlinks.insert(v.to_path_buf(), index);
+ state.indices.insert(v_buf.clone(), index);
+ state.lowlinks.insert(v_buf.clone(), index);
state.index_counter += 1;
- state.stack.push(v.to_path_buf());
- state.on_stack.insert(v.to_path_buf());
+ state.stack.push(v_buf.clone());
+ state.on_stack.insert(v_buf.clone());
// Visit all successors (dependencies)
</code_context>
<issue_to_address>
**suggestion (performance):** Reduce redundant cloning of `v_buf` when initializing Tarjan state for a node.
`v_buf` is now allocated once, which is good, but it’s still cloned four times (for `indices`, `lowlinks`, `stack`, and `on_stack`). You can avoid one clone by moving `v_buf` into the last insertion:
```rust
let v_buf = v.to_path_buf();
state.indices.insert(v_buf.clone(), index);
state.lowlinks.insert(v_buf.clone(), index);
state.stack.push(v_buf.clone());
state.on_stack.insert(v_buf);
```
```suggestion
state.index_counter += 1;
state.stack.push(v_buf.clone());
state.on_stack.insert(v_buf);
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| state.index_counter += 1; | ||
| state.stack.push(v.to_path_buf()); | ||
| state.on_stack.insert(v.to_path_buf()); | ||
| state.stack.push(v_buf.clone()); | ||
| state.on_stack.insert(v_buf.clone()); |
There was a problem hiding this comment.
suggestion (performance): Reduce redundant cloning of v_buf when initializing Tarjan state for a node.
v_buf is now allocated once, which is good, but it’s still cloned four times (for indices, lowlinks, stack, and on_stack). You can avoid one clone by moving v_buf into the last insertion:
let v_buf = v.to_path_buf();
state.indices.insert(v_buf.clone(), index);
state.lowlinks.insert(v_buf.clone(), index);
state.stack.push(v_buf.clone());
state.on_stack.insert(v_buf);| state.index_counter += 1; | |
| state.stack.push(v.to_path_buf()); | |
| state.on_stack.insert(v.to_path_buf()); | |
| state.stack.push(v_buf.clone()); | |
| state.on_stack.insert(v_buf.clone()); | |
| state.index_counter += 1; | |
| state.stack.push(v_buf.clone()); | |
| state.on_stack.insert(v_buf); |
There was a problem hiding this comment.
Pull request overview
This PR reduces unnecessary heap allocations during Tarjan SCC traversal in the incremental invalidation detector by caching PathBuf conversions and leaning on borrowed lookups, plus applies small clippy/rustfmt cleanups in the rule engine and tree-sitter utilities.
Changes:
- Optimize
tarjan_dfsby cachingv.to_path_buf()and switching map/set lookups to use borrowed&Path. - Remove redundant explicit lifetimes in
check_var.rsper clippy. - Apply formatting-only refactors in rule engine and tree-sitter tests/utility code.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| crates/flow/src/incremental/invalidation.rs | Reduces PathBuf allocations in Tarjan DFS and uses borrowed lookups for RapidMap/RapidSet. |
| crates/rule-engine/src/check_var.rs | Simplifies function signatures by removing unnecessary explicit lifetimes. |
| crates/rule-engine/src/rule/referent_rule.rs | Minor refactor (single-expression chain) in Registration::read. |
| crates/rule-engine/src/rule/mod.rs | Formatting-only change to defined_vars for Rule::Pattern. |
| crates/ast-engine/src/tree_sitter/mod.rs | Minor formatting refactors in UTF-8 conversion and a test assertion. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| state.stack.push(v.to_path_buf()); | ||
| state.on_stack.insert(v.to_path_buf()); | ||
| state.stack.push(v_buf.clone()); | ||
| state.on_stack.insert(v_buf.clone()); |
💡 What: Cached
v.to_path_buf()to a local variablev_bufand reused it, while replacing map lookups to use the borrowed referencev. Also cleaned up explicit lifetimes incheck_var.rsas identified by clippy.🎯 Why: Repeated calls to
v.to_path_buf()caused excessive O(E) heap allocations during SCC DAG traversal withintarjan_dfs, degrading incremental build performance.📊 Impact: Significantly reduces memory churn and O(E) heap allocations to O(V) during graph invalidation computations by utilizing zero-cost
Borrowtraits for Map lookups.🔬 Measurement: Observe memory allocations and execution time of
cargo test -p thread-flow --test invalidation_tests.PR created automatically by Jules for task 15864650468603263492 started by @bashandbone
Summary by Sourcery
Optimize incremental invalidation Tarjan DFS to reduce path allocation overhead and apply minor code cleanups across AST and rule engine modules.
Enhancements: