mcpField
I
instruments-analyzer

instruments-analyzer

github.com/jlreyes开发3554 次安装21 周前更新
代码仓库

关于 instruments-analyzer

将 Apple Instruments 的 .trace 性能记录导出到 DuckDB,供开发者通过 SQL 分析 CPU、SwiftUI 更新、卡顿和挂起等数据。还提供帧级分析视图及滚动与动画卡顿排查流程。

主要功能

  1. 01导出 Instruments 记录至 DuckDB
  2. 02查询 CPU 与 SwiftUI 性能数据
  3. 03分析动画卡顿和挂起事件
  4. 04生成帧级分析视图
  5. 05定位卡顿根因及关联日志

适用场景

  1. 01通过调用栈查找 CPU 热点
  2. 02排查 SwiftUI 滚动和动画卡顿
  3. 03分析应用无响应及挂起原因

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/jlreyes/instruments-analyzer --skill instruments-analyzer

安装后在 Claude Code 中输入/instruments-analyzer确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

SCHEMAS.md
scroll_and_animation.md
.gitignore
LICENSE
README.md
PerfDebugging.tracetemplate
.github/workflows/
tests.yml
scripts/
prepare_analysis.py
export_to_duckdb.py
tests/
test_export_to_duckdb.py
tests/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——一种以帧为先的工作流,用于隔离交互时间窗口、为掉帧排序、进行级联分析、逐帧归因,并生成优先级修复计划。


工作流概览

  1. 录制 跟踪(或使用现有跟踪)
  2. 导出 跟踪到 DuckDB
  3. 探索 导出的表
  4. 准备 派生视图(可选,用于帧级分析)
  5. 使用针对 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_intervalsSignpost 时间间隔(开始/结束对)
os_signpostSignpost 点事件
os_log来自 os_log 的日志消息
runloop_intervalsRunLoop 活动(主线程调度)
coreanimation_context_intervalsCA 渲染阶段(Layout、Display、Prepare、Commit)
coreanimation_lifetime_intervals带可接受延迟阈值的 CA 帧生命周期
potential_hangs检测到的挂起和无响应
life_cycle_periods应用生命周期转换
swiftui_causesSwiftUI 依赖/因果关系图
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

用例配套资源

评论

支持 Markdown