Skip to content

启动阶段随机缺失·系统性消因、旁路源可行性与方向1落地 ​

承接启动时间采集现状与根因记录。本轮以"一次只动一个变量、每步验证、累积 A/B 分组"的方法,把"重型 App 冷启动随机漏采个别启动阶段"的所有主机侧与旁路侧可行修法逐一证伪,最终确认随机缺失发生在设备侧 kdebug / 传输前链路、现有公共配置无法进一步区分或修复;随后按用户决定落地方向1(Total 端点法稳定 + 只展示真实捕获阶段)并清除所有已证伪的实验开关。原始详录见仓库 docs/startup/startup-capture-stability-investigation.md 与 docs/startup/sidechannel-feasibility.md。

1. 方法与诚实红线 ​

  • 方法:cumulative A/B(Wilson 95% CI)。A=基线 → B=Ready Barrier → C=startup-exclusive → D=receive/parse decouple → Step 4=CoreProfile action matrix(ta/bso)→ 旁路源。每步只改一个变量,前一步验证后再进下一步。
  • 红线(全程不破):不补 0、不估算、不为"好看"隐藏真实 missing 的事实;所有值必须是真实内核事件时间戳差;绝不跨轮拼接阶段(只能整轮择优,r1 头+r2 尾=一次没发生过的启动=红线)。

2. 主机侧路线——全部 NEGATIVE ​

变量假设结果
H2 Ready Barrier采集源"就绪"后再放行启动,可减少最早事件竞态无显著改善;缺失仍随机
C startup-exclusive启动窗口内延后次要 adapter,独占带宽给 CoreProfile无改善;且引入 seal 回归(target-pid-missing,live decoder 在封存前被重置),后用快照兜底修复——说明问题不在主机带宽
D receive/parse decouple独立解码 worker + 队列,消除主机接收阻塞receiverBlockedMs/rawQueueDepthMax 均无瓶颈信号,缺失不变
Step 4 CoreProfile action matrix调 ta(kperf action)/bso(bufferSizeOverride)解耦生命周期 kdebug 与高体量 baseline/perf 流移除 baseline action 直接杀死 CoreProfile 流(0 chunks);可用配置组合均无法解耦,缺失不变

结论:在当前 CoreProfile capture mode 下,生命周期 kdebug 与高体量 baseline/perf 事件流无法通过已知公共配置解耦;随机缺失发生在 host consumer 之前,现有实验无法进一步区分"设备 kdebug buffer 溢出 / CoreProfile 内部导出批处理 / 设备→DTX 前链路"中的具体丢失点。lossFree=true 只覆盖主机队列,不证明整条链完整。

3. 单轮重建(P4.1)——INFEASIBLE ​

对完整 9/9 轮做 leave-one-boundary-out:能否只用本轮真实事件重建被移除的阶段边界?

  • 过渡码是单事件双边界(一个 code 同时是上一阶段 END + 下一阶段 BEGIN),两侧同生共死,无法精确恢复;
  • perf/mach 洪流不携带 signpost 身份,不能顶替;
  • 唯一可辩护的界是"最近存活的生命周期邻居"区间宽度,实测 0.02–276 ms(生命周期事件稀疏)→ 不足以作为阶段值。
  • (曾出现"假精度":第一版把被移除边界自身时间戳拿来算界=偷看,已纠正为仅用生命周期邻居。)

4. 旁路数据源——两条均关闭 ​

目标:CoreProfile 丢阶段时,用独立于 kdebug 的旁路源补齐同一次启动(不跨轮、不造假)。

4.1 System Trace(Instruments)—— 不适合,关闭 ​

底层同为 coreprofilesessiontap + kdebug/kperf(非独立,同一设备侧丢失不构成冗余);kperf 单一所有者不能与我方 tap 并发;另起一轮=跨轮拼接=红线;App Launch 模板需 get-task-allow,生产 App 拉不起。

4.2 os_trace_relay(com.apple.os_trace_relay)—— spike 证伪,关闭 ​

统一日志活动流,独立传输、可并发、自报 LOSS、带 mach 时间戳——基础设施看似齐全。决定性 spike(探针 Pid=-1=全进程、PAYLOAD|INFO|DEBUG,冷启动百度网盘,25s,132624 条记录):

观察数据
目标进程被捕获✅ 目标进程共 53563 条统一日志消息(network/defaults/boringssl/UIKit-Touch)
非日志类型能流出✅ ACTIVITY_TRANSITION(0x0202) 1319 条
SIGNPOST(0x0600)❌ 全流 0 条
9 阶段启动边界 signpost❌ 无一出现。关键词命中全为假阳性:FirstFrame=coremedia 视频首帧;didFinish=WebKit 子进程 didFinishLaunching;百度 UIKit 子系统 225 条全为 Touch/Gesture/BackgroundTask 运维日志
mach_timestamp 域❌ ≈2.4e17,非 24MHz mach ticks、非合理 ns uptime,无法与 CoreProfile 对齐

根因:UIKit 启动阶段 signpost 是 kdebug-only(为 Instruments 经 kdebug 发出,对应 CoreProfile 的 0x2B87 class),不进统一日志,故 relay 里根本没有。启动阶段身份只存在于那条随机丢失的 kdebug 通道,统一日志里没有独立冗余。

5. 总结论 ​

主机配置(Ready Barrier / exclusive / decouple / Step4 ta·bso)、单轮重建(P4.1)、旁路源(System Trace / os_trace_relay)——全部走完,全部 NEGATIVE。守住红线的前提下,不存在"补齐单次缺失"的诚实路径。真正能做的两条:①Total 端点法稳定 + 只展示真实捕获阶段(方向1,本轮落地);②多轮整轮择优(可选增强,绝不跨轮拼接)。

