Skip to content

StartupTiming:12 项指标拆分索引(兼容入口) ​

本页不再拥有 metric ownership。 从 2026-09-18 起,StartupTiming 原先合并的 12 个进程级指标按语义拆分为三个独立 Canonical 页,公式、质量语义、证据与版本历史均以下面三页为准;本页只保留历史入口与拆分说明,不再重复维护口径。

分层指标新 Canonical 页
Observation Metrics:轻量外部观测observed_running_ms、foreground_ready_msStartup Observation
Primary Metric:启动主结果app_launch_total_msApp Launch Total
Diagnostic Phase Metrics:九阶段诊断分解9 个 phase 指标Startup Phases

三个新页各自包含完整的十要素:定义、metricID/scope/unit/source、系统原理、系统服务与调用实现、原始字段、精确公式、Clock/Window/Freshness、质量语义、当前证据与平台覆盖、常见误区、Legacy、版本历史。领域总览见 iOS 应用启动性能总览,历史技术决策见 Startup 技术演进与实验。

以下内容为拆分前 v21~v47 版本沉淀的背景说明,继续保留供历史查阅,不代表当前权威口径;如与三个新 Canonical 页冲突,以新页为准。


1. 指标分层 ​

1.1 Observation Metrics:轻量外部观测 ​

指标metricID数据源含义
Process Observed Runningios.process.startup.observed_running_mslifecycle-observer从 Launch Request 到主机首次观测目标进程运行
Foreground Readyios.process.startup.foreground_ready_mslifecycle-observer从 Launch Request 到主机首次观测目标进入前台

这两个指标使用主机 monotonic 时间,并受 lifecycle polling 周期影响;报告会保留 pollingErrorUpperBoundMs。它们适合作为粗粒度启动观测与 CoreProfile 不可用时的降级信息,不是 First Frame,也不能冒充 App Launch Total。

1.2 Primary Metric:App Launch Total ​

指标metricID数据源定义
App Launch Totalios.process.startup.app_launch_total_msCoreProfile kdebug lifecycleSystem Interface BEGIN → Initial Frame END 的绝对端点跨度

核心公式:

LaunchTotalMs=(TframeEnd−TsystemBegin)×numerdenom×1,000,000

Launch Total 不是九阶段之和。 中间阶段存在并行、交叠、条件回调;只要首尾端点成立,中间阶段本轮缺失并不会自动使 Total 失效。

1.3 Diagnostic Phase Metrics:九阶段可观测分解 ​

#指标metricID性质
1System Interface Initializationios.process.startup.system_interface_ms必需;Total 起点所在阶段
2Static Runtime Initializationios.process.startup.static_runtime_ms必需
3UIKit Initializationios.process.startup.uikit_initialization_ms必需
4UIKit Scene Creationios.process.startup.uikit_scene_creation_ms必需
5willFinishLaunchingWithOptions()ios.process.startup.will_finish_launching_ms条件回调
6didFinishLaunchingWithOptions()ios.process.startup.did_finish_launching_ms核心生命周期阶段
7sceneWillConnectTo()ios.process.startup.scene_will_connect_ms条件回调
8sceneWillEnterForeground()ios.process.startup.scene_will_enter_foreground_ms条件回调
9Initial Frame Renderingios.process.startup.initial_frame_rendering_ms必需;Total 终点所在阶段

每个阶段值来自完整 BEGIN / END span 的真实时间差或同名 span 累计值;缺失时不使用邻居时间插值,也不以 0 填充。


2. 数据源与启动语义 ​

深度启动分析使用:

text
processcontrol
    └── 发起受控 process-cold launch

coreprofilesessiontap
    └── kdebug lifecycle stream
          ├── 0x1F07  dyld / libSystem
          ├── 0x2BDC  lifecycle transition
          ├── 0x2B87  UIKit lifecycle signpost
          └── 0x31CA  initial frame endpoint

