Skip to content

全指标采集、实时窗口与快速收尾修复方案 ​

1. 决策与批准边界 ​

**方案完成,实施待用户批准。**本批只交付设计与验收合同,不变更产品代码、冻结依赖或指标算法。基线为 a9cab40 / Build 38 / Foundation 2.7 Beta。本文 E1 表示设计与代码审查;此前留存会话属于真实运行证据,但不代表修复后 E4 通过。八项问题全部进入范围,不把“入口可选”当作指标已支持。

保持唯一连接 Provider / DTX owner;不引入第二套连接内核。采用“全源准备、采集与展示解耦、单次解码增量派生、有界实时视图、增量报告封存”。放弃只增加超时、扩大缓存及停止后全量重放作为默认路径。代价是需要新的持久化检查点和恢复机制;收益是实时开销不随会话历史无限增长。

2. 已确认的用户规则 ​

  • 选择设备:准备连接、公共服务和能力探测。
  • 选择应用:准备全部可用常规指标源,也准备启动分析与截图源。选中曲线不是 Adapter 列表。
  • 开始:全部已就绪常规源开始实际采集;未显示的指标继续记录,完整报告保留它们。
  • 启动分析与截图:提前准备,但仅勾选时实际启用。准备不意味着持续产出重型数据。底层必须短暂启动以验证就绪时,探测有预算,结束后释放探测缓存;状态标为 prepared,不冒充已持续 armed。
  • 启动分析选中:启动前建立有效源与时钟边界,唯一一次冷启动。普通采集也只发送一次普通启动请求;失败不静默重复启动。
  • 截图选中:默认沿用当前频率,用户设置与会话记录一致;退出勾选的生效时机在会话开始冻结。会话中曲线增删即时生效,启动/截图设置下次会话生效并明确提示。
  • Mac 实时曲线固定最近 60 秒,随单调时间向左移动,所有图表共用窗口;无新点时也不伪造数据。最终报告保留完整时间跨度,按需加载。
  • 不修改目标应用、不注入;缺失写 null 和原因,真实 0 保留;单源失败不阻塞其他常规源。必要连接或目标身份失败才阻止开始。

3. 八项问题与证据边界 ​

最近两份匿名留存会话暂称 A/B,后续验证用本地私有映射确认用户测试对应关系。A 约 82.61 秒、80 sample、Raw 18.54 MB;B 约 19.02 秒、15 sample、Raw 267.49 MB。时长并非 Raw 大小的唯一决定因素。

问题当前事实 / 假设修复与关闭条件
启动全部 missing两份 decodedRecordCount=0、span=0;B 有 liveQueueDropCount=19。源格式/覆盖存在缺口,尚未定位唯一根因审计原始头、分片、时钟、丢失、生命周期归属;源解码通过后才进入阶段映射。可控因果测试后再验证商店应用;无证据不补猜测阶段
Mac 滚动卡顿图表重复调用 playbackPoints;该属性每次排序整个 points。可见窗口虽为 60 秒,计算仍依赖历史 N。主线程占比尚未实测固定窗口缓存、预先排序、后台分段、可见区域渲染;滚动性能及 RSS 随时长稳定
Frame Time missing两份 acceptedRecordCount=0;A ignored=5,B unknown=27/ignored=17恢复有效逐帧源、时钟及连续性;逐帧输出与独立回放一致,再校准归属与单位
Memory / XcodeMemory 相同两者当前均读 physFootprint;后者是 candidate-alias同源明示,拒绝伪造独立口径;与工具同窗对照前保持 candidate-alias
AvailableMemory 61.1当前 vmFreeCount×VMPageSizeBytes,只代表空闲页口径;尚未逐点复核该值核对原始页数、页大小来源、单位和取整;不能拿整机空闲量与进程占用作大小正确性判据。完整可回收容量另立证据门禁
GPU 三项相同留存 Raw 有 45/44/45、3/2/3,也有完全相同;不是“同值即错误”三个原始字段→metricID→Wire→图表逐层追踪;禁止互相 fallback;空闲/动画/负载同窗核查
Thermal Status missing稳定当前等级源仍开放查明受支持系统回包与枚举;未获得源前展示 source-missing,不用温度或通知名称推算
GPU Counter 等待旧批已知 schema/heartbeat 不代表 data row;当前两份无 gpu.counter.raw,尚需核对选择和 Adapter 生命周期区分未启动、探测失败、schema-ready、首行超时、有效行与断流;源及单位具证据才关闭
停止随负载变慢delivery.py 串行校验、metrics、frames、report、startup、launch_trace、mapping、calibration;多次读/解码风险增量派生、封存检查点;停止后不扫描全量 Raw;完整报告与独立审计分开标识

