SuperAPI AI 工具集

instruments-analyzer

测试与质量

查看项目

更新于 10-16 09:10

技能介绍

Instruments Analyzer 为 AI 智能体提供对 Apple Instruments 跟踪数据的编程式访问。Instruments 通常是图形界面工具,该工具通过将 .trace 文件导出到 DuckDB,使你能够用 SQL 查询、从而弥合了这一差距。

用途

当你拥有(或想要录制)Instruments 的 .trace 文件,并希望分析性能数据时可使用本工具,包括 CPU 性能剖析、卡顿、挂起、Signpost、Core Animation、SwiftUI 更新、RunLoop 活动等。它也适合进行基于帧级或事件级证据的根因分析。对于滚动与动画卡顿诊断,可参考 scroll_and_animation.md,这是一个以帧为先的工作流,用于隔离交互窗口、对丢帧排序、级联分析、逐帧归因,并产出按优先级排序的修复方案。

工作流概览

  1. 录制一个 trace(或使用已有的 trace)
  2. 将 trace 导出到 DuckDB
  3. 浏览导出的表
  4. 准备派生视图(可选,用于帧级分析)
  5. 使用 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 滚动与动画卡顿诊断