ios-ettrace-performance

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

iOS ETTrace Performance

iOS ETTrace 性能分析

Use ETTrace for a bounded, symbolicated sampling experiment. Treat capture conditions and symbolication as part of the evidence, not as setup trivia.
使用ETTrace进行有边界的、已符号化的采样实验。请将捕获条件和符号化视为证据的一部分,而非无关紧要的设置步骤。

Contents

目录

Boundary

适用边界

This skill owns ETTrace framework/CLI capture, exact-build dSYMs, processed flamegraph JSON, and like-for-like verification. Use Instruments for broad CPU, hitch, energy, or concurrency triage. Use SwiftUI performance guidance for view identity, invalidation, and layout remediation.
ETTrace periodically samples thread stacks. Its durations reconstruct sampled attribution from those intervals; do not present them as wall-clock production timings or compare them directly with a differently configured profiler.
本技能负责ETTrace框架/CLI捕获、精确构建版本的dSYM、处理后的火焰图JSON以及同类验证。如需进行广泛的CPU、卡顿、能耗或并发问题排查,请使用Instruments。如需针对视图标识、失效和布局修复的指导,请遵循SwiftUI性能优化规范。
ETTrace会定期采样线程堆栈,其时长是通过这些时间间隔重构的采样归因数据;请勿将其视为实际生产环境中的挂钟时间,也不要直接与配置不同的性能分析工具结果进行对比。

Capture Contract

捕获约定

Write these down before capturing:
  • one exact user flow and its start/stop boundary;
  • launch capture or already-running runtime capture;
  • app commit, build configuration, optimization settings, and architecture;
  • ETTrace runner and framework versions, plus single-thread or multi-thread mode;
  • simulator/device model and OS build;
  • launch method, data state, cache state, and repetition count.
Reject a before/after claim when any of these materially differ. Rebuild and repeat under one contract instead.
在捕获前请记录以下内容:
  • 一个明确的用户流程及其开始/结束边界;
  • 是启动时捕获还是运行时捕获;
  • 应用提交版本、构建配置、优化设置和架构;
  • ETTrace运行器和框架版本,以及单线程或多线程模式;
  • 模拟器/设备型号和OS版本;
  • 启动方式、数据状态、缓存状态和重复次数。
如果上述任何内容存在实质性差异,请拒绝前后对比的结论。应在同一约定下重新构建并重复实验。

Workflow

工作流程

1. Triage before instrumenting

1. 先排查再 instrumentation

Confirm that ETTrace's sampled flamechart is the right next tool. Prefer Instruments first when the slow interval is unknown, spans many subsystems, or needs system-level blocking, I/O, hitch, or concurrency context.
Choose one flow small enough to repeat. Launch, first screen construction, opening one document, or applying one edit are useful boundaries; "use the app" is not.
确认ETTrace的采样火焰图是合适的下一步工具。当慢执行区间未知、涉及多个子系统,或需要系统级阻塞、I/O、卡顿或并发上下文时,优先使用Instruments。
选择一个足够小且可重复的流程。启动、首屏构建、打开单个文档或执行一次编辑都是有用的边界;“使用应用”则不是。

2. Record and hold ETTrace versions fixed

2. 记录并固定ETTrace版本

Install the runner from the official tap and link the ETTrace package product into the app target being measured. Record the runner version and the framework revision or tag separately, then keep both fixed across compared captures. The bundled analyzer supports the verified v1.1.1 processed output shape; re-check upstream and the parser before using a different format.
bash
brew install emergetools/homebrew-tap/ettrace
Run the instrumented app once and confirm the
Starting ETTrace
log. Absence of that message means capture evidence is not trustworthy. Keep this wiring out of shipping configurations unless the project deliberately owns that tradeoff.
从官方tap安装运行器,并将ETTrace包产品链接到被测应用目标。分别记录运行器版本和框架修订版或标签,然后在所有对比捕获中保持两者固定。内置分析器支持经过验证的v1.1.1处理输出格式;使用其他格式前,请重新检查上游代码和解析器。
bash
brew install emergetools/homebrew-tap/ettrace
运行一次instrumented应用,确认出现
Starting ETTrace
日志。如果没有该日志,说明捕获数据不可信。除非项目有意承担相关风险,否则请勿将此配置留在发布版本中。

3. Build first, then collect matching dSYMs

3. 先构建,再收集匹配的dSYM

Use the final instrumented build for both capture and dSYM collection. Never choose a dSYM by filename, modification time, or Derived Data proximity.
bash
mkdir -p /tmp/myapp-ettrace
python3 scripts/collect_dsyms.py \
  --app /path/to/Build/Products/Release-iphonesimulator/MyApp.app \
  --search-root /path/to/Build/Products \
  --search-root /path/to/Archives \
  --output /tmp/myapp-ettrace/dsyms \
  --pretty > /tmp/myapp-ettrace/dsym-report.json
