Skip to content

perf(orchestration): cache forward adjacency in CascadeDetector#3114

Merged
bug-ops merged 1 commit intomainfrom
cache-cascade-adjacency
Apr 17, 2026
Merged

perf(orchestration): cache forward adjacency in CascadeDetector#3114
bug-ops merged 1 commit intomainfrom
cache-cascade-adjacency

Conversation

@bug-ops
Copy link
Copy Markdown
Owner

@bug-ops bug-ops commented Apr 17, 2026

Summary

  • Adds a lazily-built forward_adjacency: Option<Vec<Vec<TaskId>>> cache to CascadeDetector
  • descendant_count (called per-task per-tick in deprioritized_tasks) no longer rebuilds a HashMap on every invocation — the dense index is built once per DAG lifetime and invalidated in reset()
  • For diamond/fan-in DAGs the per-tick cost drops from O(K*(N+E)) to O(NRD) where D is subtree size
  • is_cascading, deprioritized_tasks, and evaluate_abort become &mut self; two scheduler call-sites updated

Changes

  • crates/zeph-orchestration/src/cascade.rs — cache field, ensure_adjacency, reset() invalidation, accessor, doc invariant
  • crates/zeph-orchestration/src/scheduler.rsrefref mut at two call-sites, pre-binding borrow fix at :1457
  • CHANGELOG.md[Unreleased] Performance entry

Test plan

  • cargo +nightly fmt --check — clean
  • cargo clippy --workspace -- -D warnings — clean
  • cargo nextest run --config-file .github/nextest.toml --workspace --lib --bins — 8175/8175 pass
  • Cache lifecycle tests: populated after first call, still populated on second, invalidated after reset()

Closes #3094

@github-actions github-actions Bot added documentation Improvements or additions to documentation rust Rust code changes performance Performance improvements size/L Large PR (201-500 lines) labels Apr 17, 2026
@bug-ops bug-ops enabled auto-merge (squash) April 17, 2026 15:41
Add a lazily-built `forward_adjacency: Option<Vec<Vec<TaskId>>>` field
to `CascadeDetector`. `ensure_adjacency` builds the dense index once per
DAG lifetime and is invalidated exclusively in `reset()`, which is called
from `inject_tasks` — the only production mutation path.

`descendant_count` (called once per task per tick in `deprioritized_tasks`
when cascade routing is active) no longer rebuilds a `HashMap` on every
invocation. For diamond/fan-in DAGs the per-tick cost drops from
O(K*(N+E)) to O(N*R*D) where D is the subtree size.

Public methods `is_cascading`, `deprioritized_tasks`, and `evaluate_abort`
become `&mut self` to carry the cache. A `#[cfg(test)]` accessor
`forward_adjacency_is_cached` mirrors the existing `region_health` pattern.

Closes #3094
@bug-ops bug-ops force-pushed the cache-cascade-adjacency branch from ea1472c to d4e869c Compare April 17, 2026 15:43
@bug-ops bug-ops merged commit 08c4f77 into main Apr 17, 2026
32 checks passed
@bug-ops bug-ops deleted the cache-cascade-adjacency branch April 17, 2026 15:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation performance Performance improvements rust Rust code changes size/L Large PR (201-500 lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf(orchestration): cache forward adjacency in CascadeDetector::descendant_count to avoid per-tick rebuild

1 participant