Summary
On macOS, get_interfaces() calls get_wifi_transmit_rate() for any Wireless80211 interface (src/os/macos/interface.rs). That function's CWWiFiClient::interfaceWithName is a synchronous XPC round-trip to airportd, and on busy hosts we measure it at ~0.3–0.5 s per process — it dominates enumeration cost. It also fires when Wi-Fi is powered off (the interface still enumerates as Wireless80211).
Caught via sample(1) on a process stuck in enumeration:
Thread ... DispatchQueue: com.apple.wifi.xpcclient.mutex (serial)
netdev::os::macos::wifi::get_wifi_transmit_rate
objc2_core_wlan::CWWiFiClient::interfaceWithName
-[CWWiFiClient interfaceWithName:] (CoreWLAN)
-[CWInterface(Private) initWithInterfaceName:xpcClient:legacy:]
Why it hurts
Downstream consumers treat get_interfaces() as cheap. netwatch (the iroh project's interface monitor) enumerates at endpoint bind and re-enumerates on every network event — on a host with virtual bridges (Docker/VM) that's continuous, so long-lived daemons pay the XPC repeatedly and short-lived processes (e.g. one process per test) pay it at every startup. In our case the value was never even consumed: transmit_speed was discarded by the entire downstream stack.
Measured impact when we no-op the call in a fork: a process that binds a QUIC endpoint at startup went from ~0.6 s to ~0.2 s; a 154-test suite (process-per-test) from 13–17 s to 5.7 s.
Proposal
Make Wi-Fi metadata collection opt-in, any of:
- A cargo feature (like the existing
gateway feature) gating the CoreWLAN query, default off — enumeration stays pure syscalls.
- A runtime API:
get_interfaces_with(Options { wifi_metadata: bool, .. }), with get_interfaces() defaulting to off.
- At minimum: skip the query when the interface is down/powered off, and document that
get_interfaces() performs blocking IPC on macOS.
Happy to send a PR for whichever direction you prefer — we currently carry a small fork that sets transmit_speed = None on macOS (branch) and would rather converge upstream.
Summary
On macOS,
get_interfaces()callsget_wifi_transmit_rate()for anyWireless80211interface (src/os/macos/interface.rs). That function'sCWWiFiClient::interfaceWithNameis a synchronous XPC round-trip toairportd, and on busy hosts we measure it at ~0.3–0.5 s per process — it dominates enumeration cost. It also fires when Wi-Fi is powered off (the interface still enumerates asWireless80211).Caught via
sample(1)on a process stuck in enumeration:Why it hurts
Downstream consumers treat
get_interfaces()as cheap.netwatch(the iroh project's interface monitor) enumerates at endpoint bind and re-enumerates on every network event — on a host with virtual bridges (Docker/VM) that's continuous, so long-lived daemons pay the XPC repeatedly and short-lived processes (e.g. one process per test) pay it at every startup. In our case the value was never even consumed:transmit_speedwas discarded by the entire downstream stack.Measured impact when we no-op the call in a fork: a process that binds a QUIC endpoint at startup went from ~0.6 s to ~0.2 s; a 154-test suite (process-per-test) from 13–17 s to 5.7 s.
Proposal
Make Wi-Fi metadata collection opt-in, any of:
gatewayfeature) gating the CoreWLAN query, default off — enumeration stays pure syscalls.get_interfaces_with(Options { wifi_metadata: bool, .. }), withget_interfaces()defaulting to off.get_interfaces()performs blocking IPC on macOS.Happy to send a PR for whichever direction you prefer — we currently carry a small fork that sets
transmit_speed = Noneon macOS (branch) and would rather converge upstream.