The helper compares
dwarfdump --uuid
output for the app executable and embedded binaries. Missing or ambiguous UUID matches stop the run by default. Read and preserve
dsym-report.json
rather than assuming every copied symbol file is relevant. The helper fails when UUID matches cannot be copied to unique flat destination names that ETTrace 1.1.1 can discover.
使用最终的instrumented构建版本进行捕获和dSYM收集。切勿通过文件名、修改时间或Derived Data位置来选择dSYM。
bash
mkdir -p /tmp/myapp-ettrace
python3 scripts/collect_dsyms.py \
  --app /path/to/Build/Products/Release-iphonesimulator/MyApp.app \
  --search-root /path/to/Build/Products \
  --search-root /path/to/Archives \
  --output /tmp/myapp-ettrace/dsyms \
  --pretty > /tmp/myapp-ettrace/dsym-report.json
该工具会对比应用可执行文件和嵌入二进制文件的
dwarfdump --uuid
输出。默认情况下,缺失或模糊的UUID匹配会终止运行。请阅读并保留
dsym-report.json
,不要假设所有复制的符号文件都相关。当无法将UUID匹配的文件复制到ETTrace 1.1.1可识别的唯一扁平目标名称时,该工具会执行失败。

4. Capture from a clean artifact directory

4. 从干净的产物目录进行捕获

Run ETTrace from an empty directory because processed files are written to the current working directory. Use
--simulator
for Simulator and
--dsyms
for the exact dSYM directory. Add
--launch
only for launch work, and follow the runner's two-launch prompts exactly.
bash
mkdir -p /tmp/myapp-ettrace
mkdir /tmp/myapp-ettrace/run-01
cd /tmp/myapp-ettrace/run-01
ettrace --simulator --dsyms /tmp/myapp-ettrace/dsyms
The second
mkdir
must fail if that per-run directory already exists. Choose a new run name instead of mixing processed captures from retries.
Launch by tapping the app on the Home Screen when the runner asks. Launching from Xcode can change the launch path and timing. For device capture, omit
--simulator
; keep all other experiment fields stable.
Stop immediately after the bounded flow and preserve every fresh
output_<threadId>.json
with the capture contract. ETTrace 1.1.1 creates these processed files after symbolication. Its internal raw runner
output.json
is a different artifact and is not accepted by the analyzer below.
从空目录运行ETTrace,因为处理后的文件会写入当前工作目录。针对模拟器使用
--simulator
参数,针对精确dSYM目录使用
--dsyms
参数。仅在捕获启动流程时添加
--launch
参数,并严格按照运行器的两次启动提示操作。
bash
mkdir -p /tmp/myapp-ettrace
mkdir /tmp/myapp-ettrace/run-01
cd /tmp/myapp-ettrace/run-01
ettrace --simulator --dsyms /tmp/myapp-ettrace/dsyms
如果该每次运行的目录已存在,第二个
mkdir
命令必须执行失败。请选择新的运行名称,不要混合重试产生的处理后捕获数据。
当运行器提示时,点击主屏幕上的应用图标启动应用。从Xcode启动会改变启动路径和时间。针对真机捕获,请省略
--simulator
参数;保持所有其他实验参数稳定。
完成有边界的流程后立即停止,并将所有新生成的
output_<threadId>.json
与捕获约定一起保留。ETTrace 1.1.1会在符号化后创建这些处理后的文件。其内部原始运行器
output.json
是不同的产物,不被下方的分析器接受。

5. Validate and summarize processed output

5. 验证并总结处理后的输出

bash
python3 scripts/analyze_ettrace.py \
  /tmp/myapp-ettrace/run-01/output_*.json \
  --top 25 --pretty > /tmp/myapp-ettrace/run-01/summary.json
The helper validates the v1.1.1 processed node shape, rejects duplicate inputs or mixed
osBuild
/
device
/
isSimulator
metadata, handles the serializer's object-or-array
children
field, and emits deterministic JSON. It does not rewrite the capture files. Keep those originals beside the summary.
Stop and repair symbolication when important app frames are
<unknown>
, raw addresses, or attributed to the wrong binary. An unsymbolicated hot address is an evidence gap, not a code recommendation. ETTrace 1.1.1 address-bearing nodes are listed under
unresolved_frames
and excluded from ordinary hotspots.
bash
python3 scripts/analyze_ettrace.py \
  /tmp/myapp-ettrace/run-01/output_*.json \
  --top 25 --pretty > /tmp/myapp-ettrace/run-01/summary.json
该工具会验证v1.1.1处理后的节点格式,拒绝重复输入或混合的
osBuild
/
device
/
isSimulator
元数据,处理序列化器的
children
字段(对象或数组类型),并生成确定性JSON。它不会重写捕获文件,请将原始文件与总结文件放在一起保留。
当重要的应用帧显示为
<unknown>
、原始地址或被归因到错误的二进制文件时,请停止操作并修复符号化问题。未符号化的热点地址是证据缺口,而非代码优化建议。ETTrace 1.1.1中包含地址的节点会列在
unresolved_frames
下,并被排除在常规热点分析之外。