以上表格将内存两项拆开说明,但用户八类问题范围不变。留存 finalizer 子阶段耗时合计 A 约 0.818 秒、B 约 3.585 秒,仅包含已记录阶段,绝非点击停止到报告的端到端耗时。需新加完整边界测量。

4. 状态机与并发所有权 ​

Disconnected → DevicePreparing → DeviceReady → AppPreparing → Prepared → Starting → Recording → CaptureStopped → Sealing → ReportReady。

每个源独立记录 unprobed/preparing/prepared/activating/streaming/missing/failed/timed-out、原因、最近有效时间和证据级别。全局 Prepared 表示必要源可运行,展示可运行源数量与失败项,不把全部指标宣称 ready。

应用、设备、指标配置绑定 generation。切换应用立即取消旧准备,迟到回包不得推进新 generation;断线、锁屏、失效 tunnel 触发重新验证。开始期间禁止重复提交;停止幂等;starting 期间也能取消,取消后禁止迟到 launch。停止超时后隔离旧 owner,未确认释放前不复用其 socket。

DTX 单 reader 只分发,不做大 JSON、base64、重解码和磁盘 fsync。每个流保持源内顺序。控制通道优先、普通源与重型源分队列;并发探测建议上限 2,协议要求串行的服务仍串行。writer 单所有者;重型解码优先采用单个受控 worker,线程受 GIL 限制时用对照数据决定是否迁移独立进程,避免盲目增加线程。截图单并发,不允许定时任务堆叠。

启动窗口启用后必须先接收有效就绪信号再 launch;激活时间计入 click-to-launch。若临时激活超过目标,明确展示 activating,禁止为了“秒开”先启动再丢 prelaunch 证据。准备 TTL、激活耗时与跨源冲突进入基线测试。

5. 轻量数据管线与一致性 ​

text
唯一设备连接 / 单 DTX reader
  → 小型有序 Envelope + 有界分发
  → Raw 单 writer(持续哈希、分段索引、检查点)
  → 一次解码 → 普通指标 / Frame / Startup 增量引擎
  → 完整派生流与报告聚合持久化
  → 实时窗口快照 → 可见图表

Raw 记录是事实源,派生事件携带 raw sequence、算法版本、源质量与 generation。跨源只按可证明时间关系合并。存储 schema 若升级必须加版本、新旧读取兼容和 fixtures,旧会话不回写。

建议重型内存队列维持当前 64 MiB 上限作为起点,32 MiB 预热预算不盲目扩大。按观测 p95 吞吐 R 配置服务能力至少 1.5R,2R 短突发验证缓冲;磁盘落后时显式积压/丢失事件。磁盘 spool 亦设可配置容量和剩余空间阈值,满盘触发 partial 并停止受影响源,不无限缓存。

主机流式哈希只能证明主机所收记录的完整性,不证明设备无丢失。写盘与派生分别维护 durable sequence;checkpoint 仅在相应 fsync 成功后推进。停止时 seal_sequence 必须被全部必要派生引擎消费。崩溃恢复从最后 durable checkpoint 回放尾段,重复 sequence 幂等;保留离线全量审计命令,但不强制放进每次点击停止关键路径。

6. 固定窗口图表 ​

设总事件 N、窗口秒数 W=60、采样率 r、可见曲线数 V、绘图宽度 P。

  • 当前路径反复排序/扫描,单次更新可达 O(V×N log N),并分配中间数组。
  • 新路径样本进入有界时间队列,均摊 O(1);乱序在有界窗口内归并,迟到点保留完整记录并标注,不全历史重排。
  • 窗口存储 O(指标数×r×W),绘制 O(V×min(rW,2P));共享最新时间和窗口快照,禁止每条曲线重新排序。
  • 用像素桶 min/max 保留尖峰、质量断点及桶内顺序;统计从全精度流计算,不从显示降采样反算。
  • 默认快照刷新上限 5 Hz;滚动时可降到 2 Hz,停止滚动恢复。后台状态只发布小型 immutable 快照。
  • 懒加载并跟踪实际可见性,屏幕外图表暂停绘制;完整数据仍落盘。截图缩略图后台解码,独立有界缓存;原图按需读取。
  • 最终报告采用分段索引、多分辨率曲线,完整范围可浏览,缩放后加载细节,不一次加载整场所有点到主线程。

