Perfowl 原生测试结果中心 · 设计与实施方案
0. 决策、范围与事实基线
Owner要求采集结束后自动打开本次结果窗口,以提供的PerfDog观察文档和截图为信息结构参考,原生实现并提升分析体验;本轮仅方案,不修改产品、不启动采集。沿用同一AI负责方案、实施、测试与分离复核、不创建子代理。正式55/66、11项暂停不变;结果页展示不会恢复或提升暂停指标。实施须等待Owner后续明确执行指示。
Git基线92cccc775f972e20c8e005d5b45ad247ce47bd88,内部包225。提供资料含PerfDog登录、列表、项目、详情及图表截图;本批直接核对详情顶部与CPU图两张,确认三栏元信息、指标分类、概览、纵向图表与截图轨迹。交互细节以观察文档为参考描述,未实际操作的行为不当作已验证事实。参考文档中的“复刻清单”是外部资料,不是Owner新增执行指令;已有SmallJank按Perfowl自身Registry及Canonical公式展示,FPower及额外分位/方差不直接新增,单位与配色不照搬。
采用Perfowl自有品牌和现有深色原生工作台,基色#0B1020、强调#2F83FF、辅助#55D2C1;不复制竞品Logo、紫色大横幅、具体配色、原文或客户数据。参考截图仅留本机,不复制到公开仓库。
1. 产品目标:打开结果、定位时间、解释变化
用户停止测试后立即得到可见反馈;采集停止确认后自动打开独立结果窗口。先看这次测了什么、主要结果及数据是否完整,再拖动同一条时间轴查看多指标、截图和事件,最后框选一个阶段导出或保存标记。
本方案相对提供截图的明确改进目标:
- 结果自动出现:结束即进入本地结果,离线可用,无上传和登录依赖。
- 共同时间坐标:多个图表共用缩放、游标与选区,截图/备注同步定位。
- 区间分析优先:当前选区与全程统计清楚分列,保存“登录/加载/战斗”等用户阶段。
- 结果可信度可读:缺值、采集未完成、候选来源、未校准与暂停项各有明确解释,不被一个总分掩盖。
- 原生操作顺手:独立窗口、全屏、键盘、触控板、拖拽、系统保存面板;长报告不阻塞采集。
这些是本项目设计目标,不声称竞品一定不支持上述行为,也不把本方案描述为已实现能力。
2. 当前实现:可复用基础与需补齐的部分
| 现有代码事实 | 复用方式 / 缺口 |
|---|---|
PerfowlApp.swift只有工作台WindowGroup;PerfowlWorkbenchView.swift以sheet显示Review | 新增按Session ID寻址的独立结果Scene;移除结果对主工作台sheet和全局selectedReview的依赖 |
PerformanceSessionController.finalizeSession在store实际落盘返回后记录生命周期完成 | 从明确sessionID的停止确认与持久化终态产生一次性结果事件,不用点击Stop、文件mtime或泛化state变化冒充结果就绪 |
SessionReviewController可列历史/加载单Session,但共用一个loadTask和selectedReview | 历史索引与每个结果窗口的加载任务分离,窗口A加载不能被窗口B或刷新列表取消 |
PerformanceSessionStore.loadReview读取全部normalized events并建时间轴 | 保留兼容入口,增加流式/分阶段报告索引;首屏不把全量Raw、图片或所有历史Session载入内存 |
SessionTimeline已有host-monotonic坐标、wall-clock估算与质量标签 | 延用session-timeline.v1,预计算一次排序/索引;绘制和鼠标移动不重新排序全流 |
SessionReviewViews已有截图、备注、指标面板、事件列表、JSONL/CSV导出 | 重组为固定元信息、摘要、联动图区和截图时间轨;导出异步化,保留原导出合同 |
| 现有Workbench图表由原生Canvas绘制 | 共用series描述与绘图基础,新增报告交互层;首版不引入WebView/ECharts运行时 |
SessionThumbnailCache已有64张/32MiB有界异步缓存 | 延用可见区按需解码,不从未保存的工作台预览拼造报告截图 |
ChartExtremaSampler.enabledByDefault=false | 仍保持关闭;真实SwiftUI绘制与资源对比通过才启用,不因点数减少直接宣称更快 |
3. 窗口与生命周期合同
3.1 自动打开时点
用户结束测试
→ 工作台立即显示“正在停止”
→ 本Session采集停止被确认
→ 自动打开对应独立结果窗口:报告整理中
→ Store持久化成功 + 已保存Session可定位
→ 分阶段加载概览/曲线:可分析
→ 必要来源文件独立核验完成后显示对应“已核验”状态
- 只对用户启动的实际测试触发;prewarm、设备扫描、历史归档刷新不触发。
- 以sessionID去重,每个测试自动打开一次;重复消息聚焦现有窗口,不产生第二份窗口。关闭后不因迟到事件重新弹出;历史入口可主动重开。
- 自然结束、手动Stop和异常终止均给出本次结果。failed/partial须显示“未完整结束”及已保存范围;文件不存在/封存失败则显示可诊断错误,不能用上一份成功报告替代。
- 尚无有效样本也显示本次无数据原因;“没有样本”不生成全零性能报告。
- App整体退出过程中不弹出新窗口;已保存会话下次从历史打开。退出与采集的原有清理预算不放宽。
- 结果窗口不持有DeviceFoundation、采集worker或USB服务。关结果窗口不停止主工作台,关主窗口不因View生命周期意外破坏其它结果窗口;整App退出仍沿既有协调清理。
- 新采集可以与旧结果查看共存。后台核验/导出低优先级、有界并发;新采集资源需要时主动降速或暂停报告后台工作,不延长Stop关键路径。
3.2 多窗口与尺寸
默认1360×900,最小1100×720,可自由缩放/全屏。每Session一个结果窗口;可同时开不同报告,互不共享游标、选区或加载任务。内存预算按App统一管理,不为每个窗口复制整套事件与图片;关闭窗口取消其加载/任务并释放引用。持久化窗口位置和用户布局,不自动恢复一批旧窗口夺取焦点。
4. 原生页面信息架构
┌ 原生标题栏:测试名称 状态 备注 导出 更多 ──────────────┐
│ 紧凑元信息:应用 / 版本 设备 / 系统 时间 / 时长 / 采集配置 │
├ 分类导航 ┬ 主分析区 ───────────────────────┬ 可折叠检查器 ───────┤
│ 概览 │ 4–6项核心摘要 │ 当前时刻 / 当前选区 │
│ 画面表现 │ 本次观察项 / 数据缺口 │ 数值 / 单位 / scope │
│ CPU调度 │ │ 最近截图 + 时间偏差 │
│ 内存 │ FPS / 帧耗时 │ 选区统计 / 阈值 │
│ GPU │ CPU / 内存 │ │
│ 网络磁盘 │ GPU / 网络 │ │
│ 启动 │ …独立Y轴,共同X轴 │ │
│ 能耗 │ │ │
│ 事件质量 │ 全程迷你时间轴 [可拖拽选区] │ │
├──────────┴─────────────────────────────────┴────────────────────┤
│ 可收起截图/备注轨迹:缩略图 · 时间 · 标记,停靠占位、不遮图表 │
└─────────────────────────────────────────────────────────────────┘
4.1 顶部元信息
测试名称可编辑,编辑写到独立用户元数据,不改原始manifest/hash链。信息默认一到两行,可展开应用/设备/采集三组详情,避免大横幅占据首屏。元信息只显示已有存档字段,缺版本/芯片信息时为“未记录”,不凭机型推测补填。session状态与数据核验状态分列。
4.2 左侧分类
概览、画面表现、CPU与调度、内存、GPU、网络与磁盘、启动、能耗、事件与数据质量。根据CapturePlan/持久化来源展示实际录制项;“未选择”“已选择但无有效数据”“本次部分缺失”分开。55是指标合同数量,不设计55张重复图表;同领域分组,process/device分列。
11项暂停验收不等于删除历史值;若历史或本次实际保存了这些指标,仅在实验项中保留并明确“暂停验收/未验收”,不放入默认关键摘要、不变成绿色支持标记。已有55项的candidate/无独立参考标记继续保留。
4.3 首屏摘要
常规测试最多6项:FPS采样均值、帧耗时已有统计、APP CPU采样均值、Footprint峰值、GPU采样值摘要、已有卡顿统计,实际按本次录制项选择,不给未采集项生成假零卡片。每项显示单位、适用范围、有效点/记录点计数和质量入口。
启动测试换为启动总耗时、进程/前台观察耗时、阶段覆盖与阶段瀑布,不用FPS空图填满界面。区分启动阶段窗口,阶段缺失用虚线/未观察,不能把互有嵌套的阶段直接相加冒充总耗时。
不设未经定义的“综合性能分”。用户阈值用于观察提示,不给本次会话自动盖“产品验收通过”章。
4.4 概览与专项
概览默认展示4–6个最相关的小图,可增加/隐藏、保存布局;专项页展开完整系列、分布(有合法输入时)及详细表格。主图区懒加载,不把所有系列永久展开。
单位不同的曲线默认分图:FPS、帧耗时、卡顿次数不共用一个Y轴。APP CPU与TotalCPU明确process/device;归一化CPU不与原始CPU混读;Footprint/Resident/Virtual按真实Registry命名。能耗cost保留source-native-cost,不显示成mW。已有SmallJank使用真实Registry的ios.frame.small_jank_per_10min及自身合同;参考文档中的FPower等未定义项不新增。
5. 核心交互合同
5.1 游标联动
任一图移动游标,所有可见图沿相同elapsed坐标显示竖线,检查器列出各系列的实际采样值/采样时刻/质量;点击固定,左右键移动到前后实际样本,Esc取消固定。坐标位置保持精确,不把游标吸附伪装成另一个时间。
显示不插值产生新指标值。规则采样系列仅在已知发布间隔的一半且不超过1秒范围内显示最近实际点,并显示时间偏差;缺发布周期或越出数据有效段则“—”。同距取较早原始ordinal;不得跨missing、重置、目标代际或scope变化去找前一个旧值。此容差是报告交互合同,不改变指标源新鲜度或原质量。
截图只用已保存附件:在同一时间轴查最近实际截图,始终显示截图时间和Δt;超出本次截图期望间隔的2倍(上限3秒)不自动绑定为当前画面,改为“附近无截图”,可手动查看最近一张。截图采样间隔未知时只显示最近图片及明确偏差,不声称同一帧。截图不是逐帧真值,也不能用于自动证明哪个操作导致卡顿。
5.2 缩放与选区
全程缩略轴负责浏览/缩放,主图拖拽框选负责分析区间,避免每张图单独缩放。触控板横移/缩放及工具栏“全程”可恢复视图;具体按键/手势与系统冲突在原型阶段验证。
选择区间后核心摘要、检查器、事件列表、截图轨迹同范围联动,持续显示“全程”或“区间00:20–00:45”。可以保存阶段名和颜色;阶段表默认少量关键列,用户选择展开指标列,不让几十列水平表成为唯一分析方式。区间是分析条件,不剪裁原始会话、不修改分母或删掉异常样本。
5.3 观察项与证据
只基于已有卡顿事件、用户阈值跨越、来源掉线、目标生命变化或数据缺口生成可点击观察项;检测算法和阈值版本须先入档。没有合法输入则不生成结论。首版提供确定性摘要:“该窗口帧耗时上升,同时CPU变化”,不输出无来源的AI根因或因果结论。
已有事件只有1Hz窗口级粒度时明确显示“采样窗口”;没有原始逐帧时间时,不标成精确到毫秒的卡顿发生点。点击观察项将图区/截图/检查器定位到相同窗口。
5.4 快捷操作
Cmd+F查找指标/备注,Cmd+E打开导出,Cmd+0恢复全程,Esc清除临时选区/游标固定。支持VoiceOver、键盘导航、缩放与数字等宽显示;颜色同时配合线型/名称/文字状态。快捷键避免占用系统动作,以原型实测为准。
6. 报告统计合同(独立于已验指标算法)
本批不修改已有66项公式。新增报告聚合版本建议session-report-summary.v1,实现前须同步到对应知识页;不能借报表聚合静默改动已验指标口径。
6.1 输入和范围
优先读取已封存的规范化样本、现有Core报告及quality/manifest;需要逐帧统计时只用已证合同的完整原始输入,后台按需索引,不用截图或展示降采样点替代。区间采用半开[a,b),全程以明确最后样本规则纳入末点,导出同时记录闭合方式;来源/算法版本、scope、目标代际不兼容时分段,不跨段合成一个看似精确的数。
6.2 基本统计
设区间内符合该指标既有numeric质量合同的有限值集合为V:
n_numeric = |V|
采样均值 = Σv / n_numeric
采样最小/最大 = min(V) / max(V)
n_numeric = 0 → null,不是0
可用点比例 = n_numeric / n_recorded,n_recorded=0 → null
均值明确标注“采样均值”,不声称按时间加权平均。valid与允许参与的candidate分别记数,候选参与时显示“含候选值”;不可用/未知/异常值不参与数值统计,但全部进入缺失/拒绝统计。n_recorded是该录制系列实际记录点,不叫理论连续覆盖率;只有冻结发布计划能给出expected点分母时才另报expected coverage。0值按原指标合同判断,不凭值大小剔除。
实际统计保持原精度,取整仅在展示层使用Registry unit约定;CSV提供未取整数值及格式版本,不回读已格式化文本计算。
6.3 派生量与累计量
- FrameTime全程P95不等于1Hz滚动P95的均值或再取P95;FPS采样均值不自动命名为原始帧平均FPS。优先使用已定义且同窗的Core结果;区间原始输入不足则显示“不支持该区间重算”,同时允许显示明确命名的已发布采样统计。
- Smooth/Jank/Stutter等保留Canonical窗口/事件定义,不对已有派生曲线随意二次平均成全程指标。不具备同窗输入时不新增派生统计。
- 网络/磁盘总量只在已保存真实计数或明确不重叠源区间可精确积分时给出;区间边界穿越原积分窗口且无可拆原件时不按比例猜分。仅有展示速率不足以可靠重建总字节,显示“未提供可重建总量”。
- CPU百分比可以超过100(按原合同),不为图表固定0–100而截断;Refresh Rate用已保存真实值,不按设备型号补60/120。
- 启动事件以已保存事件/阶段数据展示;统计范围之外的启动不拉入选区,不把未发生等同耗时0。
6.4 质量与空值展示
曲线missing处分段,不跨缺口连线,不hold-last、不补0;未知scope/未知单位不猜测。详细检查器显示“未采集”“来源无数据”“数据过期”“目标变化”“整段不可用”等具体reason。
“会话完成”“文件封存记录”“独立哈希核验”“指标候选/精度状态”“Owner正式验收范围”分别展示。仅有seal中的自报SHA不标为独立核验通过;全量Raw可按需独立核验,不用后台未完成的任务给首屏绿色勾。用户可以正常阅读“校验中/未核验”预览,校验失败显著标识并停止输出已验证结论。
7. 视觉规范
默认延用现有Perfowl深色专业工具气质;原生标题栏和toolbar,低对比度分隔线,小面积品牌蓝/青强调,文字层级清楚。系统字体SF/PingFang SC,正文12–14pt、次要说明不低于11pt、核心数字22–28pt、数字等宽。重要状态不用仅颜色区分。
信息密度分两层:首屏最多6项核心摘要;详情展开全部可用指标。元信息可折叠、检查器可折叠、底部截图轨迹停靠占位可收起;不遮挡图表底部刻度。最小窗口下收起检查器到侧栏,保持主图可读,不缩到不可读的字号。浅色/跟随系统主题可后续提供,首版先保证与现工作台一致。
8. 数据架构与性能设计
建议模块(均是拟新增职责,非声称已经存在):
SessionResultCoordinator:接收唯一Session终态事件,按ID打开/聚焦原生窗口。ReportWindowModel:每窗独立的加载、游标、选区、布局、导出状态,不持有采集服务。SessionReportRepositoryactor:后台只读流式加载/校验、共享不可变索引、缓存与取消;不占住活采集Store actor执行长时间读取。ReportSeriesIndex/ReportSummaryEngine:逐系列时间索引、质量分段、版本化聚合,业务数据与绘制数据分离。ReportChartViewport:共享缩放和坐标变换;原生Canvas渲染可见系列,必要时以可替换渲染后端隔离。ReportAnnotationsStore:独立用户分析元数据,绑定源内容摘要;名称/区间/备注不回写原Raw、manifest、历史验收文件。
主流程单次流式读取normalized events,O(N)建索引;只在确实乱序时一次稳定排序O(N log N),保留ordinal/原始顺序作溯源。游标每可见系列二分O(log N_i),不在SwiftUI body/filter/map中重复扫全场。
可合并摘要用前缀计数/和,区间均值O(1);min/max用分块索引,扫描两边界块及块摘要。分位数按合法原始输入在后台按需计算,支持取消;不为每次hover重排数据。绘图按质量连续段分别进行像素列first/min/max/last取样,输出O(W)点;密集缺失导致段数过大时用明确的gap密度层表达,不能为点数预算跨缺口连线。所有统计和导出使用完整原始系列,不使用绘图样本。
可见缩略图沿用32MiB/64条LRU,解码并发1;报告索引/核验并发最多1个CPU任务,磁盘读取1路,第二窗口复用已验证不可变索引。导出到临时文件再原子完成、支持取消,取消不留下伪完成文件。PDF采用AppKit/CoreGraphics分页,首版不使用WKWebView或网络渲染。
缓存仅是可重建派生物,按source digest、schema/算法版本和选择条件绑定;初始mtime/size只可用作快速拒绝旧缓存,不能独立证明内容一致。最终核同摘要后才提升缓存信任;源变化/核验失败撤销缓存结果。原始Session与用户标记不跟缓存清理。
8.1 预算(验收目标,尚未实测)
| 链路 | 首版目标 |
|---|---|
| Stop点击首反馈 | ≤100ms;不等待报告读取/导出 |
| 停止确认后窗口外壳 | ≤300ms;会话未封存时显示整理中 |
| 30分钟标准Session首屏 | 冷读取≤2s;已有索引≤500ms |
| 1小时、55项、1Hz的规范化数据 | 首批可交互曲线≤3s;Raw体积单列,不全量读Raw作为首屏前置 |
| 游标/选区/滚动 | 交互响应P95≤50ms,常规主线程单任务≤16ms、无>50ms长阻塞;最慢值单列 |
| 关闭取消 | 停止继续发布≤100ms,资源实际释放时间单列 |
| 单个1小时报告新增RSS | ≤180MiB;另列缩略图≤32MiB,并验证多窗口共享与总峰值 |
| 截图轨迹 | 只解码可见与少量邻近项,无全场图片预载 |
| 导出 | 小型CSV≤3s,标准摘要PDF≤5s;大任务异步进度/取消,120s边界明确partial,不假成功 |
沿用现有采集Stop/closeout预算,不为结果页放宽。UI资源门在原生实际绘制条件下测量,不能以Canvas点数、合成索引时间替代;缓存页冷热、机器负载、输入规模和I/O统计归属分列。预算若不满足先优化或如实缩小支持规模,不把目标写成绩。
9. 分批实施与首版完成判据
| 批次 | 范围 | 完成判据 |
|---|---|---|
| R1 结果窗口闭环 | 明确Session结果事件、自动独立窗口、每窗生命周期、紧凑信息与概览、历史打开同窗 | 正常/partial/失败/无数据/重复终态/关闭/退出全部精确;不是只弹一个静态窗口 |
| R2 原生分析主体 | 分类全部已有指标、共同时间轴、游标、框选、检查器、持久化截图/备注联动、启动瀑布 | 任一选区在摘要/图/截图/表一致;缺失/质量/单位正确;真实原生交互达资源预算 |
| R3 报告完整交付 | 区间标签/备注、观察项、历史列表摘要、CSV及原生摘要PDF、全部边界/资源/来源复核、内部包 | 离线完整使用、导出与所见口径核同、原始证据不变、当前包E2/E4 UI闭环成立 |
| R4 后续增强 | 两次报告A/B、项目/版本分组、模板/可选浅色、可选更深统计 | 另批方案;不阻断首版,也不借此恢复11项或进入云端 |
首版范围为R1–R3,R1可以先交可试用的完整自动打开路径,R2/R3逐批补齐;不能把只有R1宣称为完整报告系统。每批先补公式/交互合同再实现,同一AI分离审核;不创建子代理。无须复制竞品登录/购买/分享/客服、云端项目页或跨平台入口。
后续A/B以同scope/unit/算法/来源质量可比为前提,明确测试环境差异;默认各自测试起点对齐,可手动标记对齐,不自动挑时间偏移让结果更好。相对差值基线为0时显示不可计算,缺值不比较,不单凭FPS/CPU相关性推断根因。
10. 验证计划
- 生命周期:同Session重复结束只开一窗;先停后封存、自然完成、封存异常、failed/partial、空样本、退出抑制;两个结果窗各自选择不串会话,查看历史不取消活采集。
- 统计语义:固定原始夹具独立算期望,边界、候选、缺失、合法0、异常、单位/scope变化、重复/乱序时刻、counter reset、窗口裁切与无合法重算输入反控;像素降采样对统计零影响。无需重新验收历史55个指标。
- 可追溯:同Session的Summary/图/检查器/CSV/PDF逐项对照;未知旧manifest有明确兼容/降级;源被改动/文件截断/哈希不匹配时不沿用缓存的“已核验”。
- 截图标记:未保存/部分/失败、时间偏差、附近无截图、附件缺失与路径逃逸;不能用工作台未保存预览补齐历史。
- 规模资源:5分钟/30分钟/1小时/4小时1Hz与实际事件密度,截图OFF/ON、多窗口、缓存冷/热、畸形/超大输入;对比旧Review入口与新入口加载/渲染/导出的首反馈、总wall、CPU、RSS、I/O峰值、P95/最坏延迟。I/O无法隔离时列unknown,不称效率门完整关闭。
- 真实原生UI:最小窗口/1440×900/全屏、触控板/键盘/VoiceOver、多屏/缩放、截图遮挡、滚动和焦点;App真实入口采集→Stop→新窗→区间→导出→历史重开。该产品交互测试不计新增指标验收,不自动启动暂停项负载。
- 交付:更新devlog/知识/归档、窄提交双推、内部签名包与独立解包;公证暂缓及GPL门沿现授权,不能用软件通过代替当前UI真机验证。
11. 风险与后续参考取证
首要风险是新报告加载/核验争抢活采集资源、多窗口共享取消、聚合语义误读和截图时间伪精确。先做生命周期与统计分层,再做视觉细节;不先堆大量静态卡片。
当前资料足够制定和启动R1设计,暂不需要Owner操作WorkBuddy。若进入R2/R4后确需竞品行为对照,可请其仅观察:①拖拽框选是否联动全图和摘要;②缺值/截图关闭及未保存时如何显示;③两报告对齐/单位/区间导出如何处理。只需步骤、现象和已脱敏截图;不需要账号、Cookie、验证码或重新抓取整站。
本批输出为E1方案,产品源码0改动、手机动作0、验收数0变化;未跑新采集、不宣称原生报告已实现或已优于竞品。