Instruments Analyzer 为 AI 智能体提供对 Apple Instruments 跟踪数据的编程式访问。Instruments 通常是图形界面工具,该工具通过将 .trace 文件导出到 DuckDB,使你能够用 SQL 查询、从而弥合了这一差距。
用途
当你拥有(或想要录制)Instruments 的 .trace 文件,并希望分析性能数据时可使用本工具,包括 CPU 性能剖析、卡顿、挂起、Signpost、Core Animation、SwiftUI 更新、RunLoop 活动等。它也适合进行基于帧级或事件级证据的根因分析。对于滚动与动画卡顿诊断,可参考 scroll_and_animation.md,这是一个以帧为先的工作流,用于隔离交互窗口、对丢帧排序、级联分析、逐帧归因,并产出按优先级排序的修复方案。
工作流概览
- 录制一个 trace(或使用已有的 trace)
- 将 trace 导出到 DuckDB
- 浏览导出的表
- 准备派生视图(可选,用于帧级分析)
- 使用 SQL 查询对 DuckDB 数据库进行分析
使用方式
第 1 步:录制 trace
使用 xctrace 从命令行录制:
# Attach to a running app
xcrun xctrace record --template 'SwiftUI' --time-limit 20s \
--output ./traces/recording.trace \
--attach AppName --no-prompt
# Or launch the app
xcrun xctrace record --template 'SwiftUI' --time-limit 20s \
--output ./traces/recording.trace \
--launch /path/to/App.app --no-prompt
你也可以在 Instruments 中使用随附的 PerfDebugging.tracetemplate。
模板选择:
- SwiftUI:SwiftUI 视图更新、卡顿、Core Animation、Signpost
- Time Profiler:带回溯的 CPU 采样
- Animation Hitches:帧生命周期、卡顿检测
- Custom:按需组合仪器
可使用 xcrun xctrace list templates 查看可用模板。
第 2 步:导出到 DuckDB
导出脚本将 Instruments 的 .trace 文件转换为带有 Parquet 后端的 DuckDB 数据库:
./scripts/export_to_duckdb.py traces/recording.trace traces/recording/analysis.duckdb
该脚本:
- 通过 shebang 使用 uv run —— 直接运行(不要用 python3)
- 需要 uv
- 为输出路径创建缺失的父目录
- 将每个 Instruments 表导出为压缩的 Parquet 文件
- 创建一个 DuckDB 数据库,其视图引用这些 Parquet 文件
如果导出后关键表为空,建议换用不同的 Instruments 模板或延长录制时间。
第 3 步:浏览导出的表
导出后,连接 DuckDB 数据库并查看可用内容:
-- List all tables/views
SHOW TABLES;
-- Check row counts
SELECT 'updates' AS tbl, COUNT(*) AS rows FROM updates
UNION ALL SELECT 'hitches', COUNT(*) FROM hitches
UNION ALL SELECT 'time_profile', COUNT(*) FROM time_profile
UNION ALL SELECT 'os_signpost_intervals', COUNT(*) FROM os_signpost_intervals
UNION ALL SELECT 'runloop_intervals', COUNT(*) FROM runloop_intervals
UNION ALL SELECT 'potential_hangs', COUNT(*) FROM potential_hangs;
关键表:
- updates:单个 SwiftUI 视图 body 求值
- update_groups:批量 SwiftUI 事务组
- hitches:检测到的动画卡顿(丢帧)
- hitches_frame_lifetimes:完整的帧生命周期数据
- hitches_updates / hitches_renders / hitches_gpu / hitches_framewait:各阶段帧数据
- time_profile:带回溯的 CPU 采样
- os_signpost_intervals:Signpost 区间(begin/end 对)
- os_signpost:Signpost 点事件
- os_log:来自 os_log 的日志消息
- runloop_intervals:RunLoop 活动(主线程调度)
- coreanimation_context_intervals:CA 渲染阶段(Layout、Display、Prepare、Commit)
- coreanimation_lifetime_intervals:带可接受延迟阈值的 CA 帧生命周期
- potential_hangs:检测到的挂起与无响应
- life_cycle_periods:应用生命周期转换
- swiftui_causes:SwiftUI 依赖/因果图
- swiftui_changes:带回溯的 SwiftUI 变更事件
完整 schema 参考:SCHEMAS.md
常用探索查询:
-- Signpost overview (what instrumentation exists)
SELECT
name, category, subsystem,
COUNT(*) AS n,
MAX(CAST(duration_ns AS BIGINT))/1e6 AS max_ms
FROM os_signpost_intervals
WHERE name IS NOT NULL
GROUP BY 1,2,3
ORDER BY max_ms DESC
LIMIT 50;
-- Worst hitches
SELECT start_ns/1e9 AS time_s, duration_ns/1e6 AS ms, narrative_description
FROM hitches
ORDER BY duration_ns DESC
LIMIT 20;
-- Heaviest CPU backtraces
SELECT
COUNT(*) AS samples,
SUM(weight_ns)/1e6 AS approx_ms,
backtrace_json
FROM time_profile
WHERE backtrace_json IS NOT NULL
GROUP BY backtrace_json
ORDER BY approx_ms DESC
LIMIT 10;
-- Hang summary
SELECT hang_type, COUNT(*) AS count, MAX(duration_ns)/1e6 AS max_ms
FROM potential_hangs
GROUP BY hang_type
ORDER BY max_ms DESC;
第 4 步:准备派生视图(用于帧分析)
prepare_analysis.py 脚本在原始导出数据之上创建可供分析的视图:
./scripts/prepare_analysis.py traces/recording/analysis.duckdb
这会基于 hitches_frame_lifetimes 创建一个 frames 视图,包含:
- 计算出的 missed_frames 数量
- 严重程度分桶(Low / Medium / High / Extreme)
- 从 coreanimation_lifetime_intervals.acceptable_latency_ns 推断的帧预算
- 若不可用则回退到 60fps(16.67ms)
针对 120fps 显示器的覆盖:
./scripts/prepare_analysis.py traces/recording/analysis.duckdb --budget-ms 8.33
针对特定帧的级联分析:
./scripts/prepare_analysis.py traces/recording/analysis.duckdb --swap-id 166871
./scripts/prepare_analysis.py traces/recording/analysis.duckdb --swap-id 166871 --context-frames 10
这会输出:
- 目标帧详情
- 之前帧及其预算状态
- 根因识别(级联中第一个超预算的帧)
- 根因帧期间的 Signpost 与日志
时间单位
- 所有时间戳和时长均以纳秒为单位
- start_ns 相对于 trace 起点(不是墙钟时间)
- 换算:duration_ns / 1e6 得毫秒,start_ns / 1e9 得秒
- os_signpost_* 时间戳是字符串 —— 比较时需转换为 BIGINT
用例配套资源
- scroll_and_animation.md —— SwiftUI 滚动与动画卡顿诊断