Implementation Result · DATA-1
TotalCPU + Network Send/Recv 已接入
在用户批准 DATA-1 后,Perfowl 将 sysmontap 的系统总 CPU 和 DVT NetworkMonitor 接入同一条实时采集链,并把 scope、unit、quality 与原始事件一并保存。修复共享 DVT socket 的并发读取问题后,当前真机上两个匿名目标 App 均完成 9 个样本的只读短采集:首点按协议进入 warmup,后续样本输出动态 TotalCPU 与设备级 Send/Recv。
Approved scope
本批批准项与状态
| 指标/能力 | 真实来源 | scope / unit | 质量语义 | 状态 |
|---|---|---|---|---|
| TotalCPU | SystemCPUUsage.CPU_TotalLoad | device / percent | 首个系统回包 warmup;之后 valid;源缺失为 missing | 已接入 |
| Send | ConnectionUpdateEvent.tx_bytes | device / bytes-per-second(UI:KB/s) | warmup、valid、missing、counter-reset | 已接入 |
| Recv | ConnectionUpdateEvent.rx_bytes | device / bytes-per-second(UI:KB/s) | warmup、valid、missing、counter-reset | 已接入 |
| 原始事实与元数据 | rawSystem / rawNetwork / capability | 字段表、scope、unit、采样间隔 | 不把缺值转换为 0;保留原始事件摘要 | 已接入 |
采集链修正
一个 socket、一个读取泵、多个有界队列
第一次把三个 DVT 服务分别放到线程中读取时,真实设备出现 ConnectionTerminatedError。原因是 pymobiledevice3 的 RemoteServer 逻辑上分 channel,但底层 socket 仍是共享的;多个 recv_plist 会竞争同一传输。DATA-1 改为由 DVTEventPump 统一收包,再按 channel 队列分发;Bundle ID/PID 请求也通过泵等待回包,避免身份刷新再次抢读 socket。
sysmontap 的真实回包是一个列表,包含交错的 System 字典和 Processes 字典,另有 {k: 1024} 元数据消息。适配器现在先展开列表、用最近 System 配对 Processes,并保留完整 rawEnvelope、字段顺序和原始值向量。
Value semantics
看到 0 时如何判断
0 可以是真实值
- Network 的某个有效区间没有发送或接收字节时,Send/Recv 可以是数值
0,同时quality=valid。 - UI 将 0 绘制在曲线上,不把它当作缺失。
缺值不转 0
- TotalCPU 首点没有前一有效系统回包,输出为空并标记
warmup。 - Network 没有事件、连接计数回退或服务异常时,输出为空并标记
missing/counter-reset。
Real-device acceptance
当前连接设备:两个目标 App 均通过只读短采集
公开文档不写入设备名、UDID、Bundle ID、PID 或业务 App 名称;原始 JSONL 仅保存在本机临时验收目录。两个目标均使用已存在进程,不启动、不修改、不注入、不重签。
| 匿名目标 | 样本 | 身份 | TotalCPU | Network | 结论 |
|---|---|---|---|---|---|
| 目标 App A | 9 | Bundle ID → PID verified;未声明前台 | 首点 warmup;后续 8 点 valid,约 82–167% | 首点 warmup;后续 valid/missing 按事件到达;0 值保留 | 通过 |
| 目标 App B | 9 | Bundle ID → PID verified;未声明前台 | 首点 warmup;后续 8 点 valid,约 95–162% | 首点 warmup;后续 valid;Recv 在部分区间动态变化 | 通过 |
| 最终 App 内置 Collector 冒烟 | 5 | embedded binary;身份 verified | 首点 warmup;后续 valid | 出现 missing 与 valid 两种质量,未伪造 0 | 通过 |
本轮应用进程处于非前台状态,因此 FPS/GPU 继续按 foreground-device 门禁省略;这不影响 device-scope TotalCPU 和 Network 的 DATA-1 验收。
Verification ledger
代码、构建和真机证据分层
| 层级 | 结果 | 证据边界 |
|---|---|---|
| Python Collector | 14/14 通过 | 包含 SystemCPU 首点哨兵、真实 sysmontap 列表展开、Network warmup/reset、scope/unit/quality |
| Swift Core/UI | 33/33 通过 | 包含 Schema v2 Codable、15 项 Registry、TotalCPU/Network UI 映射与既有设备链 |
| 内置 Collector | 构建并短采集通过 | App Resources 中的 x86_64 sidecar 与源代码同步;hello=Collector 0.4.0 |
| Release App | 构建、ad-hoc 签名和 strict verify 通过 | 当前本机 x86_64 产物;universal2、Developer ID、公证仍是发布阶段工作 |
| 真机 | 两个目标各 9 样本 | 只读、短时、当前设备;未与 PerfDog 同场,不能作为最终误差承诺 |
匿名化验收摘要见 DATA-1 evidence JSON;原始会话不进入 Git。
Remaining gap
本批仍未具备的能力与补齐方向
| 能力 | 当前状态 | 补齐路径 |
|---|---|---|
| 进程级 Network | 未承诺;iOS 16 事件大量 pid=-2 | 在 iOS 16/17/18+ 分别采集连接关联事件;只有能证明 Bundle/PID 归属才新增 process scope,否则保持 device |
| Available Memory | 未输出伪值 | 确认设备 page size 与 vmFreeCount 语义后建立机型/iOS 转换表,并与 PerfDog 同场复算 |
| CPU Core Usage | raw PerCPUUsage 已保留,UI 未展开 | 按实际核心拓扑输出数组,建立刷新率、核心数和归一化规则 |
| FrameTime / Jank / 1% Low | 没有逐帧源 | 接入 xctrace/Animation Hitches 或可回放 Display FrameTime 源;以同场帧序列验证 PerfDog 派生公式 |
| 截图、Battery/Energy/Thermal、GPU Counter | 规划或未支持 | 分别建立 Screenshot、IOReport/Power、Thermal 与 GPU counter adapter,并按 capability 显示 |
Next gate
下一步停止点
先做口径校准
- 在目标 App 前台执行静止、滚动、网络上传、网络下载四个短场景。
- 同一时间窗保存 Perfowl 原始值、UI 值和 PerfDog 导出值。
- 明确 TotalCPU 是否需要按核心数归一化,以及 Network 是否允许发布为 device scope。
再进入后续批次
- 补 iOS 17+ tunneld 真机和断连/重绑。
- 完成截图源与截图预览 SHOT-1。
- 建立逐帧体验、Energy/Thermal、上传与 Web 报告的独立批准单。