6. 方向1 落地(本轮实现) ​

  • Total 端点法:Total = System Interface BEGIN → Initial Frame END 的内核时间戳差。中间必需阶段缺失时报告降为 partial(reason lifecycle-spans-incomplete),但 Total 照常发布、不被清零;仅当端点本身缺失时 Total 诚实判 missing(单元测试 testEndpointTotalRemainsCandidateWhenPhaseCoverageIsPartial 锁定)。
  • 只展示真实捕获阶段:展示层 visiblePhases 改为只渲染有真实值的阶段;missing / 无值 partial / not-applicable 一律不渲染空行、不补 0、不估算。隐藏行不等于隐藏事实——底部以 coverageDisclosure 如实披露"本轮捕获 X/9;N 个本轮未捕获(不展示、不补值);M 个为该 App 未触发的可选回调",且九阶段全账本保留在 phases 供导出/审计。
  • 诚实诊断保留:设备丢事件标记(deviceLostEventMarkerCount,内核 TRACE_LOST_EVENTS)与 startupObservability(按启动窗分窗计数、原始 marker 保留、argSemanticsVerified=false)保留并在工作台单独披露(与阶段覆盖正交:完整 9/9 仍可能有非零 marker,零 marker 只表示"未观测到丢失证据",不等于全链无损)。

7. 清理(代码洁净) ​

删除所有已证伪的实验开关,collector 恢复 Build52 干净基线:Ready Barrier(STARTUP_READY_BARRIER_*)、startup-exclusive、receive/parse decouple(decode worker/queue、receiverBlockedMs/rawQueueDepthMax)、Step 4F/4G env(PERFOWL_STARTUP_PERF_TA/TA_CODESET/BSO/BSOC)、CoreProfile config-audit、startupRx* 指标,以及对应 Swift 配置字段/开关 UI 与其测试;一次性调查脚本(结论已入本文与 docs/startup/)一并移除。保留诚实诊断(设备丢失标记 / startupObservability)与其单元测试。

验证:Sidecar 70 项启动相关单测通过;Swift 包编译通过、StartupTracePresentationTests 9/9 通过。

8. Total 端点精确重配对(Mode A/C)——普查 + 实现 ​

方向1 保证了"Total 有就稳、缺就诚实缺",但不改变缺失率。进一步问:kdebug 数据里是否有更好的结束边界能把缺失的精确 Total 捞回来?先普查、再实现。

8.1 边界模型与失败分类 ​

  • START = System Interface BEGIN(0x1F/07 code=13);Initial Frame BEGIN = 过渡 code=12;END(Total 终点) = 0x31CA0006 首帧 present。
  • 现规则:0x31CA0006 只有 code=12 先开了 Initial Frame 跨度才算终点,否则当"后续帧"丢弃(每帧都发 0x31CA0006)。据此把 Total 缺失分为:Mode A(首帧 END 到了、但 code=12 丢了被丢弃,ignoredTerminalBeforeBeginCount>0)、Mode B(首帧 END 本身被设备丢了)、Mode C(END 在、START 丢了)、Global fail(整轮没归因到进程)。

8.2 离线普查(134 个含启动轨迹的会话) ​

分类会话数占比精确可救
TOTAL_OK10074.6%—(其中 26 个"Total 有、中间阶段缺")
MODE_A1511.2%✅ 端点重配对
MODE_C21.5%✅ 早期阶段替代 START
MODE_B75.2%❌ 无精确解
GLOBAL_FAIL107.5%❌ 非端点问题

结论:精确重配对(Mode A+C=17 个)可把 Total 采集率 74.6% → 87.3%(+12.7pp),全部真内核时间戳、零估算。剩余 Mode B(5.2%)首帧 END 真丢无精确解。

8.3 实现(launch_trace.py) ​

  • 留存被丢弃的首帧 END(machTicks/ns/tid),report 时若 Total 缺失且属正常启动(reason=lifecycle-spans-incomplete,排除 global gate)则重配对。
  • Mode A:以"最后一个存活生命周期边界"为锚点,取其后的被丢弃首帧 END。锚点后唯一候选 → 精确(totalRepairReason=frame-end-repaired);多候选(闪屏/多帧)→ 取最早并标 frame-end-repaired-ambiguous,不冒充精确(护栏,避开 233ms-vs-1206ms 坑)。
  • Mode C:END 在、START 丢 → 用最早早期阶段(dyld/init,PHASES[0..2]) BEGIN 替代 START(误差亚毫秒~低毫秒);绝不用帧 BEGIN 或晚期阶段当 START。
  • 诚实标注:重配对的 Total 用独立 totalQuality="repaired"(不占 candidate),并带 totalSource=coreprofile-endpoint-repaired + totalRepairReason;关键:实时"完成"信号只认干净 candidate 端点,重配对值不会让实时流误判完成、只在最终封存报告出现。Swift 侧 totalIsRepaired/totalRepairDisplay 在工作台如实披露"Total 由端点重配对得出"。
  • Mode B 不救:无被丢弃首帧 END 时不替代任何值,Total 诚实 missing。

验证:新增 Mode A(精确)/Mode A(多帧歧义)/Mode C/Mode B/干净端点 5 项单测;Sidecar 全量 371/371、Swift 全量 140(3 跳过) 通过。

8.4 待办(E4) ​

本节为 E2(离线普查 + 单测)。待设备通道恢复后做 E4 真机复测:确认重配对救回的 Total 与 Apple System Trace ground-truth 一致、闪屏护栏在重型 App 上不误采。实测可行后,再把"启动各阶段如何被获取"一文补入端点重配对小节,正式收录知识库启动章节。

Perfowl · Performance Observer