perf(cua-driver-rs)(macos): batch AX attribute fetch + ranged children to cut walk IPC ~3x#1757
Draft
f-trycua wants to merge 1 commit into
Draft
perf(cua-driver-rs)(macos): batch AX attribute fetch + ranged children to cut walk IPC ~3x#1757f-trycua wants to merge 1 commit into
f-trycua wants to merge 1 commit into
Conversation
…n to cut walk IPC ~3x
Each AX attribute read is a synchronous IPC round-trip to the target app.
The tree walker previously issued ~7 of these per node (role, title, value,
placeholder, description, identifier, help). Coalesce them into a single
batched fetch and bound how many children of any one node we materialize.
- bindings: declare the batched/ranged/count attribute FFI plus the AXValue
type id, and add two helpers:
- copy_multiple_attrs: one round-trip for N attributes. options=0 (NOT
stop-on-error) so a single unsupported attribute does not abort the
batch — its slot comes back as an AXValue error placeholder and is
filtered out by position/type. Returns one Option<String> per requested
attribute, in order.
- copy_children_ranged: fetch up to N children of a node in one round-trip
and report whether the list was clipped.
- tree: replace the per-attribute reads in walk_element with one
copy_multiple_attrs batch indexed by position (~7→1 IPC per node); swap the
per-node child fetches to copy_children_ranged with a 200-child cap and a
per-node "children clipped" note when a node exceeds it.
None-vs-empty semantics preserved: a present-but-empty attribute stays
Some("") and an absent attribute stays None, so nodes whose title is "" but
whose description carries the real label still render the description in
parens (the digit-button case the click harness relies on).
The per-node child cap is a different concern from, and coexists with, the
existing total-walk node cap: the child cap bounds one pathological node
while the total cap bounds the walk as a whole.
Refs #1537
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Each AX attribute read is a synchronous IPC round-trip to the target app. The macOS tree walker previously issued ~7 round-trips per node (AXRole, AXTitle, AXValue, AXPlaceholderValue, AXDescription, AXIdentifier, AXHelp). This coalesces them into one batched fetch per node (~7→1) and bounds how many children of any single node we materialize.
Changes
bindings.rsAXUIElementCopyMultipleAttributeValues,AXUIElementCopyAttributeValues,AXUIElementGetAttributeValueCount) plusAXValueGetTypeID.copy_multiple_attrs(element, &[&str]) -> Vec<Option<String>>: one round-trip for N attributes.options = 0(NOT stop-on-error) so a single unsupported attribute does not abort the whole batch — that slot comes back as an AXValue error placeholder and is filtered out by position and type. OneOption<String>per requested attribute, in request order.copy_children_ranged(element, max) -> (Vec<…>, clipped): fetch up tomaxchildren in one round-trip and report whether the child list was clipped.tree.rswalk_elementnow issues onecopy_multiple_attrsbatch indexed by position instead of ~7 separate calls. Action names stay a separate call (different AX API).copy_children_rangedwith a 200-child cap; a per-node… (children clipped at 200)note is appended when a node exceeds it.None-vs-empty semantics (preserved)
A present-but-empty attribute stays
Some("")and an absent attribute staysNone. So a node whose AXTitle is""but whose AXDescription carries the real label still renders the description in parens — the digit-button case the click harness depends on is unaffected by batching.Coexistence with the total-walk cap
The per-node child cap (
MAX_CHILDREN = 200) is a different concern from the existing total-walk node cap (MAX_ELEMENTS = 2000): the child cap bounds one pathological node (a virtualized list/grid), the total cap bounds the walk as a whole. They layer cleanly.Notes
cargo build --release -p cua-driver); tests compile (cargo test --no-run -p platform-macos).Refs #1537
🤖 Generated with Claude Code