关于 instruments-analyzer
将 Apple Instruments 的 .trace 性能记录导出到 DuckDB,供开发者通过 SQL 分析 CPU、SwiftUI 更新、卡顿和挂起等数据。还提供帧级分析视图及滚动与动画卡顿排查流程。
主要功能
- 01导出 Instruments 记录至 DuckDB
- 02查询 CPU 与 SwiftUI 性能数据
- 03分析动画卡顿和挂起事件
- 04生成帧级分析视图
- 05定位卡顿根因及关联日志
适用场景
- 01通过调用栈查找 CPU 热点
- 02排查 SwiftUI 滚动和动画卡顿
- 03分析应用无响应及挂起原因
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jlreyes/ instruments-analyzer --skill instruments-analyzer安装后在 Claude Code 中输入/instruments-analyzer确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
SCHEMAS.mdscroll_and_animation.md.gitignoreLICENSEREADME.mdPerfDebugging.tracetemplate.github/workflows/tests.ymlscripts/prepare_analysis.pyexport_to_duckdb.pytests/test_export_to_duckdb.pytests/fixtures/time_profile_dedup.xml详细介绍
Instruments Analyzer
此工具可让你以编程方式访问 Apple Instruments 跟踪数据。Instruments 通常是一个 GUI 工具;此工具通过将 .trace 文件导出到 DuckDB 来弥补这一不足,你可以在其中使用 SQL 查询数据。
何时使用此工具
- 你有(或想要录制)Instruments
.trace文件 - 你想分析性能数据:CPU 性能分析、卡顿、挂起、signpost、Core Animation、SwiftUI 更新、RunLoop 活动等
- 你想基于帧级或事件级证据进行根因分析
滚动与动画卡顿诊断:请参阅 scroll_and_animation.md——一种以帧为先的工作流,用于隔离交互时间窗口、为掉帧排序、进行级联分析、逐帧归因,并生成优先级修复计划。
工作流概览
- 录制 跟踪(或使用现有跟踪)
- 导出 跟踪到 DuckDB
- 探索 导出的表
- 准备 派生视图(可选,用于帧级分析)
- 使用针对 DuckDB 数据库的 SQL 查询进行 分析
步骤 1:录制跟踪
使用 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:按需组合 Instruments
使用 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 文件
- 创建一个引用这些 Parquet 文件的 DuckDB 数据库,并在其中建立视图
如果导出后关键表为空,建议改用其他 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 时间间隔(开始/结束对) |
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 变更事件 |
完整架构参考: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
输出内容:
- 目标帧详情
- 前序帧及其预算状态
- 根因识别(级联中第一个超出预算的帧)
- 根因帧期间的标记和日志
时间单位
- 所有时间戳和持续时间均以纳秒为单位
start_ns相对于跟踪开始时间(不是墙上时钟)- 转换:毫秒为
duration_ns / 1e6,秒为start_ns / 1e9 os_signpost_*时间戳是字符串——比较时转换为 BIGINT
用例配套资源
- scroll_and_animation.md — SwiftUI 滚动和动画卡顿诊断