Skip to content

2026-10-28 · 第二轮对照试用增量 ​

原生结果窗与CSV/PDF现在从Session已哈希核同的report-final.json读取单次Core Total及phaseResults,保留算法版本、source、candidate/not-applicable和phaseCoverageComplete。事件不铺成每秒样本,未映射时间轴的事件不纳入选区重算;not-applicable保持空,不写0。Core Total端点不等于didFinishLaunching结束,也不与observed-running/foreground-ready混用。哈希核同证明封存绑定,不替代Raw独立复算或跨工具端点校准。

正式55/66、11项暂停不变。本批软件/主机证据不是新增真机验收。第二轮方案与实现。

App Launch Total(启动主结果) ​

作用域属性:[进程级 · 目标 App 专属](Process Scope ) 当前状态:candidate(真实内核时间戳,端点修复语义明确;尚未升级为 validated)

最近验收边界 · 2026-10-04 ​

b111设备A/目标App A两次真实工作台受控冷启动均已请求Startup并封存,默认v9来源与App最终结果一致;两轮首帧阶段缺失,Total保持null/missing,不是0。网络/26项非启动门通过不替代启动端点门,也不证明启动稳定性提高。公式与质量语义不变,后续先对已封存端点/流角色取证,不用外部Observation或后续帧补Total。本次验收。

默认启动配置实施 · 2026-10-12 ​

本批按 Owner 指令将已实测 C0 请求固化为独立 Startup channel 默认 startup-c0.candidate.v1:bm=0/curkt=false/rp=10/ur=500,单个 tk=3 trigger,10个冻结 kdf2,UUID每次新生成;ta/csd 省略。由自研 startup_profile.startup_tap_config() 构造,DedicatedStartupChannel.prepare() 选择,CoreProfileRawAdapter._make_stream() 在 pinned pymobiledevice3 tap 进入录制前应用。后续 frame/未指定 profile 的 adapter 保留 legacy。实际请求及 signature 可在 effective_config 核对,名义 options 不是请求事实。

Total公式、设备时基换算、scope、缺失/修复/端点门与算法candidate.v9未改,也未改变录制就绪→launch顺序。前批仅私有配置实验E4;新安装Build172默认采集器四目标各五轮Total 20/20,Raw端点独立重算一致;完整观察/显式Stop协议 19/20,一轮监督工具异常保留,未重采替换。阶段 not-applicable 不置0,获取Total与九阶段均有值分开统计。本配置仍 candidate,不代表通用长期稳定。实施与验证。

独立验收更新 · 2026-10-12 ​

Lead对原封存、Raw三端点/同源目标绑定、timebase整数换算与首live/final逐轮复核:当前Build172四目标各五轮的默认产品CLI Total获取子门E4接受(20/20)。完整观察/Stop协议19/20,不把一次监督异常隐藏或补轮;本批不是GUI交互复验,也未完成独立物理首帧校准。数值仍candidate,阶段条件缺值与公式不变;不外推所有设备/OS长期100%。独立验收。

1. 定义与业务价值 ​

App Launch Total 回答一个问题:从 System Interface Initialization 起点,到 Initial Frame END 系统端点,经过了多少毫秒。 它是 Perfowl Startup 领域的主指标,与业内“冷启动耗时”相关,但口径更具体——它不是用户按下图标到肉眼觉得“可以用了”的主观时间,也不是 photon-to-eye 测量,而是两个设备端生命周期事件之间的端点跨度。

2. metricID / scope / unit / source ​

字段值
metricIDios.process.startup.app_launch_total_ms
scopeprocess(目标 App / 目标 generation 专属)
unitmilliseconds
sourcedvt.coreprofilesessiontap.lifecycle
sourceKeyselected(frame-terminal.machTicks)-selected(system-begin.machTicks)
definitionVersion core-profile-app-lifecycle.candidate.v9

以上字段直接取自当前 MacApp/Sources/PerfowlCore/PerformanceModels.swift Registry ,与 site/data/metric-contracts.json 快照一致。

3. iOS 系统原理 ​

