Skip to content

Perfowl 1.0.0 内部正式版发版 ​

Owner 2026-11-03:在分版本能力表工作之前先发正式第一版;只发给公司内部同事试用,不对外发布;站点信息更新,下载按钮保持不可下载。2026-11-02 以来各项修改 Owner 已真机确认通过。

一、范围 ​

  • 版本 1.0.0,从推送到全部远程的 main 构建,内容等同内部包 251 + 本批文档;不夹带新功能。
  • 卡顿(Hitch)只做逐帧数据保留与离线重算,界面不显示,不属于本版功能。
  • 分版本能力表与自动判定排在发版之后(方案)。

二、发版门禁 ​

项要求
回归Python 全量(失败只能是既有 16 项环境基线);Swift 全量 0 失败
签名Developer ID Application 签名 App 与 DMG,codesign --verify --deep --strict
公证提交 Apple Notary Service 成功、ticket stapling、stapler validate、spctl Gatekeeper 接受(此前内部包按 Owner 决定暂缓,本版必须完成)
安装独立解包核对、本机同址安装、启动器唯一
校验DMG SHA-256
标签v1.0.0 指向发版提交,推送 GitHub 与 GitLab
站点下载页与首页写明 1.0.0 内部版已发布、仅限公司内部;不提供下载链接与安装包

构建脚本改动(发版前必需):build-app.sh 目前给包内 329 个嵌套二进制签名时不带可信时间戳(--timestamp=none,为内部包打包快),而 Apple 公证要求每个二进制都带时间戳,照现状提交会被拒。新增环境变量 PERFOWL_NESTED_TIMESTAMP=1:嵌套二进制改用 --timestamp(预计多 3–6 分钟,仅发版用,内部包不变);PERFOWL_RELEASE_CHANNEL 写入 PerfowlReleaseChannel(默认仍为 internal-beta,本版为 internal-release)。首次发版构建(d1d417b0)在第 300 余个二进制处遇到时间戳服务未返回时间戳(“A timestamp was expected but was not found”)而失败,于是每个嵌套签名最多重试 3 次、间隔 2 秒;第二次构建(624ccfc5)在第 109 个二进制处 3 次均报 “The timestamp service is not available”,随后单独测试服务已恢复,判断为间歇性不可用或限流(推断),改为指数退避最多 6 次(2/4/8/16/32 秒,累计约 1 分钟),仍失败才终止。公证流程:App 打 zip 提交 → stapling App → 用已 stapling 的 App 做 DMG → 签名 DMG → 提交 DMG → stapling DMG。

GPL-3.0:本版仅公司内部分发,不触发对外分发的法务门禁;对外发布前仍须正式法务结论。

三、发版说明(给内部同事) ​

能做什么

  • 无侵入测试 iPhone 上任意 App 的性能:不改包、不重签、不注入。
  • 实时指标:截图、启动耗时、FPS、帧耗时、显示性能、CPU(进程 / 整机 / 每核)、内存、GPU、线程、上下文切换、唤醒、磁盘、温度、网络(进程 / 整机)、电池(Wi-Fi 连接且未外接供电时)、能耗、GPU Counter。
  • 会话本地保存,可回看、导出报告(PDF / 表格)与多会话对比。
  • 工具箱:设备信息;应用管理(导入 IPA、卸载、查看与导出应用文件、签名类型标识);崩溃日志导出与删除。

使用要求与已知限制

  • macOS 13 及以上;双架构(Intel 与 Apple 芯片原生运行)。
  • 真机验证以单台 iOS 26 设备为主;iOS 16、17.0、18.2 有连接与基础指标证据;iOS 15、17.4+ 等版本未逐项验证,见能力表计划。
  • 部分指标仍为候选口径(与 PerfDog 未逐项校准),报告中按原样标注;缺失值显示为空,不显示为 0。
  • 测试中被测 App 不能在工具箱中卸载。

四、执行记录 ​

(发版完成后追加:提交号、DMG、SHA-256、公证提交号与结果、Gatekeeper、安装与启动器、标签、站点核对。)

方案变更 · 2026-11-03:改为双架构(Intel + Apple 芯片) ​

Owner 要求 1.0.0 为双架构包。已构建的 Intel 单架构候选(build 252,4d82ac67)不作为正式版。

