mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
vk_memory.c hands out page write generations (gen_now, 32 bits) with no wrap handling. Past the wrap, textures and pool mirrors the CPU writes can miss a write, and every check reads as a write. At about 181 generations a frame that takes about 110 h at 60 fps or 27 h at 240. Only trace=perf's "mem: sizes" counted them, so nothing in a player's log could tell a "textures went stale after a day" report from other causes. The nine "++gen_now" sites now call gen_next, which hands out the next generation (gen_lock held exclusively, as at every site). When the value reaches 0xC0000000, 0xD0000000, 0xE0000000 or 0xF0000000 it logs the count, the frame, the rate per frame and about how many hours of play are left at that rate. At the wrap it logs that the generations ran out. That is five lines at most a session and one predicted branch per generation. The log queue takes no lock of vk_memory.c, so logging under gen_lock is safe. The wrap handling itself waits for approval. The new tests/gen_wrap_check extracts the section from the "page write generations" banner to the "dirty census" banner and runs it with stubs. It checks one line at each mark and at the wrap and none elsewhere, and the first line's rate and hours. It also expects the four comparisons that are known to answer wrong across the wrap, and says so: the change that handles the wrap turns them into failures there and flips them. On the code before this change the check fails (no lines). Checks that passed: gen_wrap_check, pass_cc_check on vk_memory.c, no new -Wall -Wextra warnings, gpa_check, mem_growth_check, mem_budget_check, wb_lazy_check, tex_release_check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
58 lines
2.4 KiB
Python
58 lines
2.4 KiB
Python
"""Build and run tests/gen_wrap_check.c: runtime/vk_memory.c's page write generations, extracted verbatim from its
|
|
"page write generations" banner to its "dirty census" banner, with the lines gen_next logs as the 32-bit generations
|
|
near their wrap (one at each of 0xC0000000, 0xD0000000, 0xE0000000, 0xF0000000 and one at the wrap), and the four
|
|
comparisons known to answer wrong across the wrap.
|
|
|
|
No GPU, no game files, any Python.
|
|
|
|
Usage: gen_wrap_check.py [--cc <clang>]
|
|
"""
|
|
import argparse
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
MSYS_BIN = Path(r'C:\msys64\ucrt64\bin')
|
|
BEGIN = '// ---------------------------------------------------------------- page write generations'
|
|
END = '// ---------------------------------------------------------------- dirty census'
|
|
|
|
|
|
def compiler(cc):
|
|
if cc:
|
|
return cc
|
|
if os.environ.get('CC'):
|
|
return os.environ['CC']
|
|
if os.name == 'nt' and (MSYS_BIN / 'clang.exe').exists():
|
|
return str(MSYS_BIN / 'clang.exe')
|
|
return shutil.which('clang') or 'clang'
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument('--cc', help='the C compiler (default: $CC, MSYS2 UCRT64 clang, clang on PATH)')
|
|
args = ap.parse_args()
|
|
src = (ROOT / 'runtime' / 'vk_memory.c').read_text(encoding='utf-8-sig')
|
|
a, b = src.find(BEGIN), src.find(END)
|
|
if a < 0 or b < a:
|
|
print('gen_wrap_check: FAIL: the section banners are not in runtime/vk_memory.c')
|
|
return 1
|
|
work = ROOT / 'build' / 'test' / 'gen_wrap'
|
|
work.mkdir(parents=True, exist_ok=True)
|
|
(work / 'gen_section.inc').write_text('// Extracted from runtime/vk_memory.c by tests/gen_wrap_check.py.\n' +
|
|
src[a:b], encoding='utf-8')
|
|
exe = work / ('gen_wrap_check.exe' if os.name == 'nt' else 'gen_wrap_check')
|
|
env = dict(os.environ)
|
|
if os.name == 'nt' and MSYS_BIN.exists():
|
|
env['PATH'] = str(MSYS_BIN) + os.pathsep + env.get('PATH', '')
|
|
subprocess.check_call([compiler(args.cc), '-std=gnu11', '-O1', '-Wall', '-Wno-unused-function',
|
|
'-Wno-unused-variable', '-I', str(work), str(ROOT / 'tests' / 'gen_wrap_check.c'), '-o',
|
|
str(exe)], env=env)
|
|
return subprocess.run([str(exe)], env=env, timeout=120).returncode
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|