# py-ios-device puts iOS performance counters behind a Python CLI

> py-ios-device is a Python implementation of the Apple instruments protocol that streams CPU, memory, FPS and network counters from a real iPhone. It is aimed at performance testers who want the data in a script, but the command set depends on a device tunnel and the newest tagged release is older than the last commit.

**YueChen-C/py-ios-device** — IOS Professional Performance Testing Tool . You can get CPU, GPU, Memory , Lifecycle  and other metrics from real  iOS devices . iOS 性能测试工具

- Repository: https://github.com/YueChen-C/py-ios-device
- Stars: 797 · Forks: 191
- Language: Python
- License: GPL-3.0
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/yuechen-c-py-ios-device

## Reading counters from a real iPhone instead of driving the Instruments app

py-ios-device is a Python library and command line tool built on the Apple instruments protocol, the same machinery behind the system level profiling in Xcode. Its stated purpose is to pull CPU, memory and other metrics from real iOS devices, and the feature checklist covers a wide band of device data: system and application memory and CPU, FPS and jank, network traffic, app launch lifecycle, crash logs, syslog, battery state and the ability to push and pull files. It exists for performance testers and QA engineers who work with a fleet of physical phones and want the numbers in a script or a log file rather than in a GUI window. The primary language is Python, the package requires Python 3.7 or newer, and the whole thing is installed from PyPI. A Java implementation of the same project is linked from the README for teams whose tooling is already on the JVM.

## RemoteLockdownClient and InstrumentServer are the two objects that matter

The library side is built on two classes that you can read directly in the README example. RemoteLockdownClient establishes the lockdown connection to the device, and it accepts a host and port pair plus an optional userspace_port argument, which is what makes it work with a tunnel running in user space rather than as a privileged daemon. InstrumentServer sits on top of that connection and starts the instruments service, which is what actually streams counters. The flow in the documented example is to create the client, call init() on an InstrumentServer to obtain an RPC handle, pass that handle to a sampling function, and stop the server when finished. The demo package ships a sysmontap sampler, and the repository includes separate demo modules for other capabilities: crash_log.py, syslog.py, pcapd.py, afc.py, screenshotr.py, installation_proxy.py and mobile_config.py.

## The pyidevice CLI, from listing a phone to filtering a memory sample

Installation goes through pip and gives you a console entry point named pyidevice. The first three commands to run are the ones that confirm your tooling works at all: list the attached devices, ask one for its device info, and start a live monitor. The monitor prints memory, network and disk counters as dictionaries, and a filter argument narrows the output to a single category. This is the fastest way to see whether the instruments service is reachable on your hardware.

```bash
pip install py-ios-device
pyidevice --help
pyidevice instruments --help
```

```bash
pyidevice devices
pyidevice  deviceinfo --udid=xxxxxx
pyidevice instruments monitor --filter = memory
```

The console script itself is wired up in setup.py, where the entry point maps the pyidevice name to ios_device.main:cli, so the CLI is a thin wrapper around the same library the Python API exposes.

## Per-process sampling with sysmontap and its filter arguments

For anything involving a specific application, the sysmontap command is the important one. It takes a bundle identifier, and it accepts a proc_filter argument that selects which fields to report, a processes flag to list processes rather than one, and a sort key to order the list. The README shows it filtering to physFootprint and cpuUsage and sorting by cpuUsage, which is the shape you want when hunting for a memory or CPU regression in one app. The application monitor command is the lighter alternative for a running app by bundle identifier, returning pid, CPU percentage, memory, disk reads and writes, and thread count. The display command returns FPS together with jank, big_jank and stutter counters, and the fps command returns a simpler frame rate reading.

```bash
pyidevice instruments sysmontap  -b com.tencent.xin --proc_filter physFootprint,cpuUsage --processes --sort cpuUsage
pyidevice instruments appmonitor  -b cn.rongcloud.im
pyidevice instruments display
pyidevice instruments fps
```

## iOS 17 needs a tunnel, and the README recommends go-ios over pymobiledevice3

The README states plainly that iOS 17 is supported and that the command line is not. That is the central operational fact of this project. A device tunnel has to be running before the instruments service will answer, and the documented setup has two variants. One starts a tunnel with pymobiledevice3, the other uses go-ios, and the README recommends go-ios for better transmission performance. The go-ios path shows two commands, one starting the tunnel as root and one running it in user space, followed by a curl against a local endpoint that returns the tunnel descriptors, including the address and rsdPort values that the Python example then hardcodes.

```bash
pip install pymobiledevice3
sudo python3 -m pymobiledevice3 remote start-tunnel
npm install -g go-ios
sudo ios tunnel start && ios tunnel start --userspace
curl http://127.0.0.1:60105/tunnels
```

## Condition and notification commands change the device instead of watching it

Most of the CLI reports, but two families of commands act on the device. The condition commands read and write device configuration state, and the documented profiles include SlowNetwork2GUrban for throttled network conditions and ThermalCritical for making the device behave as though it were in a high thermal state. That is the useful pair for reproducing a failure that only appears on a degraded network or a hot device, and it is a different approach from the CLI approach of using Apple's own condition profile names rather than emulating them in software. The notifications command watches app lifecycle transitions, reporting the executable name, bundle identifier, foreground or background state, and a mach absolute timestamp for each transition, which gives you a launch timeline without instrumenting the app itself.

```bash
pyidevice instruments condition get
pyidevice instruments condition set -c SlowNetworkCondition -p SlowNetwork2GUrban
pyidevice instruments condition set -c ThermalCondition -p ThermalCritical
pyidevice instruments notifications
```

## The feature list is wider than the commands the README demonstrates

Here is where the documentation gets thin. The feature checklist promises a lot that the walkthrough does not show command examples for: dumping and analysing core profile stack snapshots, Metal GPU counters, app install and uninstall, device management such as installing and uninstalling a Fiddler certificate, captured packet traffic forwarded to Wireshark, syslog and crash log retrieval, app launch and kill, running xctest such as WebDriverAgent, and app start, exit and background monitoring. The demo directory suggests these paths exist, since it includes pcapd.py, crash_log.py, syslog.py and installation_proxy.py, but the README excerpt does not map them to pyidevice subcommands. A second gap is the relationship between the two sample paths. The CLI and the Python API are documented separately, and the Python example hardcodes a host, an rsdPort and a userspace port taken from a specific tunnel session, which means the values change every time you restart the tunnel.

```python
host = 'fd17:cafe:59d4::1'
port = 54934
with RemoteLockdownClient((host, port), userspace_port=60106) as rsd:
    rpc = InstrumentServer(rsd).init()
    sysmontap(rpc)
    rpc.stop()
```

## GPL-3.0, a 2023 tag, and pushes that continued afterwards

The licence is GPL-3.0, which is the significant legal detail for a tool that talks to proprietary device services. The obligations attach to distributing modified versions, and the practical consequence for most teams is that internal use and internal modification stay private, while shipping a modified build to customers or bundling it in a product would pull the source and licence terms along with it. The repository is not archived. The last push was on 2026-07-06, so work continued after the newest tag, and the release history lists v2.3.2 from 2023-02-16 and v2.3.0 from 2022-12-09. That gap between a recent commit and an old tag is worth noting: the tagged artifact you would install from a package index predates three years of repository activity. The dependency set is ordinary Python, including construct, pyasn1, pyOpenSSL, click, requests and psutil, and setup.py requires Python 3.7 or newer.

## Conclusion

Performance testers who already script their device lab will find py-ios-device worth the setup cost, since the pyidevice CLI and the Python API expose counters that would otherwise mean driving Instruments by hand. It is the wrong tool for someone who wants a packaged GUI, for CI on a shared runner without a paired phone, or for GPU counter work the documentation does not demonstrate. Before adopting it, confirm that your iOS version needs a tunnel, read the protocol requirements for RemoteLockdownClient with your host and port, and check which of the listed commands your device build actually answers. The honest baseline is that the newest tagged release is v2.3.2 from 2023-02-16 while the last push was on 2026-07-06, so pin a version and expect to patch against device changes.

## FAQ

### How do I install py-ios-device and run the first command?

Install it with pip, which provides the pyidevice console command, then run pyidevice devices to list attached devices and pyidevice instruments monitor to start streaming system counters. Python 3.7 or newer is required.

### Does py-ios-device work on iOS 17 without extra setup?

No. The README states that iOS 17 is supported but that the command line is not, so a device tunnel has to be running first, started either with pymobiledevice3 or with go-ios, which the README recommends for better transmission performance.

### What licence does py-ios-device use and can I use it commercially?

The project is released under GPL-3.0. Internal use is straightforward, and the GPL obligations attach when you distribute a modified or combined version to others.

## Sources

- [Issues](https://github.com/YueChen-C/py-ios-device/issues)
- [License: GPL-3.0](https://github.com/YueChen-C/py-ios-device/blob/main/LICENSE)
- [README](https://github.com/YueChen-C/py-ios-device/blob/main/README.md)
- [Releases](https://github.com/YueChen-C/py-ios-device/releases)
- [YueChen-C/py-ios-device on GitHub](https://github.com/YueChen-C/py-ios-device)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/yuechen-c-py-ios-device