可行性(E2):本机(Intel)swift build -c release --arch arm64 --arch x86_64 230 秒完成,主程序同时含 x86_64 与 arm64。三个 Python 冻结组件(pymobiledevice3、采集器、采集核心)PyInstaller 只能在同架构主机上冻结,必须在 Apple 芯片 Mac 上完成;该流程已于 2026-10-18 在 Apple 芯片主机跑通(ARM 冻结方案),运行时按 Tools/<arch> 选择组件。

分工:

  1. Apple 芯片主机上的 AI(Implementation 角色)从指定 main 提交执行 MacApp/scripts/build-app.sh(不签名,ad-hoc),只取产物中的 Contents/Resources/Tools/arm64/ 与 Contents/Resources/Licenses/libusb-LGPL-2.1.txt,连同清单打包为 perfowl-arm64-tools-<提交前 8 位>.tar.gz,上传到 GitHub 私有仓库的草稿 Release(gh release create arm64-tools-<提交前 8 位> --draft),不进 git 历史(约 230 MB 二进制不应永久进入两个远程的历史);不推送任何代码修改。
  2. 本机下载该附件,核对清单与架构,build-app.sh 新增双架构模式组装:主程序 universal、Tools/x86_64 本机冻结、Tools/arm64 取自附件;全部用 Developer ID 重新签名(带时间戳),公证、stapling、Gatekeeper。
  3. 附件对应提交与发版提交之间,MacApp/Sidecar 与冻结脚本必须无差异,否则拒绝组装。
  4. 发版前 Owner 在 Apple 芯片 Mac 与 Intel Mac 上各实测一次(E4)。

清单 manifest.json 字段:sourceCommit、hostArch、macOS、python、pymobiledevice3、pyinstaller、每个文件的相对路径 / 字节 / SHA-256、三个组件的实际运行检查输出(perfowl_collector_core probe、pymobiledevice3 version、perfowl_collector --help 退出码)、Mach-O 架构统计。不写主机名、用户名、设备标识。

公证凭据:Owner 要求由 Claude 保存。Claude 没有账号密码;为免密码进入对话记录,请 Owner 提供 App Store Connect API 密钥文件(.p8)路径与 Key ID、Issuer ID,由 Claude 以 notarytool store-credentials --key 存入本机钥匙串,密钥内容不进入仓库、日志或对话。

Implementation Update · 2026-11-03:双架构组装模式 ​

build-app.sh 新增 PERFOWL_ARM64_TOOLS_DIR(指向解开的 arm64 附件,含 Tools/arm64、Licenses/libusb-LGPL-2.1.txt、manifest.json):

  • 只允许在 Intel 主机上组装;读取清单 sourceCommit,该提交须在本地仓库,且与当前提交在 MacApp/Sidecar 与 MacApp/scripts(除 build-app.sh 本身)上无差异,否则拒绝;
  • Swift 以 --arch arm64 --arch x86_64 构建,主程序必须同时含两种架构;
  • Tools/x86_64 照旧本机冻结,Tools/arm64 用 ditto 原样复制(保留符号链接),其中每个 Mach-O 必须只含 arm64;
  • Info.plist 新增 PerfowlArchitectures、PerfowlArm64ToolsCommit;签名循环覆盖两套组件,arm64 的 ad-hoc 签名被 Developer ID(带时间戳)替换。

验证(E2,未签名本机实验构建):缺附件 → 拒绝;清单提交为 f14465c7(Sidecar 不同)→ 拒绝;arm64 目录混入 Intel 二进制 → 在主程序双架构检查通过后拒绝。首次运行时双架构判断写法有误(相邻架构名共用空格导致误判),已改为逐词判断并复测通过。正向组装待 arm64 附件到位。

公证凭据:按 Owner 要求检索项目记录,未找到已配置的凭据——build 50–52 验收记录均为 notaryCredentialProfileAvailable: false,2026-10-18 迁移交接写明“恢复正式交付时安全配置 notary 凭据,不从旧日志抽取密码”,私有构建目录无相关配置。仍需 Owner 提供。

Validation Update · 2026-11-03:Apple 芯片主机首次构建失败与调整 ​