Perfowl 的受控启动确保目标旧进程被替换,但不宣称清空 dyld/page cache,也不宣称消除 iOS prewarming。因此知识库统一使用:

controlled process-cold launch / 受控进程冷启动

而不使用“设备级绝对冷启动”。


3. Total Provenance:主结果来源质量 ​

Total 的“有没有值”和“这个值怎么得到”必须分开表达。

状态totalQuality / source语义使用建议
Clean Endpointcandidate + coreprofile-endpointSystem BEGIN 与 Frame END 清晰成对主结果
Repaired Exactrepaired + frame-end-repaired真实首帧终点存在,普通 opener 丢失,经生命周期锚点重新配对可用于报告,必须披露 repaired
Repaired Ambiguousrepaired + frame-end-repaired-ambiguous存在多个可能终点,保留最早候选候选值,不得冒充清晰端点
Start Substitutedrepaired + start-substitutedSystem BEGIN 缺失,使用最早可用 dyld 起点替代保留真实时间戳,但不等同 clean Total
Missing missing关键终点/起点缺失且没有诚实恢复路径不给值

repaired 不表示“估算”。当前修复仍使用真实内核 timestamp;但只要不是清晰端点配对,就必须把 provenance 暴露给用户。


4. Phase Coverage:阶段覆盖质量 ​

阶段展示使用三个基本状态:

  • captured / candidate:完整 span,存在真实耗时;
  • not-applicable:有独立证据表明本轮启动路径没有触发该条件回调;
  • missing / value-less partial:本轮没有形成可信 span。

Workbench 只渲染有真实值的阶段,避免大量空行;但不会隐藏缺失事实。底部始终披露:

text
本轮捕获 X/9 个启动阶段;
N 个本轮未捕获(不展示、不补值);
M 个为该 App 未触发的条件回调。

九阶段完整度是诊断覆盖度,不是 Total 的定义本身。


5. Transport Integrity:采集完整性证据 ​

启动报告还维护与阶段覆盖正交的数据完整性证据。

Host lossFree ​

表示主机侧 live queue / 消费链未发生已知丢弃。它不能证明设备内核缓冲、CoreProfile tap 或设备→主机之前的所有环节完全无损。

deviceLostEventMarkerCount ​

来自内核 TRACE_LOST_EVENTS 标记扫描:

  • >0:本轮明确看到设备侧丢事件证据;
  • 0:本轮没有观测到 loss marker;
  • nil:本记录未执行该扫描。

特别注意:0 不等于整链无损;同时,9/9 阶段完整也可能与非零 marker 共存,因为 marker 可能对应启动窗内其他 kdebug 事件。


6. 三个质量维度必须分开 ​

一份 Startup 结果应该这样读:

text
Total Provenance
  clean / repaired / missing

Phase Coverage
  X/9 captured
  N missing
  M not-applicable

Transport Integrity
  host lossFree
  device loss markers

例如:

text
Total = 1.83 s, clean
Coverage = 6/9
Device loss markers = 0

表示 Total 有清晰端点,但本轮阶段诊断只有 6 个真实值;不能把它简化成“Startup 成功/失败”一个布尔状态。


7. Observation Metrics 的误差边界 ​

Process Observed Running 和 Foreground Ready 的计算使用 host receive monotonic clock:

text
ObservedRunningMs
= observedRunningHostNs - launchRequestedHostNs

ForegroundReadyMs
= observedForegroundHostNs - launchRequestedHostNs

它们同时提供轮询误差上界,因此应理解为“外部观察到状态变化所需时间”。这两个指标与 CoreProfile 的 mach timestamp 生命周期跨度不是同一种精度合同,不应做毫秒级逐点等价比较。


8. 测试与统计建议 ​

日常版本回归建议:

  1. 使用同设备、同 OS、同 App 版本形态和同一受控 process-cold 场景;
  2. 连续采集多轮,首轮单独保留,不机械删除;
  3. 对稳定同场景轮次统计 P50 / P90,并同时记录 Total availability;
  4. 分开统计 clean Total 与 repaired Total 数量;
  5. 阶段分析同时记录 9/9、≥6/9 等 coverage,而不是只看一个平均启动时间。

