diff --git a/docs/Disaggregated/notes/p13/tools/w5_classify.py b/docs/Disaggregated/notes/p13/tools/w5_classify.py index 278b702b..42607a1d 100644 --- a/docs/Disaggregated/notes/p13/tools/w5_classify.py +++ b/docs/Disaggregated/notes/p13/tools/w5_classify.py @@ -37,7 +37,9 @@ TRANSPORT = [r'ClientSession', r'ServerSession', r'ServerLoop', r'Transport::', r'Transport\s*!=', r'Transport\s*==', # Second pass (S2): transport-shaped words that name no MG_Remote symbol. r'Window', r'SwapInterval', r'ContextLive', r'Ahb', r'AHardwareBuffer', r'HardwareBuffer', r'[Dd]ma[Bb]uf', - r'Gbm', r'SyncFile', r'sync_file', r'Session', r'Peer', r'Spawn', r'Tcp', r'Socket'] + r'Gbm', r'SyncFile', r'sync_file', r'Session', r'Peer', r'Spawn', r'Tcp', r'Socket', + # Device loss and its recovery are a session's (the session ends, not the process). + r'Lost', r'Epoch', r'ResetNotif', r'Recover', r'StreamGate', r'ReplacementShare', r'ReplaceProcessDefault'] RECORD = [r'DataArmIsRecord', r'RecordArm', r'Staged', r'\bWire', r'MGPipe', r'Handle', r'Record\b', r'Twin', r'Respecif', r'Readback', r'Verb', r'PersistentMap', r'GpuWrite', r'Emit', r'Applier', r'Slot', r'Residual', r'ContextValues', r'Cso\b', r'CSO', r'Placeholder', r'Mipmap', r'Shadow'] diff --git a/docs/Disaggregated/notes/p13/tools/w5_rewrite.py b/docs/Disaggregated/notes/p13/tools/w5_rewrite.py new file mode 100644 index 00000000..5277faab --- /dev/null +++ b/docs/Disaggregated/notes/p13/tools/w5_rewrite.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python3 +"""P13 W5 S2: move the record arm's guards from MOBILEGL_BUILD_DISAGGREGATED to +MOBILEGL_BUILD_RECORD_ARM, by w5_classify.py's classes. + + w5_rewrite.py [--root DIR] [--dir PREFIX ...] [--dry-run] + +Rewritten (the macro on the opening line, and on its #else / #endif comment if it names it): + * a plain `#if MOBILEGL_BUILD_DISAGGREGATED` group of class A or F (record terms or nothing, no + transport word, no MG_Remote name); + * every plain `#if !MOBILEGL_BUILD_DISAGGREGATED` (the frontend arm of a build without the record arm); + * `#if MOBILEGL_PIPE_VERIFY && !MOBILEGL_BUILD_DISAGGREGATED` (the verify tree's frontend pins). +Left for the hand pass (S3): B, C, D, E and the compound guards; the MOBILEGL_PIPE_POISON arm in +PipeInputs.h stays on DISAGG on purpose (the FCL library must not pay a per-read poison check). +Tests (MG_Test, MG_IntegrationTest) are S6's. + +While MOBILEGL_BUILD_RECORD_ARM equals MOBILEGL_BUILD_DISAGGREGATED (until S7) every rewrite is a +no-op for the compiler: both trees keep byte-identical code. +""" +import argparse +import pathlib +import re +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).parent)) +import w5_classify as wc # noqa: E402 + +OLD = 'MOBILEGL_BUILD_DISAGGREGATED' +NEW = 'MOBILEGL_BUILD_RECORD_ARM' +SKIP_TOP = ('MobileGL/MG_Test/', 'MobileGL/MG_IntegrationTest/') +# S2 touches only the trees the record core lives in. The EGL layer, the GL context's device-loss +# state, the logger's role files and the stats dump paths are session machinery whose guards the +# token classes cannot tell apart from record code; they are S3's hand pass. +RECORD_DIRS = ('MobileGL/MG_Backend/DirectGLES/', 'MobileGL/MG_Backend/DirectVulkan/', 'MobileGL/MG_Backend/MGPipe/', + 'MobileGL/MG_Pipe/', 'MobileGL/MG_Impl/Pipe/', 'MobileGL/MG_Impl/GLImpl/', + 'MobileGL/MG_State/GLState/BufferState/', 'MobileGL/MG_State/GLState/ProgramState/', + 'MobileGL/MG_State/GLState/FramebufferState/', 'MobileGL/MG_Util/SelfTest/') + + +def rewrite_file(path, rel, lines): + rows = wc.classify(rel, lines) + changed = [] + for g in wc.groups(lines): + cond = g['cond'] + plain = re.fullmatch(r'if\s+' + OLD, cond) is not None + negated = re.fullmatch(r'if\s+!\s*' + OLD, cond) is not None + verify_pin = re.fullmatch(r'if\s+MOBILEGL_PIPE_VERIFY\s*&&\s*!\s*' + OLD, cond) is not None + if plain: + cls = next(r['class'] for r in rows if r['open'] == g['open']) + if cls not in ('A', 'F'): + continue + elif not (negated or verify_pin): + continue + targets = [g['open']] + [no for no, kind in g['branches'][1:]] + [g['close']] + for no in targets: + line = lines[no - 1] + if no == g['open'] or OLD in line: + lines[no - 1] = line.replace(OLD, NEW) + changed.append((g['open'], 'plain' if plain else 'negated' if negated else 'verify-pin')) + return changed + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument('--root', default='.') + ap.add_argument('--dir', action='append', default=[]) + ap.add_argument('--dry-run', action='store_true') + args = ap.parse_args() + root = pathlib.Path(args.root) + total = 0 + for p in sorted((root / 'MobileGL').rglob('*')): + if p.suffix not in wc.EXTS or not p.is_file(): + continue + rel = p.relative_to(root).as_posix() + if wc.SKIP_PARTS & set(pathlib.PurePosixPath(rel).parts) or rel.startswith(SKIP_TOP) or not rel.startswith(RECORD_DIRS): + continue + if args.dir and not any(rel.startswith(d) for d in args.dir): + continue + raw = p.read_bytes().decode('utf-8') + crlf = '\r\n' in raw + lines = raw.replace('\r\n', '\n').splitlines(keepends=True) + changed = rewrite_file(p, rel, lines) + if not changed: + continue + total += len(changed) + print('%-70s %3d' % (rel, len(changed))) + if not args.dry_run: + text = ''.join(lines) + p.write_bytes((text.replace('\n', '\r\n') if crlf else text).encode('utf-8')) + print('groups rewritten:', total) + return 0 + + +if __name__ == '__main__': + sys.exit(main())