You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Use usbmuxd for physical Apple device discovery instead of spawning devicectl/xctrace #1522
#1403 asked whether the usbmux client should grow beyond the runner transport, and set the bar at "a second concrete product use case". Measuring #1517 produced one.
In the final cabled capture from #1517, resolving the target device cost 6672 ms:
resolve_target_device 6672 ms
open_timing 982 ms
Device resolution is an order of magnitude more expensive than anything the transport change saved per command. It shells out to devicectl list devices, xctrace list devices, simctl list devices, plus the Android and web probes, and pays process-spawn cost for each. Earlier uncached resolutions in the same investigation measured 4.5–6.8 s.
usbmuxd answers ListDevices over a unix socket in milliseconds, and it is already the authority on which physical iOS devices are attached — the same authority #1517 now trusts for routing.
Proposal
Use usbmuxd as a fast path for physical Apple device discovery, on the plist protocol the client already speaks (runner-usbmux-protocol.ts, roughly 50 LOC of additions):
ListDevices to enumerate attached physical devices without spawning anything
optionally Listen to stream attach/detach events, which would let a long-lived daemon keep an accurate device list instead of re-probing
usbmuxd returns the UDID and connection type but not the display name, OS version, or anything about Wi-Fi-only devices, so this is a fast path rather than a replacement: it can confirm which devices are cabled immediately, with the existing tooling filling in metadata or covering Wi-Fi-only devices. The exact split is the main design question here.
A public port-forward command, reverse forwarding for Metro or React DevTools, lockdownd services (installation proxy, AFC, syslog relay), and extracting a general-purpose usbmux package — that last one was evaluated during #1403 and rejected: one internal call site does not justify a package boundary, and a published client would immediately attract the whole libimobiledevice surface area.
Acceptance
Measured before/after on resolve_target_device for a cabled physical device
Wi-Fi-only and simulator resolution keep working unchanged
No behaviour change when usbmuxd is unavailable — it degrades to today's path
Scoping this turned up something that changes its priority. The 6672 ms resolve_target_device figure that justified this issue is real, but usbmux was aimed at the wrong part of it.
Breaking the number down by probe:
probe
cost
vega device list
2833 ms
xctrace list devices
1814 ms
devicectl list devices
773 ms
simctl list devices
768 ms
emulator -list-avds
698 ms
adb devices -l
539 ms
They ran back to back — listLocalDeviceInventory awaited each platform in a for loop — so an unfiltered lookup cost the sum of every installed toolchain. The biggest single contributor was Vega, which the request could never have resolved to.
#1524 removes the serialization: ~4.0 s → ~2.35 s measured by alternating A/B on one host. That is worth more than this issue would have been, and it helps every platform rather than just Apple.
This issue is still valid, just smaller than advertised. With the probes concurrent, wall time is now bounded by the slowest one, so replacing devicectl/xctrace with a millisecond usbmuxd ListDevices only helps once the slower probes are also addressed — and it still cannot supply names, OS versions, or Wi-Fi-only devices on its own.
The other half of the original argument survives untouched: Listen would let a long-lived daemon keep an accurate attached-device list instead of re-probing, and an unplugged device could fail immediately and precisely instead of as a timeout. Those remain the reasons to do this, rather than the raw resolution cost.
A cold toolchain. That capture was the first Apple tooling invocation on the host. Re-measured warm, Apple discovery is ~2.2 s.
Where the remaining ~2.2 s lives
Warm, per probe: simctl list devices ~0.3–1.3 s, devicectl list devices ~1.4 s, xctrace list devices ~2.2 s. devicectl and xctrace already run concurrently, so the Apple chain is bounded by xctrace, and nothing else in it matters much.
I also tried the obvious structural fix — starting the physical probes without waiting for simctl — and benchmarked it as two prebuilt worktrees, alternating, five warm runs each:
arm
runs (ms)
median
main
2183, 2221, 2433, 2282, 2257
2257
probes started early
2284, 2314, 2180, 2163, 2318
2284
Indistinguishable. simctl finishes long before xctrace would, so removing the gate buys nothing warm. I am not proposing that change; it would add complexity for noise.
Why usbmux cannot take the remaining cost
To beat xctrace we would have to stop running it, and usbmuxd cannot replace what it provides:
it returns a UDID and connection type — no display name, no OS version, both of which discovery needs
So usbmux can only ever add a fast signal alongside the existing probes, not remove one — and the probes are the cost.
What is still worth doing, if anything
Only the parts that were never about latency: Listen for attach/detach so a long-lived daemon stops re-probing, and failing immediately and precisely when a cabled device is gone instead of surfacing a timeout. Those stand on their own; if they are not wanted, this issue should just be closed.
Closing: the latency premise did not survive measurement (details in the comment above).
In short — the 6672 ms was sequential platform probing (fixed in #1524) plus a cold toolchain. Warm Apple discovery is ~2.2 s, bounded entirely by xctrace list devices, and usbmuxd cannot replace that probe: it supplies neither display names nor OS versions, and it cannot see network-paired devices, so it can only add a signal alongside the existing probes rather than remove one. The probes are the cost.
The two rationales that were never about latency — Listen for attach/detach so a long-lived daemon stops re-probing, and failing immediately and precisely when a cabled device disappears — are real but small, and neither is currently pulling anyone. Reopen if either becomes worth its own change.
Activity
thymikee commentedon Jul 31, 2026
Scoping this turned up something that changes its priority. The 6672 ms
resolve_target_devicefigure that justified this issue is real, but usbmux was aimed at the wrong part of it.Breaking the number down by probe:
vega device listxctrace list devicesdevicectl list devicessimctl list devicesemulator -list-avdsadb devices -lThey ran back to back —
listLocalDeviceInventoryawaited each platform in aforloop — so an unfiltered lookup cost the sum of every installed toolchain. The biggest single contributor was Vega, which the request could never have resolved to.#1524 removes the serialization: ~4.0 s → ~2.35 s measured by alternating A/B on one host. That is worth more than this issue would have been, and it helps every platform rather than just Apple.
This issue is still valid, just smaller than advertised. With the probes concurrent, wall time is now bounded by the slowest one, so replacing
devicectl/xctracewith a millisecond usbmuxdListDevicesonly helps once the slower probes are also addressed — and it still cannot supply names, OS versions, or Wi-Fi-only devices on its own.The other half of the original argument survives untouched:
Listenwould let a long-lived daemon keep an accurate attached-device list instead of re-probing, and an unplugged device could fail immediately and precisely instead of as a timeout. Those remain the reasons to do this, rather than the raw resolution cost.thymikee commentedon Jul 31, 2026
Measured this properly before implementing, and the speed premise does not survive. Recommending this be closed for the discovery-latency rationale.
What the 6672 ms actually was
Two things, neither of which usbmux addresses:
Where the remaining ~2.2 s lives
Warm, per probe:
simctl list devices~0.3–1.3 s,devicectl list devices~1.4 s,xctrace list devices~2.2 s.devicectlandxctracealready run concurrently, so the Apple chain is bounded byxctrace, and nothing else in it matters much.I also tried the obvious structural fix — starting the physical probes without waiting for
simctl— and benchmarked it as two prebuilt worktrees, alternating, five warm runs each:Indistinguishable.
simctlfinishes long beforexctracewould, so removing the gate buys nothing warm. I am not proposing that change; it would add complexity for noise.Why usbmux cannot take the remaining cost
To beat
xctracewe would have to stop running it, and usbmuxd cannot replace what it provides:xctrace/devicectlon it would silently lose Wi-Fi devicesSo usbmux can only ever add a fast signal alongside the existing probes, not remove one — and the probes are the cost.
What is still worth doing, if anything
Only the parts that were never about latency:
Listenfor attach/detach so a long-lived daemon stops re-probing, and failing immediately and precisely when a cabled device is gone instead of surfacing a timeout. Those stand on their own; if they are not wanted, this issue should just be closed.thymikee commentedon Jul 31, 2026
Closing: the latency premise did not survive measurement (details in the comment above).
In short — the 6672 ms was sequential platform probing (fixed in #1524) plus a cold toolchain. Warm Apple discovery is ~2.2 s, bounded entirely by
xctrace list devices, and usbmuxd cannot replace that probe: it supplies neither display names nor OS versions, and it cannot see network-paired devices, so it can only add a signal alongside the existing probes rather than remove one. The probes are the cost.The two rationales that were never about latency —
Listenfor attach/detach so a long-lived daemon stops re-probing, and failing immediately and precisely when a cabled device disappears — are real but small, and neither is currently pulling anyone. Reopen if either becomes worth its own change.