建议报告至少包含:

text
First Round
Total P50 / P90
Clean Total Rate
Repaired Total Rate
Total Missing Rate
Phase Coverage Distribution
Device Loss Marker Runs

9. 性能基线:优先做版本回归,不做一刀切 ​

1200 ms、2000 ms、didFinish 300 ms 等值可以作为团队参考线,但不是所有 App、设备和业务场景通用的物理标准。

更稳妥的准入方式是:

text
同设备 + 同 OS + 同场景 + 同目标版本形态

比较:

  • Total P50 / P90 回归比例;
  • Initial Frame / didFinish 等关键阶段回归;
  • clean / repaired / missing 比例是否恶化;
  • Phase Coverage 是否异常下降。

只有团队已经冻结业务 SLA 时,才把固定毫秒数升级为正式 Pass / Fail 门槛。


10. 常见问题 ​

为什么某些 scene 阶段没有显示? ​

有两种完全不同的可能:App 本轮路径没有发对应生命周期 signpost,或信号在设备侧没有被观测到。Perfowl 只有在具备足够证据时才标 not-applicable;证据不足保持 missing。详情见启动观测与数据完整性。

为什么 Total 有值但只有 6/9? ​

因为 Total 由首尾端点直接计算,不是阶段求和。中间阶段缺失会降低诊断 coverage,但不自动抹掉已经存在的真实端点跨度。

为什么 Perfowl 与手工秒表不完全一致? ​

Perfowl 的核心 Total 使用系统生命周期与首帧端点;手工秒表往往从手指动作开始,并可能等到异步网络内容全部加载。二者终点定义不同。首帧之后的业务可用性应独立测量。


技术溯源与十要素契约 ​

要素维度详细规范与技术证据
定义与概念一组 12 项进程级 Startup 指标:2 项 lifecycle observation、1 项 Launch Total、9 项可观测阶段诊断
metricIDios.process.startup.*,具体 12 项见本文 §1
scopeprocess;目标 App / 目标 generation 专属
单位 (unit)milliseconds;质量/coverage 为独立元数据,不折算成 ms
底层系统服务与通信通道processcontrol、coreprofilesessiontap、lifecycle observer,经 DTX / Provider 路线
采集命令与调用实现ProcessControl 发起 controlled process-cold;CoreProfile lifecycle decoder 解码 kdebug;observer 提供外部 running/foreground 观测
计算方式与精确公式Total = System Interface BEGIN → Initial Frame END;阶段 = 完整 span duration;Observation = host observed - launch requested
数据质量语义 (含 missing)Total provenance、Phase Coverage、Transport Integrity 三维正交;missing 不补 0,repaired 必须披露来源
当前校准状态与证据等级 (E1~E4 )iOS 17 已有多轮 E4 启动采集与缺失取证;跨版本 Foundation E4 不自动外推为九阶段语义 E4,具体版本支持需独立矩阵
兼容/回放边界历史 Startup Session 继续按其原始 profile / quality 回放;新知识口径不改写历史证据

版本历史 ​

版本日期修订要点
v48(拆分,本页降级为索引)2026-09-18本页不再拥有任何 metric ownership;12 项指标按 Observation / Total / Phase 三层拆分为 app-launch-total.md、startup-observation.md、startup-phases.md 三个独立 Canonical 页,公式与质量语义不再在本页维护。
v472026-09-17重构为 Observation / Total / Phase 三层;正式收录 Total provenance、端点修复、coverage 与 device loss marker;“绝对冷启动”统一改为 controlled process-cold;移除首轮必舍弃与统一 Pass/Fail 绝对化叙事。
v462026-09-15面向性能测试工程视角重构九阶段说明。
v452026-09-14规范条件阶段质量语义与 N/A。
v212026-09-07确立 Mach 时钟与区间耗时算法。

Perfowl · Performance Observer