Apple 芯片主机(macOS 15.3.1、Swift 6.1.2)从 b236168a 运行 build-app.sh,34 秒后在 swift build 失败:SessionReportView.swift:160 的 overview(_:) 视图表达式“unable to type-check this expression in reasonable time”。本机 Xcode 的 Swift 版本可编译同一源码(双架构 230 秒通过),判断为较旧 Swift 6.1.2 类型推断超时(推断)。ARM 冻结环境(Python 3.12.10、PyInstaller 6.22.3、pymobiledevice3 11.3.1、libusb 1.0.29)完好,单独冻结 pymobiledevice3 成功。

调整:Apple 芯片主机不再编译 Swift(主程序由本机双架构编译),只用三个冻结脚本产出 arm64 组件,并显式设置 PERFOWL_CORE_PYTHON 指向 venv-py312-arm64。源码提交改为 e10ed16d(与 b236168a 在 Sidecar 与冻结脚本上相同)。Swift 6.1.2 下的编译超时登记为遗留:发版后拆分该视图表达式,使较旧 Xcode 也能从源码构建。

Validation Update · 2026-11-03:公证凭据与试公证 ​

  • Owner 提供 App Store Connect API 密钥;以 notarytool store-credentials perfowl-notary --key … --key-id … --issuer … 存入本机钥匙串,苹果校验通过。密钥文件、路径与 ID 不进入仓库与日志。
  • 用 Intel 单架构候选 build 252(不发布)试公证:首次上传在 S3 加速通道 3 分钟超时(deadlineExceeded,未进入审核);加 --no-s3-acceleration 重试,6 分 39 秒返回 Accepted,日志 0 个问题、“Ready for distribution”(E3)。确认全部嵌套二进制带时间戳 + hardened runtime 的签名方式可通过公证;正式发版脚本同样使用 --no-s3-acceleration。

执行记录 · 2026-11-03:双架构 1.0.0(build 253) ​

  • arm64 组件:Apple 芯片主机从 d4748af3 只运行三个冻结脚本(未编译 Swift),产出草稿 Release 附件 101,245,647 字节,SHA-256 8636d86c…238ac;本机下载后 SHA-256 一致,清单 12,893 个文件大小与哈希逐一一致,30 个符号链接均指向包内;对方报告 342 个 Mach-O 全为 arm64,probe ready、pymobiledevice3 11.3.1、采集器帮助退出码 0。附件含 macOS tar 自动生成的 15,147 个 ._* 扩展属性文件,解压时排除。对方首次 build-sidecar.sh 因未设 PERFOWL_PYINSTALLER_PYTHON 退出 127,设置后成功。
  • 组装:main 3451c370(与 d4748af3 在 Sidecar 与冻结脚本上相同),545 秒;主程序 x86_64 + arm64;647 个嵌套 Mach-O 全部 Developer ID 签名且带时间戳。
  • 公证:App 提交 05354a47 Accepted 并 stapling;首次打包脚本随后在包内核对失败——核对工具按 Intel 单架构编写,要求每个 Mach-O 含 x86_64;改为 Tools/arm64 下必须纯 arm64、其余必须含 x86_64 后从断点继续,已 stapling 的 App 未重复公证。DMG 提交 0fa41153 Accepted 并 stapling。
  • 产物:Perfowl-1.0.0-253-macos-universal-internal.dmg,294,367,964 字节,SHA-256 f9663e90c93adf7c7ceb9085884f4ef4223934a274c97fd083cb1999be0f0288。
  • 验证(E3,本机 Intel):codesign --verify --deep --strict 通过;spctl 结果 source=Notarized Developer ID(退出码 0);stapler validate 通过;安装后目录树与 DMG 一致;x86_64 冻结核心 109 个模块与源码一致、CLI 一致、probe ready;回滚包 251 已校验;启动器唯一。
  • 未完成:Apple 芯片 Mac 实测(arm64 组件在本机无法运行)与 Intel Mac 实测(E4)由 Owner 进行;通过后打 v1.0.0 标签、发布站点、发送通知。

