tools: read AdrenoDrawCommands.m with its split parts

SnapMetal moves AdrenoDrawCommands.m's code into ordered parts under
AdrenoMetal/AdrenoDrawCommands/, #included by the main file. Tools that
read that file as text or hash the plug-in's sources must see the whole
unit:

- test-adreno-staging-arenas.py: the A4 lock check reads the unit with
  read_source(). On the main file alone it would find no lock at all
  and fail; its line numbers now refer to the expanded unit.
- qualify-gen57-windowserver-cause.py: binds every file of the unit
  (source_files) and searches read_source(). An unsplit tree binds and
  reads exactly what it did before.
- check-adreno-resource-encoding.py: hashes AdrenoMetal/ recursively,
  so the qualification record covers the parts.

Evidence: py_compile of the three tools; the A4 check finds the same 6
locked regions in the unsplit file and in read_source() of the split
unit (none in the main file alone), and flags a release inserted inside
one of them.
This commit is contained in:
Acelogic committed 2026-10-23 04:04:50 -04:00
1 parent 4b83aba2d2
commit 984f03937b
3 files changed
+15 -6

No files matched your search

+1 -1
View File
@@ -61,7 +61,7 @@ def main():
ROOT/'compat/adreno-resource-list.c',ROOT/'compat/adreno-resource-list.h',
ROOT/'compat/adreno-submit.h',PLUGIN/'build.sh',
PLUGIN/'harness/resource-encoding.m',PLUGIN/'harness/regtest.m',PLUGIN/'harness/ws_selectors.h']
sources+=list((PLUGIN/'AdrenoMetal').glob('*'))
sources+=list((PLUGIN/'AdrenoMetal').rglob('*')) # split sources keep their parts in subdirectories
sources+=list((PLUGIN.parent/'include').glob('*.h'))
source_hashes={str(p.relative_to(ROOT)):sha(p) for p in sorted(sources) if p.is_file()}
commands=[]
+8 -2
View File
@@ -13,6 +13,10 @@ import argparse
import hashlib
import json
import subprocess
import sys
sys.path.insert(0, str(Path(__file__).resolve().parent))
from source_text import read_source, source_files
ROOT = Path(__file__).resolve().parents[1]
PIPE = ROOT.parent / 'Snapintosh-adreno-pipeline'
@@ -74,8 +78,10 @@ proof_path = bind(PIPE / 'build/ca-vpc-a16-verified-gen58-20260928-v1/verificati
'8d95a910aedce77fb31710799e0882e0a1c8b0d32b1eacfbf709e0c5d0995c2e')
proof = json.loads(proof_path.read_text())
assert proof['status'] == 'A16_CA_FRAME_EXACT' and not proof['desktop_verified']
source = bind(PIPE / 'gpu/adreno-kext/plugin/AdrenoMetal/AdrenoDrawCommands.m')
assert '![var[@"interp"] isEqual:@"no_perspective"]' in source.read_text()
source = PIPE / 'gpu/adreno-kext/plugin/AdrenoMetal/AdrenoDrawCommands.m'
for part in source_files(source):
bind(part)
assert '![var[@"interp"] isEqual:@"no_perspective"]' in read_source(source)
bind(__file__)
output = args.output.resolve()
assert not output.exists()
+6 -3
View File
@@ -18,7 +18,7 @@ harness gauge puts a dealloc sentinel on every staging arena the plug-in allocat
faults run B: an injected IOGPU allocation failure drains a non-empty pool and is retried once (buffer and
texture); with an empty pool it is not retried (A8, A16)
gauge the plug-in's live counts equal the harness's; its peak equals the harness's (A13)
source no release between gAdrenoStagingLock's lock and unlock in AdrenoDrawCommands.m (A4)
source no release between gAdrenoStagingLock's lock and unlock in AdrenoDrawCommands.m and its parts (A4)
stats the plug-in's diagnostics stats line carries the arenas(...) fields and stays under 1 KB (A19)
--expect-before: the unchanged plug-in must fail at least one check.
@@ -34,6 +34,9 @@ import struct
import subprocess
import sys
sys.path.insert(0, str(Path(__file__).resolve().parent))
from source_text import read_source
ROOT = Path(__file__).resolve().parents[1]
HARNESS = ROOT / 'gpu/adreno-kext/plugin/harness'
REGS = ROOT / 'gpu/adreno-kext/include/AdrenoA8xxRegs.h'
@@ -256,13 +259,13 @@ def main():
check(line is not None and ' arenas(live/live_kib/peak/peak_kib/pooled_kib/aged/capped/drains/failures/retries_ok/continued)='
in line and len(line) <= 1024, f'stats: the diagnostics stats line lacks the arenas fields: {line and line[-200:]}')
# ---- source check (A4)
src = DRAW.read_text()
src = read_source(DRAW)
bad = []
for m in re.finditer(r'os_unfair_lock_lock\(&gAdrenoStagingLock\);(.*?)os_unfair_lock_unlock\(&gAdrenoStagingLock\);', src, re.S):
if re.search(r'CFBridgingRelease|__bridge_transfer|CFRelease|AdrenoStagingReleaseVictims', m.group(1)):
bad.append(src[:m.start()].count('\n') + 1)
check(bool(re.search(r'os_unfair_lock_lock\(&gAdrenoStagingLock\)', src)) and not bad,
f'source: a release inside gAdrenoStagingLock at lines {bad}')
f'source: a release inside gAdrenoStagingLock at lines {bad} of the expanded unit')
result = dict(checks=checks, failures=failures, summary=summary, bundle=bundle, expect_before=args.expect_before)
(out / 'result.json').write_text(json.dumps(result, indent=2, default=str) + '\n')
if args.expect_before: