Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@
## 2025-11-05 - [Replace HashMap Allocation with Flat Vec for Block Lookup]
**Learning:** In the `flatten_blocks` function within `orch8-engine/src/evaluator.rs`, allocating a `HashMap<&BlockId, &BlockDefinition>` to map execution blocks introduces significant hashing and memory allocation overhead on the evaluation hot path, which is called every tick. Since the tree size is typically bounded and small, building a `Vec` and sorting it by `BlockId` allows for O(log N) lookups via `.binary_search_by_key()`, completely avoiding `HashMap` overhead.
**Action:** In execution hot paths where a lookup map is created from a slice on every iteration, always prefer a flat `Vec` initialized with `Vec::with_capacity()`, sorted by key, and queried via `.binary_search_by_key()` over a `HashMap` to eliminate hashing and heap allocation costs.
## 2025-11-05 - [Replace Iterator Collect with Manual Loop and Preallocated Vec]
**Learning:** In execution hot paths like `children_of` in `orch8-engine/src/evaluator.rs`, using an iterator adapter chain like `.filter(...).collect()` on a slice doesn't know the final size in advance, causing it to start with 0 capacity and repeatedly reallocate memory as elements are pushed.
**Action:** Replace `.filter(...).collect()` chains with a manual `for` loop that pushes elements to a `Vec` instantiated with `Vec::with_capacity(N)` when a reasonably small bound is known, avoiding initial reallocation overheads.
18 changes: 12 additions & 6 deletions orch8-engine/src/evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1250,12 +1250,18 @@ pub fn children_of(
parent_id: ExecutionNodeId,
branch_index: Option<i16>,
) -> Vec<&ExecutionNode> {
tree.iter()
.filter(|n| {
n.parent_id == Some(parent_id)
&& (branch_index.is_none() || n.branch_index == branch_index)
})
.collect()
// ⚑ Bolt: Using a manual loop with a preallocated `Vec` avoids the multiple
// reallocation overheads of `.filter(...).collect()` on an unknown-sized
// iterator in execution hot paths.
let mut children = Vec::with_capacity(8);
for n in tree {
if n.parent_id == Some(parent_id)
&& (branch_index.is_none() || n.branch_index == branch_index)
{
children.push(n);
}
}
children
}

/// Check if all nodes in a set are in a terminal state.
Expand Down
Loading