标注输入卡顿与启动阶段 CPU 断档诊断

背景

Owner 2026-11-02 在内部包 237 上连续录了两场目标 App A 的会话(设备 A,iOS 26),反馈 CPU 曲线断数据,并在第二场复测后判断“点击标注后数据就断了”。同日 Owner 指定 Claude 负责全项目修改与优化(兼任 Lead 与 Implementation,见 AGENTS.md),本批诊断与修复由 Claude 决策并实施。

证据(E3,会话原件)

两场均为采集完成状态:线路序号 0 缺口、0 重复、0 乱序,两条连接无错误、无重连。断档出现在采集进程收到 sysmontap 数据的时刻上,不是电脑端丢弃。

会话时长标注保存时刻整机 CPU 来源间隔 > 1.5 秒activitytrace 逐帧来源试探期
第一场≈29 秒第 16.9 秒2.6 秒起 2.8 秒;5.4 秒起 1.7 秒0–8.3 秒
第二场≈22.5 秒第 12.9 秒3.3 秒起 3.1 秒;6.4 秒起 2.1 秒;8.8 秒起 2.3 秒0–13.1 秒
10-30 有 3 次标注的会话≈87 秒33.6 / 61.3 / 81.0 秒无0–4.4 秒
10-30 无标注的三场≈52–55 秒无最多一次 1.6–1.7 秒0–3.6~4.1 秒

• 第二场所有断档都发生在标注保存之前;试探期一结束,积压的 sysmontap 数据在约 9 秒内以正常两倍速率集中补到。

• 第二场电脑端队列(Supervisor 入队→Controller 出队)在标注保存前 6 秒内出现 737 / 95 / 761 / 625 毫秒等待,其余样本约 0.2–0.6 毫秒,说明输入标注期间主线程被占用。

• 两场的帧耗时来源都没有选出(第一场 primary-insufficient-evidence,第二场 resource-limited),逐帧统计只覆盖启动后约 1.2–1.6 秒。

判断

• 已证实(E3):输入标注时主线程长时间被占用。代码中标注草稿 noteText 是整个工作台根视图的 @State,每输入一个字(含输入法拼字)都会使 2700 余行的工作台连同实时图表全部重算;这是界面“停住”的直接原因。

• 已证实(E3):落盘数据里的 CPU 断档来自采集进程侧,与启动/逐帧追踪试探期重合;标注本身不写入采集进程,10-30 的三次标注都没有引起断档。

• 待证(假设):本机为 4 物理核 Intel 笔记本,启动追踪连接在会话中传输 0.2–3 GB 数据;试探期的追踪解码与界面重绘可能共同占满 CPU,使 sysmontap 读取落后。标注输入是否会加重采集侧断档,需要 A/B 复测才能定论,不写成结论。

本批实现

文件修改
`MacApp/Sources/PerfowlApp/PerfowlWorkbenchView.swift`新增私有子视图 `NoteComposer`,草稿文字状态移入其中;根视图只保留弹窗开关,提交后通过闭包调用原有 `appendNote` 并关闭弹窗。输入、提交、空白禁用与无障碍标识均保持不变。

• 复杂度:每次按键的重算范围从整个工作台缩小到弹窗内一个文本框与按钮,与会话长度和图表数量无关。

• 未改采集链路、指标公式与标注落盘格式。

验证

• swift build --product Perfowl 通过(E2)。

• 前后对比基准:以 host-queue-timing.json 中输入标注期间的出队等待为指标,修复前为 625–761 毫秒;修复后需 Owner 在新包上复测(待 E3)。

遗留与下一步

• A/B 复测(Owner 操作):同一目标 App,各录约 60 秒;A 场全程不加标注,B 场在第 20 秒后(试探期结束后)打开标注框并输入约 10 秒。用于区分“启动试探期断档”与“标注输入加重断档”。

• 启动/逐帧追踪试探期挤占 sysmontap:需要另立方案,方向包括给 sysmontap 独立读取优先级、限制试探期追踪数据量,以及让报告标明逐帧统计的实际覆盖时长。

• 逐帧来源过滤未生效(请求 0x31800318,实际过滤列表为空)导致帧耗时整场缺失,单独立项。

实现记录