iOS 应用启动不是单一事件,而是一条从进程建立、dyld 加载、运行时初始化、UIKit 生命周期回调到首帧呈现的链路。Apple 官方文档把 warm/cold launch 描述为一个连续谱而非两态(参考 Reducing your app's launch time、About the app launch sequence)。Perfowl 的 App Launch Total 选取这条链路上两个具体、可在内核层面观测到的端点,而不是整条链路的求和,原因见第 8 节。

4. 系统服务 / 通信通道 / 采集命令与实现 ​

  • 启动触发:com.apple.instruments.server.services.processcontrol(DTX ,processcontrol channel,launch selector),由 Perfowl 自研适配层 perfowl.startup-control.raw(MacApp/Sidecar/perfowl_collector_core/startup_timing.py::launch_request_envelope)发起受控启动请求,底层复用 pymobiledevice3 的 DTX/ProcessControl 能力(PMD3_CANDIDATE 版本锁定)。
  • 深度端点解码:com.apple.instruments.server.services.coreprofilesessiontap(DTX),由 MacApp/Sidecar/perfowl_collector_core/launch_trace.py 中的 RealtimeLaunchTraceDecoder 解析 kdebug 流。模块头部注释明确:“reuses the pymobiledevice3-owned DTX stream and implements only the small, frozen KDebug mapping needed for process-scoped launch spans”——即数据传输通道属于 pymobiledevice3,KDebug 语义映射是 Perfowl 自研、版本化、fail-closed 的 LifecycleDecoderProfile。
  • 终点 debug ID 来自 startup_trace_codes.json 契约文件中的 initialFrameEndDebugID(当前解码器里对应的具体十六进制常量为 INITIAL_FRAME_END_DEBUG_ID,py-ios-device 冻结参考源标注其代码含义为 0x31CA0006 / Initial Frame END;Perfowl 只信任该常量本身,不把其它形态相近的事件当作终点);起点属于 System Interface Initialization span 的 BEGIN(kdebug class 0x1F07,dyld/libSystem)。

5. 原始字段与字段语义 ​

  • 归属到目标 PID / generation 的 system-begin endpoint evidence:进程环境建立、dyld 开始加载动态库的起点。它在 BEGIN 到达时独立入账,不再依赖 System Interface END 存活并形成完整 span。
  • Initial Frame Rendering span 的 END mach tick(即 INITIAL_FRAME_END_DEBUG_ID):首帧呈现完成的终点。
  • 两者都以设备 mach absolute time 记录,随原始 CoreProfile chunk 一起下发 machNumer / machDenom 时间基准,由 RealtimeLaunchTraceDecoder 在主机侧转换为纳秒。
  • 端点账本同时保留 targetGeneration / sourceEpoch / reconnectGeneration / arrivalSequence / profile 版本与选择原因;字段不可得时为 null,不默认填 1 参与“同源”证明。

6. 精确公式 ​

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

其中 numer/denom 为该设备当次会话上报的 mach 时间基准(delta_ns = (delta_ticks * numer) // denom,见 launch_trace.py)。Total 不是九阶段耗时之和:中间阶段之间存在并行、交叠和条件回调,只要首尾两个端点本身成立,Total 就可以成立,即使某个中间阶段本轮未被捕获。

7. Clock / Window / Freshness ​

  • Clock domain:设备 mach absolute time(单调,与 host 收包时钟是两个不同的 clock domain,不能与 startup-observation.md 的 host monotonic 结果做毫秒级逐点对齐)。
  • Window:单次受控启动(一次 launch round)产生一个 Total 值,不是滑动窗口聚合,也没有跨轮拼接。
  • Freshness:Total 在该轮启动的 CoreProfile 数据排空(drain)并完成归因后一次性产出;不提供“实时预估中间值”。

8. Baseline / Reset / Discontinuity ​

App Launch Total 没有前值依赖、没有 counter reset 语义——它是一次性端点差值,每一轮受控启动独立计算,不跨轮次累积或平滑。

9. Quality:Total Provenance ​

状态totalQuality / 来源或修复原因语义使用建议
Clean Endpointcandidate + coreprofile-endpointSystem BEGIN 与 Frame END 清晰成对候选主结果;仍须核对本轮端点完整性与证据层级,不等于 E4 稳定性验收
Repaired Single Candidaterepaired + frame-end-repaired普通 opener 缺失,生命周期锚点后仅观测到一个候选终点;仍待首帧身份验证保留 repaired 标签;单一存活候选不自动证明为真实首帧
Repaired Ambiguousrepaired + frame-end-repaired-ambiguous存在多个候选终点,保留最早候选候选值,不得当作清晰端点使用
Start Substitutedrepaired + start-substitutedSystem BEGIN 缺失,使用最早可用 dyld 起点替代真实时间戳,但不等同 clean Total
Missingmissing关键端点缺失且没有诚实恢复路径不给值,不得用后续帧/截图/主机观察时间代替

frame-end-repaired / frame-end-repaired-ambiguous / start-substituted 是 totalRepairReason,其 totalSource 通常为 coreprofile-endpoint-repaired。真实内核时间戳不自动证明端点身份:替代起点可能产生向下偏差,后续帧误作首帧可能产生向上偏差。保留 repaired 标签,未经身份和误差校准不计为精确成功。

2026-09-20 SSO-1 实现更新:独立端点账本 ​

稳定性重评 的两类 E2 反例已进入永久回归:① System BEGIN 存活、其 phase END 缺失时,Total 直接使用独立账本的原始 BEGIN tick;②真正首帧 END 缺失而后续同码 END 存活时,仅能保持 paired-candidate,不升格为 validated/exact。新增 endpointIntegrity 为:

  • paired-candidate:opener/terminal 正常配对,仍是未经跨源校准的候选端点;
  • paired-with-loss-evidence:opener→terminal 窗口观测到设备丢事件标记,数值仅作诊断;
  • start-substituted:缺 System BEGIN,使用后续早期阶段替代;
  • single-terminal-unverified / multiple-terminals-ambiguous:opener 丢失后的单/多终点,均不计入准确成功;
  • evidence-truncated:候选超过固定上限,fail-closed;
  • missing:无可用端点或发生 generation/epoch/reconnect 身份冲突。

账本上限为 System BEGIN 8、Frame opener 16、terminal 32,热路径对每个匹配事件为 O(1)。phaseCoverageComplete 与 endpoint integrity 正交保存;阶段不完整不会抹掉真实端点,端点身份不足也不因数值接近预期而升格。当前实现证据为 E2;E4 端点校准和稳定率仍开放。

2026-09-30 补充:默认关闭的「续流端点受控准入」实验(尚未进入产线语义) ​

SW-1 P1 批次为可证明同源、唯一目标绑定的既有续流端点(frame-continuation)引入了一个默认关闭的受控准入门,目的是先回答"该端点能否被诚实地纳入既有配对/发布条件",而不是先改口径。对本页的读者而言,需要知道的只有三件事:

  1. 公式与质量语义未变:Total_ms 公式、scope、单位、totalQuality 取值与 totalRepairReason 语义全部保持原样;本批只增加"哪些字节有资格参与既有配对"的前置条件,不新增、不合成任何阶段或端点。
  2. 当时的默认路径:2026-09-30 的 P1 实验基线中,开关未开启时报告为 core-profile-app-lifecycle.candidate.v8,Total / 阶段 / 活线修订 / 报告与 Raw 的既有字段语义保持;显式开启(PERFOWL_STARTUP_CONTINUATION_ADMISSION=1)的实验路径在报告自身的 algorithmVersion 上标识 core-profile-app-lifecycle.candidate.v8.sw1-p1。这描述的是当日实验对照,不是当前默认版本;当前口径见下方 2026-10-03 更新。
  3. 仍是 candidate,不是稳定可用:该实验的 Gate A/P1a 已补 E2 在线双 sink 内容一致性正/负例和同规模资源对照;2026-10-01 自验收 只覆盖本地合成程序路径与实验包,不覆盖原生 App UI 真机启动。在取得 E4 真机证据并完成证据自验收之前,本指标不得描述为稳定可用,也不得据此宣称启动时间稳定性提升。

失败语义同时被收紧:续流端点的外层四元(source / epoch / reconnect generation / target generation)缺失或不符、同线程号出现两个进程号、映射账本或候选容量越界、字节偏移出现 gap 或队列丢包,都会使整轮准入候选粘性失效并保留 missing / partial(缺值不用 0 代替),而不是只丢弃新端点却继续用既有路径发布。开发记录见 SW-1 P1 实施记录。

2026-10-03 当前版本与 G2 合入边界 ​

当前主线 launch_trace.py 的默认 LAUNCH_TRACE_ALGORITHM 为 core-profile-app-lifecycle.candidate.v9,与本页第 2 节 Registry definitionVersion 及指标合同一致。续流准入开启时,报告的实验标识仍为 …candidate.v8.sw1-p1;这个实验标识不倒推默认路径回到 v8,也不改写 2026-09-30 的历史对照。G2 独立生命周期采集已经合入代码,但选择器未设置时仍选择 legacy;仅显式设为 dedicated-lifecycle 才进入实验路径。以上是源码及 E2 构建/测试层面的口径,不构成真机稳定性改善或正式 UI E4 验收。主线集成记录

10. 合法 0 的条件 ​

App Launch Total 理论上不存在合法的 0 值:一次进程启动到首帧呈现必然消耗可观测的正时间。任何计算结果为 0 或负值都应被判定为端点配对错误并归入 missing,不得展示为“启动 0 ms”。

11. 当前证据、校准与平台覆盖 ​

  • Total 计算逻辑已在多轮真机验收中产出非空、量级合理的数值:例如 Build48(2026-09-12)设备 A / 目标 App A 三轮命令级真机采集得到 App Launch Total 1895.326 ms、1863.244 ms、2023.438 ms,CoreProfile bridge 三轮均无 ring overwrite / live drop(Build48 devlog)。
  • Build53(2026-09-14)双轮验收中 Total provenance 与阶段排空链路通过,但 6/9 阶段未捕获,报告明确"6/9 阶段是目标 App 当前可观测结果,不能描述为九阶段完整校准"。
  • 更早的商店 App 跨系统矩阵(S5,2026-09-08,2 设备 × 3 App × 5 轮 = 30 轮)显示 Total 端点解码链路本身工作正常,但完整九阶段仍为 0/30;这批证据主要约束的是阶段覆盖而非 Total 端点本身。
  • 产品历史上短暂切换到 Apple 官方 xctrace App Launch 作为 Total/九阶段来源(xctrace-app-launch.v1,2026-09-07,在开发签名 Fixture 上 validated),但该路径依赖 Xcode 环境与开发签名安装,与 Perfowl 面向任意已安装 App 的无侵入黑盒目标冲突;此后(Build48 起)产品标准路径回到当前 Registry 记录的 CoreProfile 端点方案。详见 Startup 技术演进与实验。
  • 当前证据等级:E4(真机命令级),跨 iOS 17/18 build(21A327、22C161)已有 Profile 绑定,但 Profile 状态仍为 candidate,未升级为 validated;iOS 26/27 目前只有 E2 静态 schema 候选,无真机证据(no-ios26-device-evidence / no-ios27-device-evidence)。不得把 iOS 17/18 的证据外推到未验证的 iOS 版本。

12. 如何分析:能得到什么结论,不能得到什么结论 ​

能得到:

  • 该轮受控启动从 System Interface BEGIN 到 Initial Frame END 的设备端事件跨度;
  • 结合多轮统计(P50/P90)用于同设备、同 OS、同场景的版本回归比较;
  • 结合 Total Provenance 判断这轮结果的可信来源(clean / repaired 及其修复原因)。

不能得到:

  • 不能证明首帧之后业务内容(网络数据、图片、WebView)已经就绪——Apple 官方还区分 TimeToFirstDrawMetric、OptimizedTimeToFirstDrawMetric、ExtendedLaunchMetric 等更晚阶段的指标;
  • 不能仅凭 Total 单值判定具体代码热点,需要结合九阶段(startup-phases)和 Instruments 证据;
  • 不能跨轮拼接使用(例如用 A 轮的起点配 B 轮的终点)。

13. 常见误区 ​

  • 把 Total 理解为“设备级绝对冷启动”:Perfowl 的受控启动只保证目标进程被替换创建,不保证清空 dyld/page cache 或关闭 iOS App Prewarming,应称为 controlled process-cold launch;
  • 把 Total 当成九阶段之和:见第 6 节,两者是不同的计算路径;
  • 把 repaired Total 当作与 clean Total 同等精度;
  • 把某一版本、某一设备的 E4 证据外推到未验证的 iOS 大版本或设备。

14. Legacy / 历史实现 ​

  • xctrace-app-launch.v1(2026-09-07~2026-09-12 左右):短暂作为深度 Startup 主源,使用 Apple 官方 xctrace App Launch 模板;因依赖 Xcode/开发签名环境而未成为长期默认路径,详见 Startup 技术演进与实验。
  • core-profile-app-lifecycle.candidate.v1/v2:更早的 CoreProfile 生命周期映射候选版本,端点修复(repaired/start-substituted)语义在后续版本中逐步补齐。

15. 版本历史与来源批次 ​

本页由 site/knowledge/metrics/startup-timing.md v47(2026-09-17)拆分而来,Total 相关公式与质量语义的历史沿革(v21 确立 Mach 时钟与区间耗时算法、v45 规范条件阶段质量语义、v46 面向测试工程重构、v47 引入 Total provenance 与端点修复)保留在该页的版本历史表中,本页不重复誊写历史数字。

版本日期修订要点
v8(独立获取子门)2026-10-12Lead独立接受固定20/20默认CLI Total获取;完整协议19/20及candidate/物理/GUI边界不变。验收。
v7(默认启动请求)2026-10-12C0固定请求迁入独立Startup默认;新包固定20/20 Total原始核验,执行协议19/20,监督异常原轮保留;公式/candidate/阶段适用性不变。来源:实施与验证。
v6(验收状态同步)2026-10-04b111双轮含Startup,首帧缺失、Total为null;只更新当前证据边界,不改公式/质量/Registry。来源:R11记录。
v5(当前口径同步)2026-10-03区分 2026-09-30 的 v8 实验基线与当前默认 v9;G2 合入但默认 legacy,candidate 不等于 E4。公式、单位、scope 与历史实测值不变。来源:知识库同步记录。
v4(在线证据边界)2026-10-01P1a 的合成端到端正/负例分别核对 decoder 发布、事件、事件时在线文件全文与最终 Raw 回放;真实规模五轮对照补首个 decoder 报告、chunk CPU 与预载解码区间物理 I/O。仅 E2,未证明真机 UI 端点稳定性提高;公式、Registry 和质量语义均不变。来源:SW-1 P1a 实施记录。
v3(实验准入)2026-09-30记录默认关闭的「续流端点受控准入」实验:公式 / 质量语义 / Registry definitionVersion 均不变,OFF 路径逐字节保持 core-profile-app-lifecycle.candidate.v8;实验路径另标 …candidate.v8.sw1-p1。证据等级 E2,未 E4 前不得描述为稳定可用。来源:SW-1 P1 实施记录。
v2(证据限制)2026-09-20追加端点缺失与后续帧替代的 E2 反例,区分真实 tick 与准确首帧;单候选 repaired 保持待验证,不改变公式或产品状态。来源:稳定性重评。
v1(本页)2026-09-18从 startup-timing.md 拆出,成为 App Launch Total 独立 Canonical;补充 Build48/Build53/S5 三批真机证据与 xctrace 迁移历史。

正常UI受控延时与归档/逻辑流坐标 · 2026-10-17(限定E4) ​

内部179/设备A/自有目标A的五新轮按固定0/300/0/300/0ms配方通过端点、目标同代、设备时钟算术、实时Total包与最终报告一致性及受控变化异常门。保留candidate与物理首帧未校准;结果仅此版本/设备/场景,不外推任意App或永久零失败。完整数字和资源见本批验收与不可变快照。

可复用的格式陷阱:归档blob连续保存了原始记录块和无流偏移的辅助二进制包,因此归档物理偏移模64不等于kd_buf记录对齐。定位端点时应以chunk的明确coreProfileStreamByteOffset换算逻辑坐标,登记对应归档物理片段;辅助包仍核SHA但不当记录,真实流gap不跨界拼接。25项软件控制含辅助包插入、跨1MiB/跨chunk、真实gap与错误身份/质量/数值反例;两份资格的只读重审和五新轮验证了本例方法。字段缺失保持unknown,不猜偏移或用数值接近掩盖身份问题。

消费者区别:Total是一次性launch_trace事件/启动面板报告,不是当前周期CSV的一列。检查全部有值实时修订与封口的launch-trace-report/startup-report,核Raw SHA与最终消费序列;不要拿host观察报告的startup命令覆盖原在线同名文件。副本重放的执行环境须明示(本批为宿主加载安装模块),不能混称安装二进制CLI或独立物理仪器。

时间精度:先以tick差乘numer、除denom并在纳秒整数层截断,再除1e6。分别转换绝对时间后相减可能差1ns;不要将该取整差错判采集不准。300ms变化只验证可控负载响应无明显偏离,不证明系统首帧与光学首帧相同,也不替代真正同端点误差政策。

实时修订的额外实测边界 · 2026-10-17 ​

System Interface单项五轮中的一轮先产生375.112625ms/repaired、frame-end-repaired、single-terminal-unverified、liveComplete=false,随后484.257875ms/candidate、paired-candidate、liveComplete=true并封口。当前解码源码明确允许带标签的repaired恢复候选,完成信号只信candidate。本例补充第7节历史“一次性产出、不提供实时中间值”的描述:当前正常GUI确实可见多次launch_trace实时修订;历史验收数字不回改,适用范围以此带日期更新为准。

验收需区分:未完成诊断值、完成候选、最终封口;先按totalQuality/totalRepairReason/endpointIntegrity/liveComplete/final核来源,不能只见一个正数就判获取成功或反过来宣称最终错误。此例未独立验证GUI是否充分提示该过渡,保留展示风险;未完成repaired不计精确clean成功。System Interface各live仍一致,与Total过渡分开验收,不把单阶段通过外推全部启动稳定。本批原件与范围。

版本历史增量:2026-10-28,第二轮内部试用口径、来源及报告边界更新;E2/E3与待测E4分列。第二轮方案与实现。

Perfowl · Performance Observer