真机短采集通过 · 口径校准进行中2026-09-03

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。

Python 14/14Swift 33/33Embedded Collector PASSReal device PASSPerfDog 同场校准待补

Approved scope

本批批准项与状态

指标/能力真实来源scope / unit质量语义状态
TotalCPUSystemCPUUsage.CPU_TotalLoaddevice / percent首个系统回包 warmup;之后 valid;源缺失为 missing已接入
SendConnectionUpdateEvent.tx_bytesdevice / bytes-per-second(UI:KB/s)warmupvalidmissingcounter-reset已接入
RecvConnectionUpdateEvent.rx_bytesdevice / bytes-per-second(UI:KB/s)warmupvalidmissingcounter-reset已接入
原始事实与元数据rawSystem / rawNetwork / capability字段表、scope、unit、采样间隔不把缺值转换为 0;保留原始事件摘要已接入

采集链修正

一个 socket、一个读取泵、多个有界队列

DVT Secure Socket Proxy └─ DVTEventPump(唯一 recv 线程) ├─ sysmontap channel → [System / Processes] → process sample ├─ graphics channel → foreground-device graphics ├─ networking channel → NetworkMonitorAccumulator → Send / Recv └─ processcontrol + deviceinfo → Bundle ID → PID 身份校验 ↓ CollectorWireEvent / schema v2 ↓ Swift PerformanceSample → Session / CSV / UI

第一次把三个 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
TotalCPU 的范围暂不等同 PerfDog 的展示口径。
当前值直接承接 DVT 的多核系统负载百分比,真机上出现 80–170% 属于该原始口径的可能结果,不能在 UI 层强行裁剪或除以核数。要对齐 PerfDog,下一步必须在相同设备、相同场景和相同时间窗做原始值、核数归一化值与 PerfDog 导出值的三方校准。

Real-device acceptance

当前连接设备:两个目标 App 均通过只读短采集

公开文档不写入设备名、UDID、Bundle ID、PID 或业务 App 名称;原始 JSONL 仅保存在本机临时验收目录。两个目标均使用已存在进程,不启动、不修改、不注入、不重签。

匿名目标样本身份TotalCPUNetwork结论
目标 App A9Bundle ID → PID verified;未声明前台首点 warmup;后续 8 点 valid,约 82–167%首点 warmup;后续 valid/missing 按事件到达;0 值保留通过
目标 App B9Bundle ID → PID verified;未声明前台首点 warmup;后续 8 点 valid,约 95–162%首点 warmup;后续 valid;Recv 在部分区间动态变化通过
最终 App 内置 Collector 冒烟5embedded binary;身份 verified首点 warmup;后续 valid出现 missing 与 valid 两种质量,未伪造 0通过

本轮应用进程处于非前台状态,因此 FPS/GPU 继续按 foreground-device 门禁省略;这不影响 device-scope TotalCPU 和 Network 的 DATA-1 验收。

Verification ledger

代码、构建和真机证据分层

层级结果证据边界
Python Collector14/14 通过包含 SystemCPU 首点哨兵、真实 sysmontap 列表展开、Network warmup/reset、scope/unit/quality
Swift Core/UI33/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 Usageraw 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 报告的独立批准单。
DATA-1 结论
基础数据链已经具备真实来源、可追溯原始事实和明确质量状态;0 值不再是“成功/失败”的唯一判断。对外宣称 PerfDog 数值对齐前,仍必须完成同场校准。