7. 随开随停与 2 秒报告合同 ​

下列是待批准的目标预算,不是已测成绩。使用 host monotonic 时间,设备启动阶段继续使用其证据时钟,不混用。

边界目标计时与适用条件
点击→UI 状态反馈p95≤100ms、max≤200msMac 本地;包括 starting 时取消
已准备→唯一 launch 请求p95≤500ms含启动源实际激活;普通/启动两种模式分测,设备请求完成另记
点击→关闭采样边界p95≤100ms、max≤200ms关闭样本接纳,不等于设备已释放;晚到 drain 事件隔离为收尾数据
设备源关闭与 lease 释放p95≤1s、max≤2s正常设备;异常分支限时隔离,不能将超时称成功释放
普通 Raw 接收→Wirep95≤250ms首点 warmup 不补 0;慢频率源不套用 250ms 首次出值目标
点击停止→完整报告 ready每个验收样本≤2s从点击开始计时,含 drain、持久化与索引封存;不是只测绘制摘要

报告 2 秒要求在明确的产品支持规模内验证,初始矩阵 1/10/30/60 分钟,Raw 20 MB/300 MB/1 GB、全部常规源与两项可选源组合。更大规模不能自动推定通过。报告 ready 必须包括截至 seal 的完整常规曲线、统计及每个选中源的终态质量。深度源本身缺失可显示 missing 原因,正在积压计算不得伪装完整报告。若未满足尾段预算,显示 finalizing/积压与原因,该样本判 2 秒门禁失败。

为避免把重任务转移到采集中导致新卡顿:每秒观察 queue lag、decode throughput、writer throughput、主线程帧耗时和设备扰动;持续服务率低于输入率时门禁失败。离线 schema 研究、未知码 census、全量二次审计不属于用户报告必需产物,可显式后台独立执行,状态单列。

8. 指标口径处理与资料门禁 ​

本方案不修改现有数学公式。实施前每个口径变更必须先更新对应 Canonical 页十要素、历史记录和测试。

  • Memory/XcodeMemory:现有 physFootprint 原始 bytes 保留,UI 明示同源 candidate-alias。独立 gauge 需新证据后再命名,不人为做差。
  • AvailableMemory:逐点校验 freeBytes=vmFreeCount×pageSizeBytes;展示若使用 MiB 为 /1048576,若 MB 为 /1000000,按实际产品合同统一并标明。负计数、页大小未知时 missing;整机总容量、空闲容量、可回收容量分开。61.1 尚未完成数值验证。
  • GPU:Renderer/Tiler/Device 独立取字段、保持原始百分比,缺字段置空;同值合法性以 Raw 链为准。当前范围为 foreground-device,不宣称进程专属。
  • Startup/Frame:先拿到完整可解析流,再证实时间桥、连续性、目标归属与阶段语义。禁止因为 unknown=0 就判语义正确;零记录也可能 unknown=0。
  • Thermal:必须观察到明确当前等级回包、枚举与稳定读取,温度或通知事件不替代状态。
  • GPU Counter:必须取得实际 data row、counter schema、设备/系统适配和单位;heartbeat 不计数值样本。建议首行 10 秒超时,恢复需重新出现合法行;低频源阈值以实际协议验证调整并入档。

若在固定版本实验中仍无源,交付研究结果和所需资料,不承诺通过工程重构创造该能力。所需资料:对应系统版本的匿名原始协议回包、受控负载/阶段标记及同窗结果;付费账号或凭据不写入文档。当前无需再次换连接库。

9. 分批实施与依赖 ​

批次工作产物与通过门禁
R0 基线与可观测性两份留存重放;端到端时标、主线程 profile、队列/CPU/RSS/I/O 基线;确认版本及会话对应匿名机器证据和基线;有时间戳不等于 E4 修复
R1 全源准备与策略解耦采集配置/展示配置分开;准备状态机、generation、幂等开始停止、选项冻结、源独立失败常规曲线全隐藏仍采全量;两项可选准备但未启用时无持续 Raw;设备切换和取消测试
R2 实时窗口与主线程瘦身固定窗口缓存、可见性、后台分段、截图缩略图;移除全历史排序60 分钟采集滚动性能不恶化、完整落盘点数不减少;与基线比较
R3 单次增量派生与报告封存writer/checkpoint、共享解码、分段报告、恢复、尾段预算离线独立 replay 与在线派生一致;崩溃/满盘/断连;每轮完整报告≤2s
R4 启动/Frame 源闭环解码格式、分片头、时钟、loss、生命周期/帧语义逐层验证可控正负例和因果测试,再目标应用 E4;没有源证据保持 partial
R5 内存/GPU/Thermal/Counter逐点映射、同源解释、字段审计、状态反馈、数据行补齐原始到显示证据链;Thermal/Counter 未取得真实值则该项保持开放
R6 整体验收与发布全源+可选组合、长短会话、数值回放、资源开销与公证产物站点归档、签名公证/独立安装、窄范围提交双推送、Webhook

