Skip to content

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
mainfrom
perf/ax-walk-batched-fetch
Draft

perf(cua-driver-rs)(macos): batch AX attribute fetch + ranged children to cut walk IPC ~3x#1757
f-trycua wants to merge 1 commit into
mainfrom
perf/ax-walk-batched-fetch

Conversation

@f-trycua
Copy link
Copy Markdown
Collaborator

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.rs

  • Declare the batched / ranged / count attribute FFI (AXUIElementCopyMultipleAttributeValues, AXUIElementCopyAttributeValues, AXUIElementGetAttributeValueCount) plus AXValueGetTypeID.
  • 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. One Option<String> per requested attribute, in request order.
  • copy_children_ranged(element, max) -> (Vec<…>, clipped): fetch up to max children in one round-trip and report whether the child list was clipped.

tree.rs

  • walk_element now issues one copy_multiple_attrs batch indexed by position instead of ~7 separate calls. Action names stay a separate call (different AX API).
  • Per-node child fetches use copy_children_ranged with 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 stays None. 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

Refs #1537

🤖 Generated with Claude Code

…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>
@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 29, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Ignored Ignored May 29, 2026 4:42pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 29, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f87fd761-12bc-4e84-8671-74959de81853

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch perf/ax-walk-batched-fetch

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant