iOS-Trace:自主应用程序性能优化
iOS-Trace 是一个闭环性能优化引擎,适用于在物理 iPhone/iPad 设备和本地 iOS 模拟器(SwiftUI、UIKit、Metal、CoreAudio / AVAudioEngine 以及 URLSession 网络)上运行的 iOS 和 iPadOS 应用程序。
核心目标是消除手动操作 Instruments GUI。AI 代理可以自主诊断、定位瓶颈、实施代码更改、通过差分基准测试重新验证,并迭代直到性能目标得到经验数据的证实。
+-------------------------------------------------------------------------+
| 自主优化循环 |
| |
| 1. 目标对齐 ──> 2. 诊断性跟踪 ──> 3. 针对性代码修复 |
| ^ │ |
| │ ▼ |
| └────── 若目标未达成则迭代 <── 4. 复测验证 |
+-------------------------------------------------------------------------+
第一阶段:用户目标对齐(预检问卷)
在修改代码或在移动设备上收集跟踪之前,代理必须与用户就优化目标和成功标准达成一致。
模态工具与聊天交互
- 如果你的代理平台提供交互式问卷/模态工具(例如
ask_question、输入对话框或可选项列表),请调用它以向用户清晰呈现这些选项。 - 如果没有可用的模态工具,请在对话中直接向用户提问,提供结构化的选项和具体的推荐值。
需要询问用户的问题
-
主要优化目标:
- 选项 A:减少电池消耗、CPU 利用率和热节流。
- 选项 B:降低内存占用、瞬时分配峰值或防止 Jetsam OOM 崩溃。
- 选项 C:消除 UI 帧卡顿和动画帧丢失(ProMotion 120Hz 抖动)。
- 选项 D:加速移动应用冷启动时间。
- 选项 E:优化网络无线电开销和批处理请求效率。
-
具体性能目标(提供推荐默认值):
- 电池和 CPU 目标:
- 空闲基准目标:< 15 M/s 指令数,CPU 影响 < 0.3。
- 活跃工作负载目标:< 80 M/s 指令数(或指定:减少 30% - 50%)。
- 内存和 Jetsam 目标:
- 最大常驻 RAM:限制在 < 150 MB(标准工具)或 < 300 MB(媒体/富交互应用)。
- 分配事件速率:稳态交互期间 < 400 事件/秒。
- 内存泄漏:确保持续泄漏为 0。
- UI 流畅度和帧率目标:
- 抖动比:< 5.0 ms/s(可接受),< 1.0 ms/s(流畅 / 120Hz ProMotion 级别)。
- 最大抖动持续时间:< 16.6ms(60Hz)或 < 8.33ms(120Hz)。
- 启动时间目标:
- 到首帧时间:< 400 ms(优秀),< 800 ms(可接受)。
- 网络和无线电目标:
- 无线电开销:将周期性的 ping 合并为单次突发请求,以避免无线电尾随待机功耗。
- 电池和 CPU 目标:
-
基准测试用户场景:
- 询问用户要对其进行基准测试的具体屏幕、用户交互、物理设备或模拟器。
一旦确认目标,进入第二阶段。
范围与先决条件
- 目标平台:运行在通过 USB 或本地网络连接的物理 iPhone/iPad 设备上,或本地 iOS 模拟器上的 iOS 和 iPadOS 应用程序。(对于 macOS 桌面应用,请使用 macOS-Trace)。
- 主机系统:运行 Apple Silicon 或 Intel Mac 的 macOS 12+,并安装了完整的 Xcode 或 Xcode 命令行工具(
xcode-select -p、xcrun xctrace version)。 - 设备就绪状态:
- 物理 iPhone/iPad 必须已解锁且被 Mac 主机信任。
- 运行
xcrun xctrace list devices时,设备必须出现在== Devices ==下(而不是== Devices Offline ==)。 - 自动锁定应设置为“永不”,或者在录制期间保持屏幕唤醒,以防止 iOS 挂起后台进程。
- Python:主机 Mac 上需安装 Python 3.8+(仅使用标准库;零外部 pip 依赖)。
- 进程授权:需要具有
get-task-allow授权的调试版本或开发者预发布版本,才能使用--attach <PID>。
代理规则
在自动性能分析期间,请遵循以下不可协商的规则:
- 验证设备连接状态:录制前始终运行
xcrun xctrace list devices。切勿尝试对列在== Devices Offline ==下的设备进行录制。 - 防止屏幕锁定和后台运行:如果 iOS 设备锁定或返回主屏幕,iOS 会挂起或限制进程,导致测量结果无效。保持设备唤醒且应用在前台。
- 首先建立基线:切勿仅录制活跃工作负载。在录制活跃状态之前,始终先捕获一个空闲基线运行(应用在前台、设备屏幕打开、工作负载暂停)。计算:
差值 = 活跃 - 基线。 - 使用相同的测试参数:比较运行时应使用相同的采样持续时间(默认:
60s)、相同的设备电池状态(避免在电量低于 20% 或低电量模式下进行性能分析)以及相同的测试输入数据。 - 无第三方 Python 依赖:所有捆绑脚本(
scripts/compare_elements.py、scripts/parse_power.py、scripts/top_categories.py)仅使用 Python 3 标准库。 - 将输出保存到
/tmp/ios-traces/:将所有.trace包和.xml导出文件存储到/tmp/ios-traces/,并使用带时间戳和场景标签的文件名。 - 保护对话上下文预算:跟踪文件和原始导出的 XML 文档可能达到几十或几百兆字节。切勿将原始
.trace输出、完整调用树或未解析的 Allocations XML 转储到代理对话上下文中。始终使用捆绑的 Python 脚本在读取前对流数据进行处理、过滤、排序和汇总。 - 聚焦主要瓶颈:不要将微优化分散到众多无关紧要的实用函数上。首先进行性能分析以确认主导因素(例如,冗余的表面实例、高频率的定时器重新评估、无缓冲的 I/O),并将优化工作完全集中在该根本原因上。
- 切勿在未获许可的情况下静默更改 UI、视觉效果或核心行为:如果性能瓶颈涉及视觉保真度(例如,模糊/材质、帧动画、阴影、布局过渡)或基本软件行为:
- 不要单方面移除或降低视觉功能。
- 首先正式征求用户许可(使用交互式提示或明确的聊天消息)。
- 清晰阐述权衡:描述更改前后的视觉效果,解释该功能为何消耗资源,并展示预期的具体性能提升(例如,“禁用卡片视图上的动态阴影和模糊将把 GPU 平均影响从 1.8 降低到 0.2,并消除 120Hz ProMotion 抖动”)。
- 清理录制工件:每次
xctrace录制都会将几 GB 的临时内核跟踪(instruments*.ktrace)和一个 Instruments CLI 缓存(C/com.apple.dt.InstrumentsCLI)写入每个用户的系统临时文件夹($TMPDIR)。scripts/run_trace.sh在退出时(无论成功或失败)会自动删除它们。当直接运行xctrace时,请在结束前自行清理:绝不要留下数百 GB 的临时录制数据来结束会话。find "${TMPDIR:-/tmp}" -maxdepth 1 -type f -name 'instruments*.ktrace' -delete 2>/dev/null || true
4 阶段优化协议
第二阶段:诊断性性能分析与归因
在编写代码之前,在设备上测量当前状态并隔离根本原因:
# 1. 确认目标设备在线且已解锁(可选检查;
# 当省略 --device 时,run_trace.sh 自动检测第一个连接的 iPhone/iPad)
xcrun xctrace list devices
BUNDLE_ID="com.example.MyApp"
# SKILL_DIR = 此技能的安装目录(如果安装在别处请调整)
SKILL_DIR="$HOME/.claude/skills/ios-trace"
# 2. 录制 60 秒空闲基线(设备解锁、应用在前台、工作负载暂停)
"$SKILL_DIR/scripts/run_trace.sh" \
--bundle-id "$BUNDLE_ID" \
--template power \
--duration 60s \
--label "01-baseline"
# 3. 在应用中触发目标工作负载,录制活跃状态
"$SKILL_DIR/scripts/run_trace.sh" \
--process "MyApp" \
--template power \
--duration 60s \
--label "02-pre-opt"
# 4. 计算优化前差值
python3 "$SKILL_DIR/scripts/compare_elements.py" \
/tmp/ios-traces/01-baseline-power.xml:"Idle Baseline" \
/tmp/ios-traces/02-pre-opt-power.xml:"Active Pre-Opt"
使用专门的模板来归因瓶颈:
- 运行
--template time以隔离工作线程上的热点调用树函数。 - 运行
--template alloc结合scripts/top_categories.py以识别导致内存压力的抖动分配。 - 在滚动期间运行
--template hitches以隔离 ProMotion 显示器上的渲染与提交延迟。 - 运行
--template network以检测连续的非批处理无线电唤醒。
第三阶段:针对性代码修改
根据发现应用最小、精确的修复:
- 内存峰值与 Jetsam:使用
CGImageSourceCreateThumbnailAtIndex对高分辨率图像进行降采样,而不是加载完整大小的UIImage。 - ProMotion 抖动:移除复杂的阴影和离屏混合通路;将繁重的视图布局计算从主线程移出。
- 无线电能量开销:将周期性的网络请求合并为统一的负载突发,以消除无线电尾随待机功耗。
- 实时音频:确保 CoreAudio 渲染回调(
AVAudioEngine或 RemoteIO)中无堆分配。
重建应用并部署到设备。
第四阶段:复测、定量审查与决策门
在相同条件下重新运行性能分析,并评估差值:
# 1. 录制优化后的活跃工作负载
"$SKILL_DIR/scripts/run_trace.sh" \
--process "MyApp" \
--template power \
--duration 60s \
--label "03-post-opt"
# 2. 比较优化前与优化后与基线的对比
python3 "$SKILL_DIR/scripts/compare_elements.py" \
/tmp/ios-traces/01-baseline-power.xml:"Idle Baseline" \
/tmp/ios-traces/02-pre-opt-power.xml:"Active Pre-Opt" \
/tmp/ios-traces/03-post-opt-power.xml:"Active Post-Opt"
示例决策输出:
Scenario Sec CPU Avg CPU Max Display GPU Avg Total Instr Instr M/s WiFi Tx/Rx
=========================================================================================================
Idle Baseline 60 0.12 0.60 0.05 0.00 0.85G 14.2 0.0/0.0MB
Active Pre-Opt 60 2.40 4.80 1.10 1.80 15.60G 260.0 14.2/1.8MB
Active Post-Opt 60 0.55 1.10 0.15 0.20 4.20G 70.0 2.1/0.4MB
---------------------------------------------------------------------------------------------------------
Differential vs Baseline [Idle Baseline]:
Active Pre-Opt +245.8 M/s instructions, CPU Avg Delta +2.28, WiFi Tx Delta +14.20MB
Active Post-Opt +55.8 M/s instructions, CPU Avg Delta +0.43, WiFi Tx Delta +2.10MB
Optimization Delta (Post-Opt vs Pre-Opt):
Instruction throughput: -73.1% (70.0 vs 260.0 M/s)
CPU Average Impact: -77.1% (0.55 vs 2.40)
GPU Average Impact: -88.9% (0.20 vs 1.80)
WiFi Radio Traffic: -85.2% (2.1MB vs 14.2MB)
决策门逻辑:
- 目标达成:向用户展示经验比较表并结束。
- 目标未达成:保留之前的优化,隔离下一个剩余热点,并重复第三阶段和第四阶段。
报告后清理:在用户接受最终优化报告后,删除 /tmp/ios-traces/ 下累积的 .trace 包(每个可能有几十 GB),除非用户明确要求保留。报告中显示的比较表和 .xml 导出已足够作为证据。
直接 CLI 命令
如果直接执行 xctrace 而不通过 run_trace.sh:
录制
# 附加到设备上正在运行的应用
xcrun xctrace record \
--device <DEVICE_UDID> \
--template 'Power Profiler' \
--time-limit 60s \
--output /tmp/ios-traces/power.trace \
--attach <PID>
# 在设备上冷启动应用
xcrun xctrace record \
--device <DEVICE_UDID> \
--template 'Time Profiler' \
--time-limit 30s \
--output /tmp/ios-traces/launch.trace \
--launch -- com.example.MyApp <LaunchArgs>
导出
# 导出电源影响表(CPU 指令数、能耗、GPU、显示、WiFi/蜂窝网络)
xcrun xctrace export \
--input /tmp/ios-traces/power.trace \
--xpath "/trace-toc/run[@number='1']/data/table[@schema='ProcessSubsystemPowerImpact']" \
> /tmp/ios-traces/power.xml
# 导出分配汇总表
xcrun xctrace export \
--input /tmp/ios-traces/alloc.trace \
--xpath "/trace-toc/run[@number='1']/data/table[@schema='all-allocations-summary']" \
> /tmp/ios-traces/alloc.xml
模板参考
通过 scripts/run_trace.sh 和无头 xctrace 在 iOS 上支持的 Instruments 模板:
计算、电池与能耗
| 模板 | 短名称 | 目标指标与导出模式 | 用例 |
|---|---|---|---|
Power Profiler | power | 每秒指令数 (M/s),CPU/GPU/显示/WiFi/蜂窝网络的能耗影响 (ProcessSubsystemPowerImpact)。 | 全面的电池消耗、热节流和 A/B 基准测试。 |
Time Profiler | time | 按线程的 CPU 样本权重、调用树热点、主线程阻塞方法。 | 高 CPU 利用率、失控的工作线程和热函数路径。 |
CPU Counters | `c |
…
[内容已截断以进行翻译]