依赖 R0→R1→R2→R3;R4/R5 复用 R0 证据并在 R3 后做完整回归,R6 汇总。用户批准本方案后逐批开发,每批有独立结果与开放门禁;未经批准不启动实施。资源与耗时目标以实验收敛,不用未验证工期承诺替代技术门禁。

10. 测试与效率预算 ​

以下预算待基线确认后由用户批准调整,禁止测试后降低标准以宣称通过:

  • 主线程常规更新 p95≤8ms;滚动帧 p95≤16.7ms(60Hz 显示环境);>100ms 主线程阻塞为零。区分测试机器与刷新率,保留录制/profile 证据。
  • 图表及缩略图增量缓存目标≤64 MiB;30→60 分钟稳态 App/Sidecar RSS 增长各≤10%,排除正常初次缓存后再统计,同时记录绝对峰值。
  • 报告 CPU/RSS/I/O 单独计量;持续主机 CPU 较 R0 同负载不得回退超过 10%,CPU 明确按单核 100%计。新增全源负载与旧少源模式不能直接作优化对比,另做等源 A/B。
  • 吞吐目标持续≥1.5×实测输入 p95,2×突发 10 秒不静默丢数据;临界吞吐/磁盘空间不足明确 partial。
  • 展示与采集独立测试:默认全常规源;曲线 0/3/全部;Startup×截图四组合;窗口边界、乱序、missing/0/重置、峰谷、应用切换、取消、锁屏、断线、短存储、进程崩溃和重启恢复。
  • E2:真实 Raw 尺寸回放与合成极端各至少 20 轮;必须含真实大 payload,不以 byteLength 小占位模型替代内存压力。固定输入校验 hash、依赖版本、运行环境和算法版本。
  • E4:每种实际接入系统独立验收,正常短会话每组合≥3轮;10/30/60分钟各至少1轮,再对最差组合重复3轮。iOS 15+/26/27 无相应设备就保留待测,不外推。
  • 数值验证区分原始传输、目标归属、数学计算、外部同窗对齐。启动与逐帧关键语义由受控 fixture 因果证明,不仅用同一解码器自证。
  • 完整报告≤2s 每轮都检查,另报告 p50/p95/max、样本数、失败比例;设备释放单独报告。禁止只呈现最优轮或忽略 timeout。

11. 交付与回滚 ​

仅方案阶段:Markdown、HTML 快照、时间线登记、构建与链接检查、窄范围提交、双远程推送尝试及 Webhook。本文前述均为设计,不宣称开发完成或数值已修复。

实施后:增量写入/报告 schema 和窗口实现均保留受控 feature flag;回滚不破坏新旧 Session 读取,切换只在会话边界生效。性能退化、sequence 丢失、报告 hash 不一致触发暂停推广并保留证据。

正式产品交付需 Developer ID、Notary accepted、staple、Gatekeeper、独立解包/安装与 SHA-256;证书/公证或法务未就绪保持 partial,不把内部包冒充正式包。每批本地窄提交并对两个远程分别记录结果,保留既有无关工作区变更。

交付最终汇报前发送企业微信 Webhook,地址从环境变量或 Keychain 读取且不输出;仅 HTTP 2xx 且 errcode=0 视为成功。失败交付标 partial 并说明重试方式。

12. 当前进度与下一阶段 ​

本轮完成 E1 修复方案;已知八类问题仍开放,旧 E2 测试数不等于新体验通过。下一阶段等待明确批准后执行 R0 基线及 R1 策略解耦,再按 R2~R6 收口。64 项 Registry 是合同定义数量,不是 64 项在所有系统均具备 E4 数值能力。

代码溯源:MacApp/Sources/PerfowlCore/SessionTimeline.swift 的 playbackPoints;MacApp/Sources/PerfowlApp/PerfowlWorkbenchView.swift 的 WorkbenchMetricChart/segments;MacApp/Sidecar/perfowl_collector_core/{realtime,recording,delivery,metric_engine}.py。历史证据:上一轮修复、最终 HEAD 回归。

Perfowl · Performance Observer