[Merge] (P8): integrate wave 2 package MF - the push flush ladder gets dev's Adreno 830 queued-ring-copy guard (FlushPendingRangesFrom, create-instancing x Espryt x monolith 0.870 -> 0.99998 on the Redmi), and both G5 scripts pin the two reviewed ladder bodies under ID-P8-14

This commit is contained in:
2026-09-30 07:12:50 -04:00
6 changed files with 231 additions and 78 deletions
+7 -1
View File
@@ -1490,9 +1490,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
hostBaseFrom, hostBaseTo, start, end);
}
#endif
// Read per range, like the pull arm: a ring copy staged for an earlier range of
// this same drain puts every later partial range of the store behind it
// (InvalidateFlushAccessFor's queued-copy rule, dev f973008c).
const Bool ringCopyInFlight = resource.ringCopyRetireSerial > DirectGLES::CompletedFrameSerial();
const GLbitfield access =
mapUsable ? InvalidateFlushAccessFor(start, end, coveredFrom, coveredTo, limit,
resource.storageSize)
resource.storageSize, ringCopyInFlight)
: 0u;
if (access != 0) {
BindBufferId(TempBufferTarget, resource.id);
@@ -1512,6 +1516,8 @@ namespace MobileGL::MG_Backend::DirectGLES {
BindBufferId(GL_COPY_WRITE_BUFFER, resource.id);
g_GLESFuncs.glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER,
(GLintptr)ringOffset, (GLintptr)start, (GLsizeiptr)size);
// Commands recorded now retire with the fence the next Present inserts.
resource.ringCopyRetireSerial = DirectGLES::CurrentFrameSerial() + 1;
} else {
UploadRangeFrom(resource, hostBase, start, end);
}
+18 -5
View File
@@ -1005,10 +1005,12 @@ namespace MobileGL::MG_Backend::DirectGLES {
// matches, exactly like the per-VAO memo stamps.
Uint64 drawCleanEpoch = 0;
// Frame serial whose completion retires the last glCopyBufferSubData the upload
// ring staged INTO this store (FlushPendingRangesNow's ring tier); 0 = none. Until
// it retires, FlushPendingRangesNow keeps every partial range off the
// range-invalidating map: on Adreno 830 that map, on a store with a queued copy,
// loses the copy (see FlushPendingRangesNow). Draw thread only, like the flush.
// ring staged INTO this store (the flush ladder's ring tier: FlushPendingRangesNow
// on the pull arm, FlushPendingRangesFrom on the push arm); 0 = none. Until it
// retires, both keep every partial range off the range-invalidating map: on
// Adreno 830 that map, on a store with a queued copy, loses the copy (see
// FlushPendingRangesNow and InvalidateFlushAccessFor). Draw thread only, like the
// flush.
Uint64 ringCopyRetireSerial = 0;
// Zero-copy coherent persistent map (EXT_buffer_storage): the GL store is
// immutable, persistently+coherently mapped, and persistentPtr is what the app
@@ -1192,10 +1194,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
// ("do not take tier 1"), which drops the range onto the staging ring and costs a copy
// rather than a corruption.
//
// `ringCopyInFlight`: the store still has an upload-ring glCopyBufferSubData queued that the
// GPU may not have run (GLESBufferResource::ringCopyRetireSerial not yet retired).
//
// Returns the glMapBufferRange access bits, or 0 when tier 1 must not be taken.
inline constexpr SizeT kEsprytInvalidateRangeMinBytes = 128u * 1024u;
constexpr GLbitfield InvalidateFlushAccessFor(SizeT queuedStart, SizeT queuedEnd, SizeT mapStart,
SizeT mapEnd, SizeT limit, SizeT storageSize) {
SizeT mapEnd, SizeT limit, SizeT storageSize,
Bool ringCopyInFlight) {
if (mapEnd <= mapStart) return 0u;
// THE WIDENING REFUSAL. Not >=, not "covers": exactly, in both directions. A map
// narrower than the queued range leaves bytes unwritten inside a range it has just
@@ -1207,6 +1213,13 @@ namespace MobileGL::MG_Backend::DirectGLES {
// page-substitution fast path needs a page-coverable range to engage, and below it
// the driver falls back to waiting out the WAR hazard on the CPU.
if (!wholeBuffer && size < kEsprytInvalidateRangeMinBytes) return 0u;
// A partial range-invalidating map must not overtake a ring copy into this store the GPU
// has not run yet. Adreno 830 answers such a map on a store with a copy still queued by
// losing the copy (dev f973008c, the pull arm's FlushPendingRangesNow: create-instancing
// drew whole Embeddium terrain sections empty, SSIM 0.870). The range goes to the ring
// instead, GPU-ordered behind the copies. The whole-buffer orphan-map is exempt: it
// rewrites every byte from the shadow the queued copies were taken from.
if (!wholeBuffer && ringCopyInFlight) return 0u;
return GL_MAP_WRITE_BIT |
(wholeBuffer ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_INVALIDATE_RANGE_BIT);
}
+22 -7
View File
@@ -819,19 +819,19 @@ namespace {
} // namespace
TEST(EsprytFlushLadder, AWholeBufferRangeOrphansTheStore) {
EXPECT_EQ(InvalidateFlushAccessFor(0, kStore, 0, kStore, kStore, kStore),
EXPECT_EQ(InvalidateFlushAccessFor(0, kStore, 0, kStore, kStore, kStore, false),
static_cast<GLbitfield>(GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT));
}
TEST(EsprytFlushLadder, ALargePartialRangeInvalidatesExactlyThatRange) {
const SizeT start = 4096;
const SizeT end = start + kEsprytInvalidateRangeMinBytes;
EXPECT_EQ(InvalidateFlushAccessFor(start, end, start, end, kStore, kStore),
EXPECT_EQ(InvalidateFlushAccessFor(start, end, start, end, kStore, kStore, false),
static_cast<GLbitfield>(GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT));
}
TEST(EsprytFlushLadder, ASmallPartialRangeFallsThroughToTheStagingRing) {
EXPECT_EQ(InvalidateFlushAccessFor(4096, 4096 + 64, 4096, 4096 + 64, kStore, kStore), 0u)
EXPECT_EQ(InvalidateFlushAccessFor(4096, 4096 + 64, 4096, 4096 + 64, kStore, kStore, false), 0u)
<< "below the threshold the map WAITS out the WAR hazard on the CPU instead of "
"substituting pages, which is the whole reason tier 2 exists";
}
@@ -846,19 +846,33 @@ TEST(EsprytFlushLadder, AMapWiderThanTheQueuedRangeRefusesTierOne) {
const SizeT queuedStart = 4096;
const SizeT queuedEnd = queuedStart + kEsprytInvalidateRangeMinBytes;
// Page-aligned outward, the exact widening the in-tree note records.
EXPECT_EQ(InvalidateFlushAccessFor(queuedStart, queuedEnd, 0, queuedEnd + 4096, kStore, kStore), 0u)
EXPECT_EQ(InvalidateFlushAccessFor(queuedStart, queuedEnd, 0, queuedEnd + 4096, kStore, kStore, false), 0u)
<< "a widened INVALIDATE_RANGE declares bytes dead that the shadow is not about to "
"rewrite, and overwrites whatever the GPU put there";
// And narrower, which is the same corruption read the other way round: bytes left
// unwritten inside a range that has just been declared dead.
EXPECT_EQ(InvalidateFlushAccessFor(queuedStart, queuedEnd, queuedStart, queuedEnd - 8, kStore, kStore), 0u);
EXPECT_EQ(InvalidateFlushAccessFor(queuedStart, queuedEnd, queuedStart, queuedEnd - 8, kStore, kStore, false),
0u);
}
TEST(EsprytFlushLadder, AnEmptyRangeIsNeverTierOne) {
EXPECT_EQ(InvalidateFlushAccessFor(4096, 4096, 4096, 4096, kStore, kStore), 0u);
EXPECT_EQ(InvalidateFlushAccessFor(4096, 4096, 4096, 4096, kStore, kStore, false), 0u);
}
// dev f973008c's rule on the push arm (P8-MF): Adreno 830 loses an upload-ring copy still queued
// on a store when a partial range-invalidating map of that store overtakes it, so a partial range
// waits behind the copy on the ring. The whole-buffer orphan-map is exempt.
TEST(EsprytFlushLadder, APartialRangeDoesNotOvertakeAQueuedRingCopy) {
const SizeT start = 4096;
const SizeT end = start + kEsprytInvalidateRangeMinBytes;
EXPECT_EQ(InvalidateFlushAccessFor(start, end, start, end, kStore, kStore, true), 0u)
<< "a range-invalidating map of a store with a queued ring copy loses the copy on Adreno 830";
EXPECT_EQ(InvalidateFlushAccessFor(0, kStore, 0, kStore, kStore, kStore, true),
static_cast<GLbitfield>(GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT))
<< "the whole-buffer orphan-map rewrites every byte from the shadow the copies were taken from";
}
#else
// The same five names in a pull build, for the G2/G14 reason above: the ladder's push arm
// The same six names in a pull build, for the G2/G14 reason above: the ladder's push arm
// (FlushPendingRangesFrom) is the only one that carries this decision as a function - the pull
// arm's FlushPendingRangesNow is byte-frozen against 5cb826b0 (ID-15) and may not grow one.
#define MGL_PUSH_ONLY_OR_SKIP() \
@@ -869,4 +883,5 @@ TEST(EsprytFlushLadder, ALargePartialRangeInvalidatesExactlyThatRange) { MGL_PUS
TEST(EsprytFlushLadder, ASmallPartialRangeFallsThroughToTheStagingRing) { MGL_PUSH_ONLY_OR_SKIP(); }
TEST(EsprytFlushLadder, AMapWiderThanTheQueuedRangeRefusesTierOne) { MGL_PUSH_ONLY_OR_SKIP(); }
TEST(EsprytFlushLadder, AnEmptyRangeIsNeverTierOne) { MGL_PUSH_ONLY_OR_SKIP(); }
TEST(EsprytFlushLadder, APartialRangeDoesNotOvertakeAQueuedRingCopy) { MGL_PUSH_ONLY_OR_SKIP(); }
#endif // MOBILEGL_PIPE_PUSH
+79
View File
@@ -0,0 +1,79 @@
# P8-MF:dev 的 Adreno 830 部分冲刷修复镜像到 push 梯子
> 2026-09-30,分支 `p8/mf`(基线 `37174242` = `p8/main` 合入 dev `f973008c`)。简报 `~/w7/notes/p8/BRIEF-MF.md`;全文 `~/w7/notes/p8/mf-report.md`;证据(设备归档、探针日志、脚本、APK 哈希)`~/w7/notes/p8/mf-evidence/`(树外)。只动 Espryt:Magma 没有这条梯子,create-instancing × Magma 本来就是 0.999983725(MD)。
## 1. 改动
| 提交 | 位置 | 内容 |
|---|---|---|
| `ac9ab078` | `MobileGL/MG_Backend/DirectGLES/Managers.cpp:1520` | `FlushPendingRangesFrom` 的 ring 档每次 `glCopyBufferSubData` 后盖 `ringCopyRetireSerial = CurrentFrameSerial() + 1`(同 pull 臂 `Managers.cpp:1808`) |
| `ac9ab078` | `MobileGL/MG_Backend/DirectGLES/Managers.cpp:1496` | 逐 range 读 `ringCopyRetireSerial > CompletedFrameSerial()`(同 pull 臂 `:1785`),传给 `InvalidateFlushAccessFor` |
| `ac9ab078` | `MobileGL/MG_Backend/DirectGLES/Managers.h:1222` | 纯函数 `InvalidateFlushAccessFor` 新参数 `ringCopyInFlight`:部分范围且拷贝未退役 → 0(走 ring,GPU 序排在拷贝后);整 buffer 孤立映射豁免 |
| `ac9ab078` | `MobileGL/MG_Test/Buffer/SplitBufferTest.cpp:865` | `EsprytFlushLadder.APartialRangeDoesNotOvertakeAQueuedRingCopy`(pull 构建同名 skip 桩 `:886`);原 5 例补 `false` |
| `9c24a14d` | `scripts/p3a_untouched_regions.sh`、`scripts/p4a_untouched_regions.sh` | G5 第十行 `FlushPendingRangesNow` 也改为钉住行;两条梯子一起重钉在审过的修后正文:Now `c40cae66…`、From `33bc4cb8…`,提交 `ac9ab078`,裁定 ID-P8-14 |
- pull 臂 `FlushPendingRangesNow` 未动:`37174242` 的正文 = `37da3c3a` 正文 + 恰好 `f973008c` 的那一块(dev 自己的正文另缺 feat 既有的 PipeStats 块,所以 `f973008c` 处哈希是 `c85443ce…`,不是钉值)。
- 不盖 `DrainResidentWritesNow` 的 ring 拷贝:目标是收养的不可变 store,永不走范围失效映射(dev 同样不盖)。
## 2. 设备(红米 2f7cbe2e,create-instancing × Espryt,SSIM)
| APK(lib sha256 前 8) | monolith ×3 | spawn ×3(pbuffer) |
|---|---|---|
| 基线 `37174242`(`5ed6d6dc`) | 0.870389049 ×3 | 0.999984504 ×3 |
| 修复 `9c24a14d`(`34d826c7`) | **0.999984504 ×3** | 0.999984504 ×3 |
| red-once:守卫关(`7938ff89`) | 0.870389049 ×3 | — |
回归(Espryt monolith ×1,基线 → 修复):sodium 0.999993736 → 0.999993736;common-mods 0.999869638 → 0.999869638;improved-transparency-26.3 0.999683991 → 0.999683991。
## 3. 为什么 spawn 不受影响:同样撞上,但拷贝在映射前已提交
探针 APK(守卫关 = 基线行为,`FlushPendingRangesFrom` 每个 range 一行日志,未提交;`04e09442`),monolith / spawn 各 1 次;主机 llvmpipe 三臂同一探针数字完全一致。
| 量 | monolith | spawn(server) |
|---|---|---|
| SSIM | 0.870389049 | 0.999984504 |
| 冲刷的 range / store | 3340 / 11 | 12956 / 26 |
| ring 拷贝 | 3337 | 3337 |
| **部分失效映射且该 store 仍有未退役 ring 拷贝** | **2**(store 38、63,`[3518480,+217120)`、`[3279760,+209360)`) | **2**(同偏移、同大小的两个 arena) |
| 整 buffer 孤立映射 | 1 | 9617(158 MB;24 B–307 KB 的小 store,monolith 下它们不进这条梯子) |
| 该 arena 上次 ring 拷贝与部分映射之间,其他 store 的 range | 4,其中整 buffer 映射 0 | 32 / 34,其中整 buffer 映射 28 / 30 |
- server 走的是同一条梯子:客户端的 `glCopyBufferSubData` 是 CPU 拷贝(`MobileGL/MG_State/GLState/BufferState/BufferObject.cpp:809-831`),以 `resource_subdata` 到 server,`Ops_H_SubData` 排队(`MobileGL/MG_Backend/DirectGLES/Managers.cpp:2469`),draw 时 `EnsureBufferResourceForHandle` 冲刷(`Managers.cpp:4247`)。
- T0 只收养了 16 MiB 持久暂存 buffer(server 日志 `T0 imported store {slot=1, gen=1} - 16777216 bytes`),3.8 MiB arena 不是 T0,不走 `Managers.cpp:2412` 的 resident 分支。
- 机理探针(守卫关 + 每次 ring 拷贝后 `glFlush`,未提交;`754c5d64`):monolith 0.999984504。拷贝只在部分映射到来时仍未提交才会丢。
- 结论:spawn 以同样的 tier 组合撞上同样两处,但 server 在拷贝与映射之间多做了 28–30 次其他 store 的整 buffer 孤立映射,拷贝在映射前已被提交(推断:具体是哪一步触发提交未单独验证)。spawn 是碰巧躲过;修复后 spawn 不变(0.999984504 ×3)。
## 4. red-once
| 门 | 变异 | 载体 | 红 |
|---|---|---|---|
| 设备修复 | `Managers.h:1222` 守卫改 `false && …`(盖戳保留),APK `7938ff89` | create-instancing × Espryt × monolith ×3 | 0.870389049 ×3 |
| 新单测(守卫) | 同上,主机 | `EsprytFlushLadder.APartialRangeDoesNotOvertakeAQueuedRingCopy` | `SplitBufferTest.cpp:868`:得 6(WRITE\|INVALIDATE_RANGE),期望 0 |
| 新单测(整 buffer 豁免) | 守卫去掉 `!wholeBuffer &&` | 同上 | `SplitBufferTest.cpp:871`:得 0,期望 10(WRITE\|INVALIDATE_BUFFER) |
| G5 重钉 | 提交 `ac9ab078` 对旧脚本(`HEAD:` 版本) | `p3a`/`p4a` `37da3c3a HEAD` | 两脚本 rc=1:首个移动 `FlushPendingRangesNow`,另移动 `FlushPendingRangesFrom` |
| G5 From 钉值 | 新脚本对基线提交 | `p3a`/`p4a` `37da3c3a 37174242` | rc=1:首个移动 `FlushPendingRangesFrom`,并报 "IS A PINNED ROW (ID-P8-14)" |
- 每个探针都以拷回 + 比对 + `touch` 恢复(`restored identical: True`、`git diff` 干净)。
- G5 `--self-test`:p3a 两条梯子各有 pin-precedence 控制与一 token 变异控制,全过;p4a 10 个负控制全触发且点名。
## 5. 门(`gate.sh ~/w7/p8-mf p8mf`,头 `9c24a14d`)
| 项 | 结果 |
|---|---|
| G1 | 符号增 0 减 0(clang 22.1.6);`.text` `0xa5ba43`,与本树基线构建相同 |
| fatal census / link ratchet / parity / 协议修订 | 78 / 172 不变 / 0 / 5 |
| wire-declines | 58 行,59 站点 |
| 卫生 | 14/14 OK(含 `g5_p3a`、`g5_p4a`) |
| unit | 2722 / 2722(+1 新单测) |
| split / spawn / tcp | 738 / 652 / 664 全过 |
| Magma split / spawn / tcp / full-split | 271 / 248 / 216 / 671 全过 |
| gpu monolith / inproc | 两臂各 3695 / 3699,同 4 例:`DirectGLES.Tcp.UnlocatedIoBlocks.*` 3 例 + 其 fixture `TcpServer.Start.P8aUnlocatedIoBlocks`(负载下);单独重跑两臂各 31/31 过 |
| retrace(`ctest -L retrace`,monolith + .SPLIT + .SPAWN,两后端) | 230 / 236,失败只有已知 6 例 iterationrp(主机 llvmpipe JIT) |
## 6. 未做 / 遗留
| 项 | 原因 |
|---|---|
| server 对小 store 反复整 buffer 孤立映射(create-instancing 一次重放 9617 次 / 158 MB,monolith 1 次) | 性能项,不是本包;它恰好让 spawn 躲过本缺陷 |
| 其他 GPU 写(SSBO、xfb)后接部分失效映射是否同样丢 | 未观察到;守卫只覆盖 ring 拷贝(同 MD) |
| 两臂之间的注释仍写 pull 臂冻结于 `5cb826b0`、From 钉于 `3e298c9a`(`MobileGL/MG_Backend/DirectGLES/Managers.cpp:1376`、`:1535`、`:1553`;`MobileGL/MG_Test/Buffer/SplitBufferTest.cpp:877`) | ID-41 起就过时,ID-P8-14 后 pull 行也改为钉住;都在哈希正文之外,留给下次改这段的人 |
+59 -35
View File
@@ -24,9 +24,19 @@
# RingAllocate the fast path on the hot upload route
# FlushPendingRangesNow the three-tier drain: tier 1 is an INVALIDATE_BUFFER map + memcpy
# for a whole-buffer flush or a range >= 128 KiB, tier 2 the upload
# ring + glCopyBufferSubData, tier 3 UploadRangeNow
# ring + glCopyBufferSubData, tier 3 UploadRangeNow. PINNED since
# ID-P8-14 (see below)
# FlushPendingRangesFrom the SAME three-tier drain, on the arm that ships. Born in P3a
#
# ID-P8-14 PINS THE TENTH TOO. dev f973008c changed FlushPendingRangesNow on purpose: on Adreno 830 a
# partial range-invalidating map of a store that still has an upload-ring glCopyBufferSubData queued
# loses the copy (create-instancing drew whole terrain sections empty, SSIM 0.870), so the ring tier
# stamps ringCopyRetireSerial and a partial range waits behind an unretired copy. P8 merged dev
# (37174242) and P8-MF mirrored the rule into FlushPendingRangesFrom (via InvalidateFlushAccessFor).
# The base ref CI passes (37da3c3a) predates the fix, so the tenth row can no longer be compared
# against <ref-a>; both ladders are now PINNED rows, re-pinned together on the reviewed post-fix
# bodies, and still compared on every run.
#
# THE ELEVENTH IS HERE BY INTEGRATOR DECISION ID-15, and it is the whole reason the row about the
# tenth is not decorative. On this tree Managers.cpp has TWO arms: `#if MOBILEGL_PIPE_PUSH` holds
# FlushPendingRangesFrom, `#else` holds FlushPendingRangesNow byte-identically, and BOTH of a push
@@ -36,9 +46,10 @@
# would exit 2 rather than run). The consequence, and what ID-15 closes: a push build compiles no
# FlushPendingRangesNow at all, so a gate that hashed only that name protected text the shipping
# build never sees, and a tier-threshold edit made in the ladder that DOES ship would pass it. So
# both names are hashed. The pull build's ladder is compared against the base ref; the push build's
# is compared, ALWAYS AND WHETHER OR NOT <ref-a> DEFINES IT, against a sha pinned at the commit
# where that body was reviewed - see PINNED_FUNCTIONS.
# both names are hashed. The push build's ladder is compared, ALWAYS AND WHETHER OR NOT <ref-a>
# DEFINES IT, against a sha pinned at the commit where that body was reviewed - see
# PINNED_FUNCTIONS. The pull build's ladder was compared against the base ref until ID-P8-14 pinned
# it the same way (see the note under the list above).
#
# "ALWAYS" IS INTEGRATOR DECISION ID-41 AND IT IS A CHANGE. Until P5 this text said "pinned" while
# the implementation consulted the pin only as a FALLBACK, when <ref-a> did not define the function
@@ -50,7 +61,8 @@
# InvalidateFlushAccessFor, the pull arm (FlushPendingRangesNow) is byte-identical across that
# change and G1 reports .text +0, so it is the intended change to the eleventh row rather than
# drift - and the answer is to RE-PIN it, not to revert it and not to let the row stop being
# compared. The OTHER TEN stay ref-a-vs-ref-b: nothing about them moved.
# compared. The other nine stay ref-a-vs-ref-b: nothing about them moved (the tenth moved at
# ID-P8-14 and was pinned then).
#
# THE TENTH IS HERE BY INTEGRATOR DECISION ID-11, resolving a contradiction inside the brief.
# D-F's "Decision: nine functions" table omits FlushPendingRangesNow, but BRIEF-P3A.md:420 calls it
@@ -99,24 +111,33 @@
set -u -o pipefail
SOURCE_PATH=MobileGL/MG_Backend/DirectGLES/Managers.cpp
# The ten that exist at the P3a base ref, so their baseline is read out of <ref-a>.
FUNCTIONS="IsPoolable EnrollIntoPool AcquireFromPool TrimBufferPool ClearBufferPool ProcessDeferredBufferReleases CreateRingStorage RingAvailable RingAllocate FlushPendingRangesNow"
# The ELEVENTH (ID-15), and it is a different kind of row: it was BORN in P3a, so there was no
# body at the base ref to compare it with, and its baseline is PINNED below and consulted
# UNCONDITIONALLY (ID-41 - see the long note at the top of this file).
# The nine unpinned rows: they exist at the P3a base ref, so their baseline is read out of <ref-a>.
FUNCTIONS="IsPoolable EnrollIntoPool AcquireFromPool TrimBufferPool ClearBufferPool ProcessDeferredBufferReleases CreateRingStorage RingAvailable RingAllocate"
# The TENTH and the ELEVENTH, and they are a different kind of row: their baseline is PINNED below
# and consulted UNCONDITIONALLY (ID-41 - see the long note at the top of this file). The eleventh
# (ID-15) was BORN in P3a, so there was no body at the base ref to compare it with; the tenth joined
# it at ID-P8-14, when a reviewed fix moved it past the base ref. PINNED_FUNCTIONS is in the fixed
# order, because apply_pinned_shas appends the pinned rows in that order.
#
# THE PIN, AND WHAT RE-PINS IT. Whoever moves this body deliberately replaces BOTH lines and
# writes the decision beside them; a pin with no commit and no decision next to it is a number
# nobody can audit.
# 3e298c9a 37fc94ff... ID-15, P3a: the two-arm shape, reviewed and accepted
# 3dadd4c1 172b0222... ID-41, P5 (b1): [Fix] (DirectGLES): make the extent hostBase is good
# for a parameter of the flush ladder, so tier 1's widening refusal is
# live code the moment a SEG_STAGE snapshot is narrower than the queued
# range. <- CURRENT
PINNED_FUNCTIONS="FlushPendingRangesFrom"
PINNED_BASELINE_REF=3dadd4c1
PINNED_BASELINE_DECISION=ID-41
PINNED_SHA_FlushPendingRangesFrom=172b022273db01b16e772d15b269ffcd797fe38c767f7354d83ce113a66040d0
# THE PIN, AND WHAT RE-PINS IT. Whoever moves one of these bodies deliberately replaces the shas
# AND the commit AND the decision, and writes a line here; a pin with no commit and no decision
# next to it is a number nobody can audit.
# 3e298c9a From 37fc94ff... ID-15, P3a: the two-arm shape, reviewed and accepted
# 3dadd4c1 From 172b0222... ID-41, P5 (b1): [Fix] (DirectGLES): make the extent hostBase is
# good for a parameter of the flush ladder, so tier 1's widening
# refusal is live code the moment a SEG_STAGE snapshot is narrower
# than the queued range.
# ac9ab078 Now c40cae66... ID-P8-14, P8-MF: dev f973008c (merged at 37174242) keeps a partial
# From 33bc4cb8... range-invalidating map behind an upload-ring copy still queued on the
# store - Adreno 830 loses the queued copy - in FlushPendingRangesNow;
# ac9ab078 mirrors it into FlushPendingRangesFrom (the stamp on
# the ring tier, the guard in InvalidateFlushAccessFor, the
# whole-buffer exemption kept). <- CURRENT
PINNED_FUNCTIONS="FlushPendingRangesNow FlushPendingRangesFrom"
PINNED_BASELINE_REF=ac9ab078
PINNED_BASELINE_DECISION=ID-P8-14
PINNED_SHA_FlushPendingRangesNow=c40cae66f021160478ef9af6bcf5e8ef0bf26721486173695d5257263c97723f
PINNED_SHA_FlushPendingRangesFrom=33bc4cb855b932ed4fb0de44a4cfa7a9be8aca34da267ccd2fc9fedfad4d3328
ALL_FUNCTIONS="$FUNCTIONS $PINNED_FUNCTIONS"
EXPECTED_FUNCTION_COUNT=11
# The functions the self-test perturbs, one control each. ClearBufferPool is small, has no forward
@@ -353,21 +374,22 @@ apply_pinned_shas() {
for name in $PINNED_FUNCTIONS; do
eval "pinned=\$PINNED_SHA_$name"
if [ -z "$pinned" ] || [ "$pinned" = "PLACEHOLDER_SHA" ]; then
say "$name has no pinned baseline sha; the eleventh row cannot be compared"
say "$name has no pinned baseline sha; that row cannot be compared"
return 2
fi
grep -v " $name\$" "$file" > "$file.unpinned" || true
mv -f "$file.unpinned" "$file" || return 2
# Appended LAST, which is also its position in the fixed order (it is the eleventh of eleven),
# so the header's "stdout is always the sha list in the fixed order" stays true and a baseline
# captured by redirect still diffs cleanly against a two-ref run.
# Appended LAST, in PINNED_FUNCTIONS order, which is also their position in the fixed order
# (the tenth and the eleventh of eleven), so the header's "stdout is always the sha list in the
# fixed order" stays true and a baseline captured by redirect still diffs cleanly against a
# two-ref run.
printf '%s %s\n' "$pinned" "$name" >> "$file"
done
return 0
}
# The BASELINE side (<ref-a>). The TEN are extracted strictly, so a rename of one of THOSE is
# exit 2 rather than a silently short list. FlushPendingRangesFrom then takes the PINNED sha
# The BASELINE side (<ref-a>). The NINE are extracted strictly, so a rename of one of THOSE is
# exit 2 rather than a silently short list. Each pinned row then takes the PINNED sha
# WHETHER OR NOT <ref-a> defines it (ID-41), and a <ref-a> that defines it DIFFERENTLY is
# reported - loudly - because the two answers disagreeing is itself a finding rather than a
# reason to prefer the ref.
@@ -379,7 +401,7 @@ extract_baseline() {
return 2
fi
if ! python3 "$PY" extract "$blob" "$FUNCTIONS" > "$WORK_DIR/$out.sha" 2>"$WORK_DIR/$out.err"; then
say "the baseline ref '$ref' does not define the pre-P3a ten exactly once each:"
say "the baseline ref '$ref' does not define the nine unpinned rows exactly once each:"
sed 's/^/[p3a-untouched] /' "$WORK_DIR/$out.err" >&2
return 2
fi
@@ -387,7 +409,7 @@ extract_baseline() {
eval "pinned=\$PINNED_SHA_$name"
atRef=$(python3 "$PY" extract "$blob" "$name" 2>/dev/null | awk -v n="$name" '$2 == n { print $1 }')
if [ -z "$atRef" ]; then
say "$name is not defined at '$ref' (it was born in P3a): its baseline is the sha PINNED in"
say "$name is not defined at '$ref' (a pinned row): its baseline is the sha PINNED in"
say " this script, captured at $PINNED_BASELINE_REF ($PINNED_BASELINE_DECISION)"
elif [ "$atRef" != "$pinned" ]; then
say "NOTE: $name IS defined at '$ref' and hashes"
@@ -517,14 +539,16 @@ if [ "${1:-}" = "--self-test" ]; then
# --- THE PINNED ROW (ID-41) -----------------------------------------------------------------
# TWO more controls, and they exist because none of the five above can see the pin at all: every
# one of them compares one extraction of the working tree against another, so they would all be
# green on a build of this script in which PINNED_SHA_* was never read by anything. The eleventh
# row's whole claim is "the baseline is the PIN, not <ref-a>", and that claim needs its own two.
# green on a build of this script in which PINNED_SHA_* was never read by anything. A pinned
# row's whole claim is "the baseline is the PIN, not <ref-a>", and that claim needs its own two -
# per pinned row (both ladders since ID-P8-14).
for target in $PINNED_FUNCTIONS; do
eval "pinned=\$PINNED_SHA_$target"
# (1) PIN PRECEDENCE, positive. A baseline that carries some OTHER sha for the pinned row -
# which is the shape of every <ref-a> CI passes today, since ff2994d9 and 37da3c3a both DEFINE
# FlushPendingRangesFrom - must come out of apply_pinned_shas carrying the PIN. This is the
# FlushPendingRangesFrom and both predate ID-P8-14's FlushPendingRangesNow - must come out of
# apply_pinned_shas carrying the PIN. This is the
# control that would have caught the ID-41 defect itself: before it, the pin was consulted
# only when <ref-a> lacked the function, so the row silently reverted to ref-a-vs-ref-b the
# moment a base ref had one.
@@ -537,7 +561,7 @@ if [ "${1:-}" = "--self-test" ]; then
got=$(awk -v n="$target" '$2 == n { print $1 }' "$WORK_DIR/pinprec.sha")
if [ "$got" != "$pinned" ]; then
say "PIN CONTROL FAILED: a baseline that carried a DIFFERENT sha for $target came out as"
say " '${got:-<absent>}' and not as the pin ($pinned). The eleventh row would be compared"
say " '${got:-<absent>}' and not as the pin ($pinned). That pinned row would be compared"
say " against <ref-a> again, which is exactly the defect $PINNED_BASELINE_DECISION closed."
exit 2
fi
@@ -545,7 +569,7 @@ if [ "${1:-}" = "--self-test" ]; then
# (2) A ONE-TOKEN EDIT TO THE PINNED LADDER, negative, AGAINST THE PIN. The comparison must go
# red, must name the row, and must say that the row is PINNED - R-16's "a control asserts its
# OWN failure string": the pinned row and the ten ref-a rows are fixed differently, and a
# OWN failure string": the pinned rows and the nine ref-a rows are fixed differently, and a
# reader who gets only the generic paragraph goes looking for a diff against <ref-a> that does
# not exist.
python3 "$PY" perturb-token "$WORK_DIR/pristine.cpp" "$WORK_DIR/pinperturbed.cpp" \
+46 -30
View File
@@ -25,7 +25,8 @@
# CreateRingStorage glBufferStorageEXT + persistent|coherent, retires at serial + 1
# RingAvailable self-heals a stale context generation
# RingAllocate the fast path on the hot upload route
# FlushPendingRangesNow the three-tier drain, pull arm
# FlushPendingRangesNow the three-tier drain, pull arm. PINNED since ID-P8-14: dev
# f973008c moved it past <ref-a> on purpose (the parent's note)
# FlushPendingRangesFrom the SAME three-tier drain, on the arm that ships (ID-15). Born
# in P3a, so its baseline is PINNED, not read from <ref-a>
#
@@ -125,6 +126,11 @@
# be RE-PINNED on the reviewed P5 body rather than reverted or quietly left comparing
# against <ref-a>. This script says so on stderr, in both directions, and keeps the PIN -
# because the pin is the reviewed text.
#
# ID-P8-14 extends the same treatment to FlushPendingRangesNow: dev f973008c changed it
# past every <ref-a> CI passes (the Adreno 830 queued-ring-copy guard), P8-MF mirrored the
# rule into FlushPendingRangesFrom, and both ladders were re-pinned together on the
# reviewed post-fix bodies.
set -u -o pipefail
# One row per region: <name>@<kind>@<path>. The ORDER is the fixed order the sha list is printed
@@ -151,21 +157,32 @@ ShouldUseCaveatTextureFormat@function@MobileGL/MG_Backend/DirectGLES/Utils.cpp"
EXPECTED_FUNCTION_COUNT=17
# The one region born in P3a, so there is no body at P4a's base ref that this phase reviewed: its
# baseline is PINNED and consulted UNCONDITIONALLY (DEVIATIONS D-N/2, and ID-41 for the parent).
# The two flush ladders. FlushPendingRangesFrom was born in P3a, so there is no body at P4a's base
# ref that this phase reviewed; FlushPendingRangesNow was moved past the base ref by a reviewed fix
# (ID-P8-14, dev f973008c: a partial range-invalidating map must not overtake an upload-ring copy
# still queued on the store - Adreno 830 loses the copy). Both baselines are PINNED and consulted
# UNCONDITIONALLY (DEVIATIONS D-N/2, and ID-41 for the parent).
#
# THE PIN, AND WHAT RE-PINS IT. Whoever moves this body deliberately replaces BOTH lines and
# writes the decision beside them; a pin with no commit and no decision next to it is a number
# nobody can audit. The parent script carries the identical table and the two must not drift.
# 3e298c9a 37fc94ff... ID-15, P3a: the two-arm shape, reviewed and accepted
# 3dadd4c1 172b0222... ID-41, P5 (b1): [Fix] (DirectGLES): make the extent hostBase is good
# for a parameter of the flush ladder, so tier 1's widening refusal is
# live code the moment a SEG_STAGE snapshot is narrower than the queued
# range. <- CURRENT
PINNED_FUNCTIONS="FlushPendingRangesFrom"
PINNED_BASELINE_REF=3dadd4c1
PINNED_BASELINE_DECISION=ID-41
PINNED_SHA_FlushPendingRangesFrom=172b022273db01b16e772d15b269ffcd797fe38c767f7354d83ce113a66040d0
# THE PIN, AND WHAT RE-PINS IT. Whoever moves one of these bodies deliberately replaces the shas
# AND the commit AND the decision, and writes a line here; a pin with no commit and no decision
# next to it is a number nobody can audit. The parent script carries the identical table and the
# two must not drift.
# 3e298c9a From 37fc94ff... ID-15, P3a: the two-arm shape, reviewed and accepted
# 3dadd4c1 From 172b0222... ID-41, P5 (b1): [Fix] (DirectGLES): make the extent hostBase is
# good for a parameter of the flush ladder, so tier 1's widening
# refusal is live code the moment a SEG_STAGE snapshot is narrower
# than the queued range.
# ac9ab078 Now c40cae66... ID-P8-14, P8-MF: dev f973008c (merged at 37174242) keeps a partial
# From 33bc4cb8... range-invalidating map behind an upload-ring copy still queued on the
# store - Adreno 830 loses the queued copy - in FlushPendingRangesNow;
# ac9ab078 mirrors it into FlushPendingRangesFrom (the stamp on
# the ring tier, the guard in InvalidateFlushAccessFor, the
# whole-buffer exemption kept). <- CURRENT
PINNED_FUNCTIONS="FlushPendingRangesNow FlushPendingRangesFrom"
PINNED_BASELINE_REF=ac9ab078
PINNED_BASELINE_DECISION=ID-P8-14
PINNED_SHA_FlushPendingRangesNow=c40cae66f021160478ef9af6bcf5e8ef0bf26721486173695d5257263c97723f
PINNED_SHA_FlushPendingRangesFrom=33bc4cb855b932ed4fb0de44a4cfa7a9be8aca34da267ccd2fc9fedfad4d3328
# The regions the self-test perturbs, one negative control each. FOUR, exactly as D-N requires, and
# each is a different shape so that a control which only ever perturbed the easy one cannot leave
@@ -502,8 +519,8 @@ extract_ref() {
return $?
}
# The BASELINE side (<ref-a>). The sixteen ordinary regions are extracted strictly, so a rename of
# one of THOSE is exit 2 rather than a silently short list. FlushPendingRangesFrom then takes the
# The BASELINE side (<ref-a>). The fifteen ordinary regions are extracted strictly, so a rename of
# one of THOSE is exit 2 rather than a silently short list. Each pinned row then takes the
# PINNED sha (DEVIATIONS D-N/2) whether or not <ref-a> defines it, and a <ref-a> that defines it
# DIFFERENTLY is reported - loudly - because the two answers disagreeing is itself a finding.
extract_baseline() {
@@ -517,7 +534,7 @@ extract_baseline() {
mv -f "$WORK_DIR/$out.spec.tmp" "$WORK_DIR/$out.spec" || return 2
done
if ! python3 "$PY" extract "$WORK_DIR/$out.spec" > "$WORK_DIR/$out.sha" 2>"$WORK_DIR/$out.err"; then
say "the baseline ref '$ref' does not define the sixteen unpinned regions exactly once each:"
say "the baseline ref '$ref' does not define the fifteen unpinned regions exactly once each:"
sed 's/^/[p4a-untouched] /' "$WORK_DIR/$out.err" >&2
return 2
fi
@@ -608,8 +625,8 @@ compare_lists() {
say " $labelA ${shaA:-<not found>}"
say " $labelB ${shaB:-<not found>}"
if is_pinned_row "$name"; then
# ITS OWN MESSAGE, and that is R-16 rather than decoration: the pinned row and the
# sixteen ref-a rows fail differently and are fixed differently, so a reader who sees
# ITS OWN MESSAGE, and that is R-16 rather than decoration: the pinned rows and the
# fifteen ref-a rows fail differently and are fixed differently, so a reader who sees
# only the generic paragraph below goes looking for a diff against <ref-a> that does not
# exist.
say " $name IS A PINNED ROW ($PINNED_BASELINE_DECISION): its baseline is ALWAYS the sha"
@@ -640,10 +657,10 @@ compare_lists() {
# A gate that always says "identical" and a gate that is working produce the same green, so the
# comparison has to be shown failing. Both controls run: the POSITIVE ones (an untouched copy
# compares equal; an edit OUTSIDE the regions is invisible; a baseline that names another sha for
# the PINNED row is overridden by the pin) rule out a comparison that reports every region as
# moved, and the NINE NEGATIVE ones - D-N's four regions, each perturbed at the HEAD of its body
# and again at its TAIL, plus a ONE-TOKEN edit to the pinned ladder compared AGAINST THE PIN
# (ID-41) - rule out the comparison that never reports any, the extraction whose extent stops
# a PINNED row is overridden by the pin) rule out a comparison that reports every region as
# moved, and the TEN NEGATIVE ones - D-N's four regions, each perturbed at the HEAD of its body
# and again at its TAIL, plus a ONE-TOKEN edit to each pinned ladder compared AGAINST THE PIN
# (ID-41; two pinned rows since ID-P8-14) - rule out the comparison that never reports any, the extraction whose extent stops
# before the closing brace (F-m2), and a pin that nothing consults.
if [ "${1:-}" = "--self-test" ]; then
[ $# -eq 1 ] || { say "--self-test takes no other arguments"; exit 2; }
@@ -750,18 +767,17 @@ if [ "${1:-}" = "--self-test" ]; then
# --- THE PINNED ROW (ID-41) -----------------------------------------------------------------
# TWO more controls, and they exist because none of the ten above can see the pin at all: every
# one of them compares one extraction of the working tree against another, so they would all be
# green on a build of this script in which PINNED_SHA_* was never read by anything. The pinned
# green on a build of this script in which PINNED_SHA_* was never read by anything. A pinned
# row's whole claim is "the baseline is the PIN, not <ref-a>" (D-N/2, ID-41), and that claim
# needs its own two.
# needs its own two - per pinned row (both ladders since ID-P8-14).
for target in $PINNED_FUNCTIONS; do
eval "pinned=\$PINNED_SHA_$target"
targetSource=$(printf '%s\n' "$REGIONS" | awk -F@ -v n="$target" '$1 == n { print $3 }')
[ -n "$targetSource" ] || { say "$target is not one of the regions"; exit 2; }
# (1) PIN PRECEDENCE, positive. A baseline that carries some OTHER sha for the pinned row -
# which is the shape of every <ref-a> CI passes, since 37da3c3a DOES define
# FlushPendingRangesFrom and no longer hashes the pin - must come out of apply_pinned_shas
# carrying the PIN.
# which is the shape of every <ref-a> CI passes, since 37da3c3a DOES define both ladders and
# hashes neither pin - must come out of apply_pinned_shas carrying the PIN.
grep -v " $target\$" "$WORK_DIR/pristine.sha" > "$WORK_DIR/pinprec.sha" || true
printf '%s %s\n' \
"0000000000000000000000000000000000000000000000000000000000000000" "$target" \
@@ -779,7 +795,7 @@ if [ "${1:-}" = "--self-test" ]; then
# (2) A ONE-TOKEN EDIT TO THE PINNED LADDER, negative, AGAINST THE PIN. The comparison must go
# red, must name the region, and must say the region is PINNED - R-16's "a control asserts its
# OWN failure string": the pinned row and the sixteen ref-a rows are fixed differently, and a
# OWN failure string": the pinned rows and the fifteen ref-a rows are fixed differently, and a
# reader who gets only the generic paragraph goes looking for a diff against <ref-a> that does
# not exist.
rm -rf "$WORK_DIR/pinperturbed"