6. Change one cause and repeat

6. 修改一个原因并重复实验

Make the smallest code or configuration change supported by a hot app-owned path. Rebuild, recollect UUID-matched dSYMs, and capture the same flow at least twice. Report variance and the full capture contract with the result.
针对热点的应用自有路径,做出最小的代码或配置修改。重新构建、重新收集UUID匹配的dSYM,并至少重复捕获相同流程两次。报告结果时请说明差异情况和完整的捕获约定。

Interpret the Report

报告解读

  • Exclusive seconds approximate sampled time charged directly to a symbol after subtracting direct child durations. Start with high exclusive app-owned work.
  • Inclusive seconds show the weight of an entire call subtree. Use them to find expensive entry paths, not to blame every parent frame.
  • Aggregated inclusive time can exceed the root duration because recursive or nested appearances count each frame. Exclusive percentages use root duration.
  • <unattributed>
    is reported separately. A large value weakens conclusions about what happened in the missing interval.
  • A framework hotspot may still be caused by app call frequency, data shape, or configuration. Walk upward to the first controllable app-owned caller.
  • Multi-thread files sum thread time, not wall-clock latency. Do not describe their combined root duration as elapsed time.
  • Exclusive seconds(独占时间):表示直接归因于某个符号的采样时间近似值,已减去直接子节点的时长。请从占比较高的应用自有独占工作开始分析。
  • Inclusive seconds(包含时间):显示整个调用子树的权重。用于查找昂贵的入口路径,而非指责每个父帧。
  • 聚合后的包含时间可能超过根节点时长,因为递归或嵌套出现的每个帧都会被计数。独占百分比以根节点时长为基准。
  • <unattributed>
    (未归因)会单独报告。如果该值较大,会削弱对缺失区间内发生情况的结论可信度。
  • 框架热点可能仍由应用调用频率、数据格式或配置导致。请向上追溯至第一个可控制的应用自有调用方。
  • 多线程文件是线程时间的总和,而非挂钟延迟。请勿将其合并后的根节点时长描述为经过时间。

Common Mistakes

常见误区

  • Profiling an unbounded session and then guessing which samples match the bug.
  • Capturing one build while supplying dSYMs from another build or architecture.
  • Treating ETTrace's raw runner JSON as a processed flamegraph.
  • Comparing launch capture with runtime capture, or single-thread with multi-thread capture.
  • Optimizing the top inclusive parent without inspecting exclusive work and child paths.
  • Claiming improvement from one noisy run.
  • Leaving ETTrace instrumentation in production by accident.
  • 对无边界的会话进行性能分析,然后猜测哪些采样与bug匹配。
  • 捕获一个构建版本的数据,却提供另一个构建版本或架构的dSYM。
  • 将ETTrace的原始运行器JSON视为已处理的火焰图。
  • 对比启动捕获和运行时捕获,或单线程与多线程捕获的结果。
  • 在未检查独占工作和子路径的情况下,优化顶层包含父节点。
  • 通过一次噪声较大的运行就声称性能有所提升。
  • 意外将ETTrace instrumentation留在生产版本中。

Review Checklist

审核检查清单

  • One reproducible flow and start/stop boundary are recorded.
  • Launch/runtime capture mode, single/multi-thread mode, runner version, and framework revision match.
  • Build configuration, architecture, target/OS, launch method, and app data/cache state match.
  • Every capture starts in a fresh, empty per-run artifact directory.
  • App and embedded-binary UUIDs match the supplied dSYMs.
  • The dSYM collection JSON report is preserved with source/destination and missing, ambiguous, collision, or incompatibility evidence.
  • Processed
    output_<threadId>.json
    files are preserved unchanged.
  • Important app frames are symbolicated.
  • Exclusive, inclusive, unattributed, and multi-thread semantics are clear.
  • The recommendation names an app-controlled path and supporting evidence.
  • Verification repeats the same contract and reports more than one run.
  • Temporary instrumentation is removed or intentionally scoped.
  • 已记录一个可重现的流程及其开始/结束边界。
  • 启动/运行时捕获模式、单/多线程模式、运行器版本和框架修订版保持一致。
  • 构建配置、架构、目标/OS、启动方式和应用数据/缓存状态保持一致。
  • 每次捕获都从全新的空运行产物目录开始。
  • 应用和嵌入二进制文件的UUID与提供的dSYM匹配。
  • 已保留dSYM收集JSON报告,其中包含源/目标路径以及缺失、模糊、冲突或不兼容的证据。
  • 已保留未修改的处理后
    output_<threadId>.json
    文件。
  • 重要的应用帧已完成符号化。
  • 已明确独占、包含、未归因和多线程的语义。
  • 优化建议指明了应用可控路径并提供了支持证据。
  • 验证实验遵循同一约定,且报告了多次运行结果。
  • 临时instrumentation已移除或被有意限定范围。

References

参考资料