发版阻断 · 2026-11-03:采集核心启动即崩溃(内部包 246–253) ​

  • 现象:Owner 在 Intel Mac 上用 253 选择设备与应用后,右上角一直显示“正在准备应用采集服务”。本机进程中没有采集核心。
  • 复现:按界面同样参数手动运行包内 perfowl_collector_core stream --prewarm,启动即退出:UnboundLocalError: cannot access local variable 'asyncio'(perfowl_collector_core_cli.py main)。
  • 原因:e6ce454c(2026-11-02,查看文件)在 main() 的 container 分支内写了局部 import asyncio,Python 因此把整个 main() 中的 asyncio 视为局部变量,stream(预热与采集)和 screenshot-worker 两个命令在到达设备前就崩溃。probe、container、工具箱均不经过该变量,所以包内自检与工具箱测试都没有暴露问题。影响内部包 246–253 的全部性能采集。
  • 修复:删除该局部导入(模块顶部已导入)。新增测试 test_main_dispatches_stream_and_screenshot_worker:断言 main 没有名为 asyncio 的局部变量,并实际分派 stream 与 screenshot-worker;撤掉修复时该测试失败、修复后通过(E2)。修复后源码对设备 A 预热:hello → provider → device_ready 正常(E3)。
  • 遗留:采集核心在握手前崩溃时,界面一直停在“准备中”而没有显示失败原因,单独排查。包内核对应增加一次真实的 stream --prewarm 冒烟测试(不只 probe),防止同类问题再次带进包里。
  • 处置:build 253 作废(不发布、不打标签);两种架构都需从修复后的提交重新冻结并重新公证。

Implementation Update · 2026-11-03:标题栏调整(Owner 发版前反馈) ​

  • 去掉标题栏的内部版本号 “Foundation v0.3”。
  • 图标与下方左栏卡片左边缘对齐(Owner 选择):系统窗口按钮(红黄绿)单独占顶部 28 点高的一条,品牌与连接状态放在其下 44 点高的一行,左边距 12 点与左栏一致;连接提示横幅相应下移。标题区总高度由 48 点变为 72 点。
  • 只改 Swift 界面;Sidecar 与冻结脚本未变,arm64 组件(31c8ccbc)继续有效。Swift 459 项 0 失败;本地调试版截图核对位置(E3)。

执行记录 · 2026-11-03:双架构 1.0.0(build 254) ​

  • 源码 main e3ca7780(含采集核心修复与标题栏调整);arm64 组件来自 31c8ccbc(Sidecar 与冻结脚本与发版提交相同),草稿 Release 附件 100,765,751 字节,SHA-256 8d8daece…cdeac9,本机核对 12,893 个文件一致,无 ._ 文件;对方四项检查含 stream --prewarm 首条输出 hello、无 Traceback。build 253 作废。
  • 构建 601 秒;主程序 x86_64 + arm64。App 公证 3e804f33 Accepted,DMG 公证 cb8e40d2 Accepted,均已 stapling。
  • 产物 Perfowl-1.0.0-254-macos-universal-internal.dmg,288,609,671 字节,SHA-256 846eba12dbcc9340fea352a156d7e11a9f75713f58fb2d3e8671342eaaacaa33。
  • 本机验证(E3):严格签名、spctl source=Notarized Developer ID、stapler validate 通过;安装树与 DMG 一致;x86_64 核心 109 模块与源码一致;包内新增冒烟测试 stream --prewarm 首条 hello;回滚包 253;启动器唯一。另用已安装核心对设备 A 走完预热:hello → device_ready → prepare_app_accepted → source_preparation → app_ready(被动观察、不拉起应用,约 2 秒)。
  • 待 Owner 在 Intel 与 Apple 芯片 Mac 上实际开始一次性能测试(E4)。

Validation Update · 2026-11-03:真机验收与发布 ​

  • Intel Mac(E4):Owner 用 254 完成一次约 4 分钟性能测试(设备 A,iOS 26),会话正常结束、数据完整。整场 FPS 平均 4.56、FTime 平均 5,480 ms 由静止主导:236 秒中 197 秒无新帧,9 个超过 1 秒的静止空档合计 206 秒(最长 60 秒);有帧时逐帧间隔中位 12.5 ms。候选卡顿算法重算:动画 12.4 秒、6 次、5.6 ms/s(candidate,未校准)。登记遗留:报告需标注有效动画时长,避免整场平均误读。
  • Apple 芯片 Mac(E4):Owner 确认测试通过。
  • 发布:v1.0.0 附注标签指向构建提交 e3ca7780,推送 GitHub 与 GitLab;站点下载页与首页标注 1.0.0 内部正式版已发布、不提供公开下载。

Perfowl · Performance Observer