36 KiB
设备窗口 #1 运行手册(wave 1,Redmi 2f7cbe2e)
本文是 PLAN-PH-P34B-P7.md §3 wave 1 的可逐条粘贴执行稿:一次
reboot-clean 会话里打三笔债——P7-7 实验 E0–E3、P6.5 残余的 39 例 DirectGLES TCP golden
矩阵、P3b/P4b + P7 出口门 5 的 CTS $BASE。
它不做什么。 不改任何源码,不调阈值,不删用例。每一步都先说明什么结果支持哪个假设, 再说明证据落在哪里。没有跑到的步骤写进
unrun.md,不按「大概没问题」记过。
设备由集成者独占;本手册假定执行者就是持机的人。所有命令块都标了它跑在哪个 shell 里:
[Win] = Windows(PowerShell 或 Git Bash,adb 在这一侧),[WSL] = WSL Arch。
0. 设备与环境事实(不要重新发现)
来自 ../p65/validation-status.md 与
../../../../tools/device_bench/pin_device.sh 的 2f7cbe2e 行:
| 事实 | 值 | 出处 |
|---|---|---|
| 设备 | Redmi M332BF / SM8750 / Adreno 830v2,aarch64 | pin_device.sh:73-74 |
| LAN IP | 192.168.21.181 |
validation-status.md:130 |
| GPU 钉频上限 | 1050 MHz(本板 thermal_pwrlevel=1 闩死,max_gpuclk 只读 1050000000) |
pin_device.sh:85-97 |
| 大核 / 小核钉频 | policy6 1958400,policy0 1555200 |
pin_device.sh:82 |
| 绝对时间可比性 | 不可与 35d0befa 的行比较(那台还能到 1100) |
pin_device.sh:92-93 |
| 测试包 | top.mobilegl.plugin.trace(可用 MOBILEGL_TRACE_PACKAGE 改) |
run_android_retrace_local.py:34-64 |
| Doze 状态文件 | /home/swung/.cache/mobilegl/tcp-server/2f7cbe2e-top.mobilegl.plugin.trace.json,内容 originally_whitelisted=false |
validation-status.md:211-213 |
| 已知真机 DirectVulkan 分歧 | 两次观测 0.988998 / 0.976494,inproc 与 spawn 一致,同 pbuffer 的 monolith = 1.0 | CURRENT_STAGE_PROGRESS.md:158-160 |
| 已知 GLES 失败 | minecraft-1.21.11-main-menu SSIM 0.890161(trace 的 UBO offset 不满足本机 32 字节对齐,非分离缺陷) |
../p65/mainmenu-trace-difference.md |
| 出口门 3 分母排除 | minecraft-1.21.4-rd12-odinlite-in-world、create-indirect(OQ-17 dev 侧崩溃) |
ID-P7-4 |
--use-pbuffer 在本机的 DirectVulkan 上是可用的:CURRENT_STAGE_PROGRESS.md:158 记的
monolith 1.0 就是同一 pbuffer 口径取的。(tools/cts/README.md:120-124 说 DirectVulkan 的
pbuffer 在 Adreno 上不可用——那条只针对 CTS 的 dEQP platform 端口,retrace 走 MobileGL 自
己的 EGL,两者不是同一条路径。若当天 E0 的 DirectVulkan pbuffer 臂在 eglMakeCurrent 上红,
改用窗口表面重跑并在证据里写明换了口径,不要把它当成分歧。)
证据根目录(每一步都写进去):
docs/Disaggregated/notes/p7/device-window-1/
00-session/ boot id、pin 前后、APK 身份、设备信息
E0-attribution/ 归属与重复确定性
E1-lockstep/ RUN_AHEAD=0 对照
E2-credit/ PRESENT_CREDIT 1 vs 3
E3-caps/ 两臂 caps 日志比对
P65-tcp-matrix/ 39 例 DirectGLES TCP golden 矩阵
CTS-base/ monolith × DirectVulkan 的五个块
unrun.md 窗口内没跑到的步骤,逐条写明原因
.trace-work/ 与 /home/swung/ 下的原始产物不入库;入库的是 result.json、
*-actual.png(只在分歧 case 上)、summary.json、transport-proof.json、pin-*.txt、
run.json 和各步的一段结论。大于 ~2 MiB 的原图留在 WSL 并在文里记绝对路径与 SHA-256。
1. 窗口前置(不占设备时间,前一天做完)
-
主机工具自测(全部不需要设备、不需要 GPU):
# [WSL] 在本窗口要用的那棵树里 cd /home/swung/w7/p7-runner python3 tools/trace_replay/test_run_tcp_matrix.py # 18 tests, OK python3 tools/trace_replay/test_compare_actuals.py # 10 tests, OK python3 tools/trace_replay/compare_actuals.py --self-test python3 scripts/ci/tcp_lane_tools_test.py # 6 tests, OK python3 tools/trace_replay/test_android_lifecycle.py # 含 SpawnServerPath 的解析门 -
构建并签名 APK(
-Pmobilegl.debuggableRelease=true不是可选项:没有它 release APK 不可run-as,trace-replay-ci.sh取不到私有角色日志,而「没有库日志」与 「跑了但没产生日志」在结果里长得一模一样,见tools/device_bench/p6/README.md):# [WSL 或 Win] 见 tools/device_bench/p6/README.md「Building the APK」 gradle --no-daemon -p <tree>/android-plugin :app:assembleTraceRelease \ -Pmobilegl.buildDisaggregated=ON -Pmobilegl.buildDisaggregatedInproc=ON \ -Pmobilegl.pipePush=ON -Pmobilegl.debuggableRelease=true \ -Pmobilegl.applicationIdSuffix=.p7w1 -Pmobilegl.apkSuffix=p7w1 apksigner sign --ks ~/.android/debug.keystore --ks-pass pass:android \ --ks-key-alias androiddebugkey --key-pass pass:android \ --out MobileGL-plugin-trace-release-p7w1.apk <unsigned>.apkapplicationIdSuffix让它并排装在既有 trace 安装旁边(两个不同签名的 APK 不能共用 application id,adb install -r会INSTALL_FAILED_UPDATE_INCOMPATIBLE)。用它就必须同时 设MOBILEGL_TRACE_PACKAGE,见 §3。 -
主机侧 TCP 矩阵的制品先备好(第 7 步用):一份 WSL 的
libMobileGL.so+mobilegl_trace_replay,以及ctest --show-only=json-v1的 catalog。两端必须共享同一个 显式MOBILEGL_BUILD_STAMP,否则MOBILEGL_IPC_REQUIRE_SAME_BUILD=1会在握手上拒绝。 设备上的 server 也必须是本次构建(wave 2-F 起 TCP 握手换成了「一条连接 +Welcome.dataNonce」): 新 APK 的 server 对旧 client 会回Refuse{WireFingerprint},但旧 APK 的 server 对新 client 没有任何 Refuse 帧——旧 supervisor 等第二条连接 2000 ms 后把两条都关掉(设备日志only 1 of 2 connections arrived),主机侧只看到MG_Remote client: no Welcome ... (rc=6);看到这条先回 §3 核对apk-install.txt的lastUpdateTime,再怀疑别的:# [WSL] cd /home/swung/w7/p7-runner ctest --test-dir build-split --show-only=json-v1 > /home/swung/p7w1-catalog.json sha256sum build-split/libMobileGL.so build-split/<...>/mobilegl_trace_replay \ > docs/Disaggregated/notes/p7/device-window-1/00-session/host-artifacts.sha256 -
CTS 的 caselist:见 §8 —— 树内生成不了,必须在窗口前解决,否则第 8 步只能记 unrun。
2. 会话开始:reboot-clean、钉频、唤醒(~10 min)
# [Win] 0) 记下重启前的 boot id,重启,再记一次。两者相同 = 没有真的重启,按失败处理。
adb -s 2f7cbe2e shell cat /proc/sys/kernel/random/boot_id | tee 00-session/boot-id-before.txt
adb -s 2f7cbe2e reboot
adb -s 2f7cbe2e wait-for-device
adb -s 2f7cbe2e shell 'while [ "$(getprop sys.boot_completed)" != 1 ]; do sleep 2; done'
adb -s 2f7cbe2e shell cat /proc/sys/kernel/random/boot_id | tee 00-session/boot-id-after.txt
# 1) 唤醒并让屏幕别灭。Dozing 时 native supervisor 会停在 do_freezer_trap,
# 前台 Service 的 partial wake lock 显示 DISABLED(validation-status.md:141-143)。
adb -s 2f7cbe2e shell input keyevent KEYCODE_WAKEUP
adb -s 2f7cbe2e shell svc power stayon usb
adb -s 2f7cbe2e shell dumpsys deviceidle get deep | tee 00-session/deviceidle-before.txt
# 2) 钉频。需要 root(脚本自己会先验 su)。0=PINNED / 1=DRIFT / 2=UNPINNED。
bash tools/device_bench/pin_device.sh 2f7cbe2e pin | tee 00-session/pin-session-start.txt
bash tools/device_bench/pin_device.sh 2f7cbe2e check | tee 00-session/pin-check-00.txt
纪律:每一个臂开始前 check、结束后再 check。 任一次不是 PINNED,那个臂的数据作废
(status: UNPROVEN),不降级使用。check 的三值语义见 pin_device.sh:19-31。
判别:
boot-id-before≠boot-id-after⇒ 窗口是 reboot-clean 的;相同 ⇒ 重启没发生, 停下重来,不要把它记成干净窗口。
3. APK 安装身份(~5 min)
# [Win] 注意:Git Bash 里若设了 MSYS_NO_PATHCONV=1,adb.exe 收到 /c/... 会 "failed to stat"——
# APK 参数用 Windows 路径($(cygpath -w ...));设备侧 /data/... 路径才需要 MSYS_NO_PATHCONV。
# flavour 后缀在 applicationIdSuffix 之后:包名是 top.mobilegl.plugin.p7w1.trace。
adb -s 2f7cbe2e install -r "$(cygpath -w MobileGL-plugin-trace-release-p7w1.apk)"
adb -s 2f7cbe2e shell pm list packages | grep mobilegl | tee 00-session/packages.txt
adb -s 2f7cbe2e shell dumpsys package top.mobilegl.plugin.p7w1.trace \
| grep -E 'versionName|lastUpdateTime|codePath|nativeLibraryPath' | tee 00-session/apk-install.txt
sha256sum MobileGL-plugin-trace-release-p7w1.apk | tee 00-session/apk.sha256
# 等 dex2oat 退出再开始任何臂:一条 am_kill ... due to installPackageLI 落在臂里量的是安装器。
adb -s 2f7cbe2e shell 'n=0; while pgrep dex2oat >/dev/null && [ $n -lt 150 ]; do sleep 2; n=$((n+1)); done; echo "dex2oat idle after $((n*2))s"'
# (`pgrep -f dex2oat` 会匹配到承载这条循环的 sh 自己,永远不退出;按进程名匹配。)
# 本窗口的其余步骤都要看得见这个 id:
export MOBILEGL_TRACE_PACKAGE=top.mobilegl.plugin.p7w1.trace # [Win] 每个 shell 都要设
export MOBILEGL_TRACE_SKIP_INSTALL=1 # 已装好,别让每个 case 再装一次
判别:
00-session/apk.sha256+apk-install.txt的lastUpdateTime是这组图像由哪个二进 制产生的唯一答案。run_android_retrace_local.py --archive-dir写的run.json里也会带 同一个apk_sha256(它自己重新算,所以两者不一致本身就是发现)。
4. E0:分歧归属与重复确定性(~1.5 h)
问题:DirectVulkan 的 0.988998 / 0.976494 是哪些 case贡献的?同一个 case 跑三遍是不是 逐位相同?
窗口预算说明(必须读)。 39 例 × 2 传输 × 3 遍 = 234 次回放,按每例 45–90 s 计约 3–4 h,一个窗口里放不下它加第 7、8 步。所以 E0 拆成 E0a 普查(1 遍)→ E0b 确定性 (只对分歧集 + 两个对照 case 跑 3 遍)。判别力不受损:确定性问题只对已经分歧的 case 有 意义。若当天时间充裕,E0b 直接把
--case换成--matrix就是完整版。
E0a:一遍全矩阵,得到分歧 case 列表(~50 min)
# [Win] 对照臂:monolith。这是「同 pbuffer 下 DirectVulkan 本来是 1.0」的复验。
bash tools/device_bench/pin_device.sh 2f7cbe2e check | tee E0-attribution/pin-before-monolith.txt
python tools/trace_replay/run_android_retrace_local.py \
--matrix --backend DirectVulkan --use-pbuffer --transport monolith --repeat 1 \
--archive-dir .trace-work/p7w1/E0a-monolith \
2>&1 | tee E0-attribution/E0a-monolith.log
bash tools/device_bench/pin_device.sh 2f7cbe2e check | tee E0-attribution/pin-after-monolith.txt
# [Win] 验收臂:inproc。同一进程内跨真实 ring 到 apply 线程;--require-inproc 由脚本自动带上。
bash tools/device_bench/pin_device.sh 2f7cbe2e check | tee E0-attribution/pin-before-inproc.txt
python tools/trace_replay/run_android_retrace_local.py \
--matrix --backend DirectVulkan --use-pbuffer --transport inproc --repeat 1 \
--archive-dir .trace-work/p7w1/E0a-inproc \
2>&1 | tee E0-attribution/E0a-inproc.log
bash tools/device_bench/pin_device.sh 2f7cbe2e check | tee E0-attribution/pin-after-inproc.txt
--matrix 取的是 manifest 的 CI split 子集(39 例),按各 case 自己的 ci_backends 过滤
(DirectVulkan 下是 39 例,DirectGLES 下是 38 例,差的一例是 DirectVulkan-only 的
iterationrp)。--all 会多带上 ci:false 的 rd12——ID-P7-4 把它排除在出口门 3 的分母外,
所以这里用 --matrix,不用 --all。
iterationrp 需要 apk.yml 的三个 Magma 旋钮(.github/workflows/apk.yml:460-462,原文逐字):
# [Win] 只在跑 iterationrp 时导出;它们由 trace-replay-ci.sh 自己读环境,不走 --env
export MOBILEGL_MAGMA_FIX_ITERATIONRP_SUBGROUP_SCRATCH=1
export MOBILEGL_MAGMA_DERIVE_NUM_SUBGROUPS=1
export MOBILEGL_MAGMA_ITERATIONRP_FIX_BARRIER=1
create-indirect 与 rd12 按 ID-P7-4 排除:它们在 dev@81b17c0b 就在 Adreno 830 上坏,不是本
分支造成的。rd12 不在 --matrix 里;create-indirect 在,所以它的红单列,不计入出口
门 3 的分母(在 E0-attribution/exclusions.md 里写清楚,别在汇总表里悄悄删行)。
汇总:
# [WSL 或 Win]
python3 tools/trace_replay/compare_actuals.py summary .trace-work/p7w1/E0a-inproc \
--json E0-attribution/E0a-inproc-summary.json | tee E0-attribution/E0a-inproc-summary.txt
python3 tools/trace_replay/compare_actuals.py summary .trace-work/p7w1/E0a-monolith \
--json E0-attribution/E0a-monolith-summary.json | tee E0-attribution/E0a-monolith-summary.txt
判别:monolith 全 1.0 而 inproc 有 N 个 case < 阈值 ⇒ 分歧属于分离路径,且那 N 个 case 的名字就是 wave 2 的工作清单;monolith 也分歧 ⇒ 问题不在分离,在 Magma 本身(整条 run-ahead / credit 线索出局,E1/E2 不必跑,直接进 E3 与 wave 2-B)。
证据:E0-attribution/{E0a-*-summary.json,E0a-*.log},以及只对分歧 case 归档的
*-actual.png + result.json(从 .trace-work/p7w1/E0a-inproc/<case>-DirectVulkan/repeat-01/
拷进 E0-attribution/divergent/)。分歧 case 名单写成 E0-attribution/divergent-cases.md。
E0b:分歧集 × 3 遍 × 两传输(~40 min)
# [Win] $D = E0a 得到的分歧 case,逐个 --case;外加两个 E0a 通过的 case 作对照
python tools/trace_replay/run_android_retrace_local.py \
--case <divergent-1> --case <divergent-2> ... --case <control-1> --case <control-2> \
--backend DirectVulkan --use-pbuffer --transport inproc --repeat 3 \
--archive-dir .trace-work/p7w1/E0b-inproc 2>&1 | tee E0-attribution/E0b-inproc.log
python tools/trace_replay/run_android_retrace_local.py \
--case <同一组> --backend DirectVulkan --use-pbuffer --transport monolith --repeat 3 \
--archive-dir .trace-work/p7w1/E0b-monolith 2>&1 | tee E0-attribution/E0b-monolith.log
python3 tools/trace_replay/compare_actuals.py summary .trace-work/p7w1/E0b-inproc \
--json E0-attribution/E0b-inproc-summary.json | tee E0-attribution/E0b-inproc-summary.txt
汇总表的列就是要回答的问题:case × repeat × ssim_vs_golden × ssim_vs_first × bit-identical。
ssim_vs_first 用的是 result.json 自己记的 crop,和 ssim_vs_golden 描述同一个矩形;
SSIM 的实现是 retrace 门自己的那一个(trace_replay_core.cpp:630/:671 的逐字转写)。
判别:三遍
bit-identical=yes⇒ 分歧是确定性的,可以在桌面上用固定输入追(E4/E5 有 意义,RenderDoc 抓一次就够);三遍不逐位相同、ssim_vs_first < 1⇒ 分歧带时序/竞态成分, 先看 E1(run-ahead 排队)再谈内容路径,且任何单次截图的对比都不可作结论。
5. E1:MOBILEGL_IPC_RUN_AHEAD=0 的 lockstep 对照(~20 min,判别力最高)
这是 §0 结论 3 说的「从未在 golden 口径下跑过、且不需要改任何代码」的那个实验。
# [Win] 与 E0b 完全相同的 case 集、相同 pbuffer、相同 3 遍,只多一个 --env
bash tools/device_bench/pin_device.sh 2f7cbe2e check | tee E1-lockstep/pin-before.txt
python tools/trace_replay/run_android_retrace_local.py \
--case <与 E0b 同一组> --backend DirectVulkan --use-pbuffer --transport inproc --repeat 3 \
--env MOBILEGL_IPC_RUN_AHEAD=0 \
--archive-dir .trace-work/p7w1/E1-inproc-ra0 2>&1 | tee E1-lockstep/E1.log
bash tools/device_bench/pin_device.sh 2f7cbe2e check | tee E1-lockstep/pin-after.txt
python3 tools/trace_replay/compare_actuals.py summary .trace-work/p7w1/E1-inproc-ra0 \
--json E1-lockstep/E1-summary.json | tee E1-lockstep/E1-summary.txt
证明 lockstep 真的生效的那一行日志
不能指望 running lockstep。 那句话来自 MG_Remote/Client/ClientSession.cpp:1877-1879:
MG_Remote client: run-ahead requested, server does not publish kCapRunAheadApply -
running lockstep. The selected backend has not enabled its implementation-readiness gate
它的守卫是 else if (MG_Config::Ipc.RunAhead != 0 && m_barrierArmed)(:1873)——即
「旋钮开着但 server 没有那个 cap」。RUN_AHEAD=0 时这一句根本不会打印,
LatchRunAheadFromCaps 一行也不打。所以证据是一条在 + 一条不在:
| 必须出现 | 出处 |
|---|---|
Config: IPC ring=... verb-barrier=1 run-ahead=0 present-credit=... strict=1 ... role-split-state=1 |
ConfigLoader.cpp:459-462,只在非 monolith 打 |
Config: MOBILEGL_TRANSPORT=inproc - the MGPipe record stream |
ConfigLoader 的 inproc 臂,pull 库写不出来 |
| 必须不出现 | 出处 |
|---|---|
MG_Remote client: run-ahead ARMED - the server publishes kCapRunAheadApply |
ClientSession.cpp:1869-1872 |
# [Win/WSL] 逐遍核对,三遍都要
for r in .trace-work/p7w1/E1-inproc-ra0/*/repeat-*; do
echo "== $r"
grep -c 'run-ahead ARMED' "$r/mobilegl.log" || true # 必须是 0
grep -o 'run-ahead=[0-9]*' "$r/mobilegl.log" | sort -u # 必须只有 run-ahead=0
grep -c 'MOBILEGL_TRANSPORT=inproc - the MGPipe record stream' "$r/mobilegl.log"
done | tee E1-lockstep/arm-proof.txt
这个形状与 ../p5f/magma-runahead.md:120 记的一致:「Magma inproc RA=0 | 实际 Config
run-ahead=0,无 ARMED」。
已知副作用,先说在前面:
run_android_retrace_local.py --transport inproc会自动带上--require-inproc,而那个门要求Config: IPC行里run-ahead=1(android-plugin/trace-replay-ci.sh:601)。所以 E1 的每个 case 都会以非零退出码结束, 且退出发生在result.json已经拉回来之后(trace-replay-ci.sh:548拉结果、:586判passed、:587才跑 arm proof)。这不是失败:按上表自己核对Config: IPC行即可,SSIM 与 归档照常可用。把E1.log里的非零退出连同这句说明一起入库,不要为了让它绿而去掉--env MOBILEGL_IPC_RUN_AHEAD=0。
判别(本窗口判别力最高的一行):分歧 case 在 RA=0 下回到 1.0 ⇒ 原因在 run-ahead 这条 线(未等待的发布排队 / 延迟退休 / present credit),wave 2 从
ClientSession的发布路径查; 不变 ⇒ run-ahead 整条线出局,原因在 server 的内容路径(Magma 的 wire 应用),E2 的 credit 扫描多半也会不变,直接转 E3 + wave 2-B/C。
6. E2:MOBILEGL_IPC_PRESENT_CREDIT 1 vs 3(~25 min)
只在 E1 「不变」或「部分回到 1.0」时才有意义;E1 全数回 1.0 时这一步降级为确认性抽查。
# [Win] 两个臂,其余参数与 E0b 逐字相同
for c in 1 3; do
bash tools/device_bench/pin_device.sh 2f7cbe2e check | tee E2-credit/pin-before-credit$c.txt
python tools/trace_replay/run_android_retrace_local.py \
--case <与 E0b 同一组> --backend DirectVulkan --use-pbuffer --transport inproc --repeat 3 \
--env MOBILEGL_IPC_PRESENT_CREDIT=$c \
--archive-dir .trace-work/p7w1/E2-credit$c 2>&1 | tee E2-credit/E2-credit$c.log
python3 tools/trace_replay/compare_actuals.py summary .trace-work/p7w1/E2-credit$c \
--json E2-credit/E2-credit$c-summary.json | tee E2-credit/E2-credit$c-summary.txt
bash tools/device_bench/pin_device.sh 2f7cbe2e check | tee E2-credit/pin-after-credit$c.txt
done
grep -ho 'present-credit=[0-9]*' .trace-work/p7w1/E2-credit*/*/repeat-*/mobilegl.log \
| sort | uniq -c | tee E2-credit/credit-actually-applied.txt
最后那一行不是装饰:present-credit= 来自 ConfigLoader.cpp:459-462 的同一条 Config: IPC
行,它是「旋钮真的到达了库」的唯一证据。两个臂各自只应出现自己的值。
判别:credit=1(最严格的节流)下分歧消失、credit=3 下仍在 ⇒ 是帧间排队深度问题,与 E1 的结论应当一致,wave 2 查 present credit 的释放点;两个 credit 表现相同 ⇒ 排队深度不是 变量,credit 线索与 run-ahead 线索一起出局。
7. E3:两臂 caps 日志比对(~10 min,不占额外回放)
E3 不需要新回放,读 E0a/E0b 已经产生的日志即可。
# [Win/WSL] 两臂、两个角色的日志一起扫
for d in .trace-work/p7w1/E0a-monolith .trace-work/p7w1/E0a-inproc; do
echo "=== $d"
grep -rh 'CapsMirror::.* read before the first CapsSnapshot - answering a PLACEHOLDER' "$d" | sort | uniq -c
grep -rh 'the server does not consume MGPipe subsystem' "$d" | sort | uniq -c
grep -rh 'CapsMirror generation .* adopted' "$d" | sort | uniq -c
grep -rhE 'GL_(UNIFORM_BUFFER|SHADER_STORAGE_BUFFER)_OFFSET_ALIGNMENT: [0-9]+' "$d" | sort | uniq -c
done | tee E3-caps/caps-compare.txt
精确出处,免得当天去找:
| 行 | 出处 | 期望 |
|---|---|---|
MG_Remote client: CapsMirror::<accessor> read before the first CapsSnapshot - answering a PLACEHOLDER. Expected exactly once at startup, from LogBackendInfo (MG_Backend/Init.cpp:21); anything later means a caps read beat the handshake |
MG_Remote/Client/CapsMirror.cpp:47-51 |
启动期恰好一条(来自 LogBackendInfo)。多于一条 ⇒ 有 caps 读跑在握手前面,客户端在用占位能力决策 |
MG_Remote client: the server does not consume MGPipe subsystem 0x%llx - this family emits NOTHING and the legacy pull path runs for it (R-8). callMask=... |
CapsMirror.cpp:143-149 |
零条。出现即该 family 整族不过线、走 legacy pull,是分歧的一等嫌疑 |
MG_Remote client: CapsMirror generation N adopted (backend=..., callMask=0x...) |
CapsMirror.cpp:81-83 |
至少一条,且 backend 是 DirectVulkan 对应值;callMask 两臂应相同 |
GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT: 32(SSBO 64) |
MG_Util/BackendLoaders/OpenGL/Loader.cpp:1094;本机实测值见 ../p65/mainmenu-trace-difference.md |
Adreno 830 的真值是 32 / 64(Loader.h:1263-1265)。inproc 臂的 client 若打出 256(Loader.h:1261/:1266 的默认值)⇒ client 用了默认而不是远端上报的对齐 |
判别:inproc 臂出现
does not consume MGPipe subsystem或 placeholder 多于一条 ⇒ 分歧 是能力协商问题,与 run-ahead 无关,归 wave 2-C(OQ-8/OQ-10 同族);两臂 caps 逐字相同 ⇒ 能力线索出局,留下 Magma wire 应用(wave 2-B)。
8. P6.5 残余:39 例 DirectGLES TCP golden 矩阵(~2.5–3 h)
口径就是 validation-status.md:231-233 欠的那一条:WSL 作 client,Redmi 作 server,
逐例要求 run-ahead ARMED。
# [Win] 8.1 起设备端 supervisor(前台 Service),并临时豁免 Doze
python3 tools/trace_replay/tcp_device_server.py start \
--serial 2f7cbe2e --package top.mobilegl.plugin.p7w1.trace \
--listen tcp://0.0.0.0:40613 --token <TOKEN> --allow-idle \
--state-file /home/swung/.cache/mobilegl/tcp-server/2f7cbe2e-top.mobilegl.plugin.p7w1.trace.json \
| tee P65-tcp-matrix/server-start.txt
adb -s 2f7cbe2e logcat -s MobileGLServer -d | tee P65-tcp-matrix/server-ready.txt
--allow-idle 是显式选项,它把改动前的原状态存进 --state-file(重复 start 不覆盖原
值),stop 再按原值恢复——不要手工 dumpsys deviceidle whitelist -。
# [WSL] 8.2 LAN 直连。WSL 默认经 eth2/xray_tun 到手机时只回第一个 MSS
# (validation-status.md:144-146),所以加一条只针对手机的临时 host route。
sudo ip route add 192.168.21.181/32 via 192.168.31.1 dev eth0 metric 10
ping -c 3 192.168.21.181 | tee P65-tcp-matrix/route.txt
# [WSL] 8.3 正式矩阵。--require-run-ahead 强制 RUN_AHEAD=1 + VERB_BARRIER=1,
# 并逐例要求私有 client 日志有 ARMED、没有 lockstep / DISARMED。
cd /home/swung/w7/p7-runner
export MOBILEGL_BUILD_STAMP=<两端共享的显式 stamp>
python3 tools/trace_replay/run_tcp_matrix.py \
--catalog /home/swung/p7w1-catalog.json \
--runner /home/swung/w7/p7-runner/build-split/<...>/mobilegl_trace_replay \
--library /home/swung/w7/p7-runner/build-split/libMobileGL.so \
--endpoint tcp://192.168.21.181:40613 --token <TOKEN> \
--backend DirectGLES --credit 2 --require-run-ahead \
--wake-adb-serial 2f7cbe2e \
--out /home/swung/p7w1-tcp-matrix 2>&1 | tee P65-tcp-matrix/matrix.log
# 中断 / 超时后原样续跑(同一 library、runner、peer):
# ... --out /home/swung/p7w1-tcp-matrix --resume
--wake-adb-serial 2f7cbe2e 让 driver 每 15 秒打一次 KEYCODE_WAKEUP
(run_tcp_matrix.py:363-371),这是长 case 跨越息屏的唯一保险。看门狗是
300 秒无日志进展 + 7200 秒绝对上限两条独立线,和 manifest 的 timeout_seconds 无关。
一条 case 超时或留下残留进程时 driver 会停下整个矩阵(避免把对端不健康级联成一串 Busy),
checkpoint 保留;先查对端再 --resume。
预期里已经有一条红:minecraft-1.21.11-main-menu,SSIM ≈ 0.890161。它的成因已定位为
trace 的 UBO offset 不满足本机 32 字节对齐(../p65/mainmenu-trace-difference.md),单列,
不当成新发现,也不改阈值。
# [WSL] 8.4 收口
python3 - <<'PY' | tee P65-tcp-matrix/summary.txt
import json, collections
rows = json.load(open('/home/swung/p7w1-tcp-matrix/results.json'))
print(collections.Counter(r['status'] for r in rows))
for r in rows:
if r['status'] != 'passed':
print(r['case'], r['backend'], r['status'], r.get('error'))
PY
cp /home/swung/p7w1-tcp-matrix/results.json P65-tcp-matrix/results.json
每行都带 backend、golden、alternate_golden、ssim_threshold、requested_arm、
actual_arm,所以这份 results.json 自己就能回答「用哪张图、哪个阈值、实际有没有 ARMED」。
判别:38 例(DirectGLES 下 39 例里
iterationrp是 DirectVulkan-only)逐例 ARMED 且除 main-menu 外全绿 ⇒ P6.5 的这笔残余结清;出现新的红 ⇒ 按 case 名单单列,不与 DirectVulkan 的分歧混记。
9. CTS $BASE:monolith × DirectVulkan 的五个块(~1.5–2 h,可无人值守)
出口门 5 要的是「迁移落地之前的基线读数」。五个块(PLAN-PH-P34B-P7.md §1.3 出口门 5):
texture_*、shader_image_*、packed_pixels、direct_state_access.*、uniform_buffer_object*。
9.1 两个必须先解决的前置(当天临时抱佛脚会浪费整个窗口)
(a) caselist 树内生成不了。 tools/cts/ 有完整 harness,但没有任何 caselist 入库,
mustpass 清单也不在本仓:
$ find tools/cts -iname '*caselist*' -o -iname '*mustpass*' -o -name '*.txt'
(空)
本机 /home/swung/cts-src 的 checkout 里 external/openglcts/data/ 是空的,也没有任何
mustpass 文件,所以连它也生成不出来。正确做法,窗口之前做完:
# [WSL] 取一个 release tag 的完整 checkout(用 tag,不用 main,读数才可引用)
git -C "$CTS" checkout opengl-cts-4.6.8.1
python "$CTS"/external/fetch_sources.py
ls "$CTS"/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.*/ # gl46-main.txt 在这里
# 从 mustpass 切出五个块,入库到 tools/cts/caselists/p7-*.txt
cd /home/swung/w7/p7-runner
mkdir -p tools/cts/caselists
MP="$CTS/external/openglcts/data/mustpass/gl/khronos_mustpass/4.6.8/gl46-main.txt" # 以实际路径为准
grep -E '^KHR-GL46\.texture_' "$MP" > tools/cts/caselists/p7-texture.txt
grep -E '^KHR-GL46\.shader_image_' "$MP" > tools/cts/caselists/p7-shader-image.txt
grep -E '^KHR-GL46\.packed_pixels' "$MP" > tools/cts/caselists/p7-packed-pixels.txt
grep -E '^KHR-GL46\.direct_state_access\.' "$MP" > tools/cts/caselists/p7-dsa.txt
grep -E '^KHR-GL46\.uniform_buffer_object' "$MP" > tools/cts/caselists/p7-ubo.txt
wc -l tools/cts/caselists/p7-*.txt # 入库时把这几个数写进提交信息
入库这五个文件的提交要单独说明它取自哪个 tag、哪个 mustpass 文件、各多少条—— 读数只有连着 caselist 的出处才可引用。
(b) KHR-GL46 在 Android 跑器上多半够不着。 tools/cts/skills/gl-cts-on-mobilegl/SKILL.md
的全部参考读数都是 KHR-GL33,并明说「KHR-GL33 不需要解门——包注册表无条件注册它」,
暗示别的包可能被门住;README 的 4.5 读数取自桌面 lavapipe,不是设备。平台端口本身
会把包要求的版本原样传给 eglCreateContext(tcuMobileGLPlatform.cpp:401-405),所以这是
「MobileGL 的 Android EGL 能否给出 4.6 core context」+「这个 arm64 glcts 构建里有没有
KHR-GL46 包」两个问题,都没有树内证据。窗口前必须先 5 分钟验掉:
# [Win] 设备上已部署的 glcts,列一下包与其中一个块的条数(只读,不跑用例)
adb -s 2f7cbe2e shell 'cd /data/local/tmp/mgcts && LD_LIBRARY_PATH=. \
MOBILEGL_BACKEND_TYPE=DirectVulkan ./glcts --deqp-runmode=stdout-caselist \
--deqp-case=KHR-GL46.texture_\* 2>&1 | head -20'
有输出 ⇒ 按 9.2 跑 KHR-GL46.*。无输出或 context 创建失败 ⇒ 改用 KHR-GL33 的同名块,
并在 CTS-base/README.md 里写明基线的 API 版本是 33 而不是 46,AFTER 读数必须用同一个版本
(0.5 pp 是两个同口径读数的差,跨版本比较没有意义)。这是给集成者的裁定项,不是执行者当场
能定的事。
9.2 preflight 与跑
# [Win] 先 preflight,绝不跳过:它一秒内证明这台设备 + 这个库能给出 core context 且 FBO 回读正确
adb -s 2f7cbe2e shell 'cd /data/local/tmp/mgcts && LD_LIBRARY_PATH=. ./mgprobe \
--backend DirectVulkan --surface imagereader --lib ./libMobileGL.so' | tee CTS-base/preflight.txt
# 期望 PASS ... user_fbo=ok;DirectVulkan 的 default_fb=broken 是已知且不设门的
# [Win] 五个块,逐块一个 outdir。monolith 是 $BASE 的定义,所以不传任何 MOBILEGL_TRANSPORT。
for b in texture shader-image packed-pixels dsa ubo; do
bash tools/device_bench/pin_device.sh 2f7cbe2e check | tee CTS-base/pin-before-$b.txt
python tools/cts/scripts/run_cts.py \
--serial 2f7cbe2e --backend DirectVulkan \
--caselist tools/cts/caselists/p7-$b.txt \
--outdir /c/.../CTS-base/runs/$b \
--env MOBILEGL_CTS_FBO_COLOR_TEXTURE=1 \
--surface fbo --gl-config-name rgba8888d24s8 --cpu-mask fast \
--chunk-timeout 900 \
--skip-file tools/cts/caselists/p7-skip.txt 2>&1 | tee CTS-base/run-$b.log
python tools/cts/scripts/qpa_report.py /c/.../CTS-base/runs/$b --label "DirectVulkan-$b" \
| tee CTS-base/report-$b.txt
bash tools/device_bench/pin_device.sh 2f7cbe2e check | tee CTS-base/pin-after-$b.txt
done
不可省的三个参数,理由见 tools/cts/skills/gl-cts-on-mobilegl/SKILL.md「Required flags」:
| 参数 | 没有它会怎样 |
|---|---|
--surface fbo |
DirectVulkan 从默认 framebuffer 回读全零且不报 GL 错,整套读数接近 0 而与一致性无关 |
--env MOBILEGL_CTS_FBO_COLOR_TEXTURE=1 |
--surface fbo 单独不够:dEQP 的 FboRenderContext 挂的是 renderbuffer,DirectVulkan 从 renderbuffer-attached FBO 一样回读零。实测影响 46.15% → 72.74%;DirectGLES 两种方式逐位相同,是证明这个开关中性的对照 |
--deqp-terminate-on-device-lost=disable(run_cts.py 自己加,:281) |
默认 enable 会在每个 case 后调 GL 4.5 的 glGetGraphicsResetStatus(),3.3 core 里没有,第一个 case 就段错误 |
run_cts.py 的超时是**「device 侧 .qpa 900 秒不增长」**而不是墙钟上限(:66-76)——一个 chunk
合法地跑一小时,而 GPU hang 会让日志停止增长。到期它按 caselist 路径 pkill 设备侧 glcts 并报
124。它还区分「case 崩了」与「设备没了」(device_alive,:36-44),会等设备回来、重新拉那份
在 /data/local/tmp 上活下来的 .qpa,把当时打开的那个 case 记成 DeviceHang 并隔离。
结果落点:每块 outdir 下 chunk*.qpa、crashed.txt、hung.txt、unrun.txt、skipped.txt。
unrun.txt 非空就不能把这块当完整读数——qpa_report.py 会把隔离与未跑的单独列出并排除在
比率之外,照抄它的口径。
判别:五块都有
unrun.txt为空的完整读数 ⇒$BASE成立,wave 4 的 AFTER 读数按同一 caselist、同一 flag、同一 API 版本比 0.5 pp;任一块unrun.txt非空或hung.txt有新条目 ⇒ 该块只记为部分读数并把 hang 的 case 加进p7-skip.txt,下一窗口补。
10. 临时环境恢复(窗口结束必做)
顺序不能反:先停 server(它会按状态文件恢复 Doze 豁免),再撤路由,最后解钉频。
# [WSL] 1) 停测试包并恢复本次添加的包级 idle 豁免(validation-status.md:215-218)
python3 <tree>/tools/trace_replay/tcp_device_server.py stop --serial 2f7cbe2e \
--package top.mobilegl.plugin.p7w1.trace \
--state-file /home/swung/.cache/mobilegl/tcp-server/2f7cbe2e-top.mobilegl.plugin.p7w1.trace.json
# [WSL root] 2) 撤掉本次新增的临时网络辅助配置
sudo ip route del 192.168.21.181/32 via 192.168.31.1 dev eth0 metric 10
adb -s 2f7cbe2e forward --remove tcp:40615 # 若本窗口用过;40613 的 --forward 同理
# [Win] 3) 解钉频并复核。unpin 之后 check 应报 UNPINNED(退出码 2,对这个动作而言即成功)
bash tools/device_bench/pin_device.sh 2f7cbe2e unpin | tee 00-session/pin-session-end.txt
bash tools/device_bench/pin_device.sh 2f7cbe2e check | tee 00-session/pin-check-final.txt
# [Win] 4) 还原屏幕常亮,并核对 Doze 白名单确实回到会话前的样子
adb -s 2f7cbe2e shell svc power stayon false
adb -s 2f7cbe2e shell dumpsys deviceidle whitelist | grep -i mobilegl | tee 00-session/deviceidle-after.txt
00-session/deviceidle-after.txt 必须与 deviceidle-before.txt 对本包一致。不一致就地修,
不要留给下一个窗口。若本窗口用了并排安装的 .p7w1 包,明确决定是卸载还是保留,并写进
00-session/README.md——一台共享设备上留一个来历不明的安装,是下一次 A/B 的噪声源。
11. 收口清单
窗口结束时 docs/Disaggregated/notes/p7/device-window-1/ 里应当有:
00-session/:两个 boot id、pin 起止与每臂前后的check、APK SHA-256 与安装时间、Doze 前后E0-attribution/divergent-cases.md:分歧 case 名单(本窗口最重要的一件产出)+ 两臂 summaryE0-attribution/exclusions.md:按 ID-P7-4 单列的create-indirect(与未纳入--matrix的 rd12)E1-lockstep/arm-proof.txt:三遍都run-ahead=0且run-ahead ARMED计数为 0E1-lockstep/E1-summary.json与一句结论:RA=0 下回到 1.0 / 不变E2-credit/credit-actually-applied.txt:两个臂各自只出现自己的present-credit=E3-caps/caps-compare.txt:placeholder 条数、subsystem 拒绝条数、两臂callMask、UBO/SSBO 对齐实测值P65-tcp-matrix/results.json+summary.txt:逐例actual_arm,红的单列CTS-base/report-*.txt×5 + 各自的unrun.txt/hung.txt状态,以及 §9.1(b) 的 API 版本裁定unrun.md:没跑到的步骤逐条写原因
写完之后,PLAN-PH-P34B-P7.md §1.3「出口门 3」一行应当从「不可测」变成「已定位到 N 个
case,原因指向 X」——那句话就是 wave 2 派活的依据。