mesa/src/compiler/nir/nir_shader_bisect.py
Emma Anholt 66b157095c
Some checks are pending
macOS-CI / macOS-CI (dri) (push) Waiting to run
macOS-CI / macOS-CI (xlib) (push) Waiting to run
nir/shader_bisect: Allow passing in a --lo / --hi to continue a run.
Sometimes you fumble an answer, and would like to not restart from the
beginning (or just want to see the behavior of the script late in the run
if you're debugging it).  Pass in the last bad range, and you can keep
going.

Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/38760>
2025-12-04 22:47:25 +00:00

105 lines
3.3 KiB
Python
Executable file

#!/usr/bin/env python3
import argparse
import subprocess
import os
import re
def run(args, lo, hi):
print(f'NIR_SHADER_BISECT_LO: {lo}')
print(f'NIR_SHADER_BISECT_HI: {hi}')
env = os.environ.copy()
env['MESA_SHADER_CACHE_DISABLE'] = '1'
env['NIR_SHADER_BISECT_LO'] = lo
env['NIR_SHADER_BISECT_HI'] = hi
env.pop('MESA_LOG_FILE', None)
cmd = [args.cmd] + args.cmd_args
if args.debug:
print(f"running: {cmd}")
result = subprocess.run(cmd, env=env,
text=True, capture_output=True)
if args.debug:
print(f"Result: {result.returncode}")
print("stdout:")
print(result.stdout)
print("stderr:")
print(result.stderr)
shaders = set(re.findall(
"NIR bisect selected source_blake3: (.*) \((.*)\)", result.stderr))
num = len(shaders)
print(f'Shaders matched: {num}')
if num <= 5:
for blake3, id in sorted(shaders):
print(f' {blake3}')
return shaders
def was_good():
while True:
response = input('Was the previous run [g]ood or [b]ad? ')
if response in ('g', 'b'):
return response == 'g'
def bisect(args):
lo = f'{args.lo:064x}'
hi = f'{args.hi:064x}'
# Do an initial run to sanity check that the user has actually made
# nir_shader_bisect_select() select some broken behavior.
bad = run(args, lo, hi)
if was_good():
print("Entire hash range produced a good result -- did you make nir_shader_bisect_select() select the behavior you want?")
exit(1)
if len(bad) == 0:
print("No bad shaders detected -- did you rebuild after adding nir_shader_bisect_select()?")
exit(1)
while True:
if len(bad) == 1:
for shader in bad:
print(f"Bisected to source_blake3 {shader}")
print(
f"You can now replace nir_shader_bisect_select() with _mesa_printed_blake3_equal(s->info.source_blake3, (uint32_t[]){shader[0]})")
exit(0)
else:
num = len(bad)
print(f"Shaders remaining to bisect: {num}")
if num <= 5:
for shader in sorted(bad):
print(f' {shader}')
# Find the middle shader remaining in the set of shaders from the last
# bad run, and check if the bottom half of set of possibly-bad shaders
# (up to and including it) is bad.
ids = sorted([id for blake3, id in bad])
lo = ids[0]
split = ids[(len(ids) - 1) // 2]
cur = run(args, lo, split)
if was_good():
bad = bad.difference(cur)
else:
bad = cur
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-d', '--debug', action='store_true')
parser.add_argument('--lo', type=lambda x: int(x, base=16),
default=0,
help="NIR_SHADER_BISECT_LO from a bad range, to continue a cancelled run")
parser.add_argument('--hi', type=lambda x: int(x, base=16),
default=(1 << (8 * 32)) - 1,
help="NIR_SHADER_BISECT_HI from a bad range, to continue a cancelled run")
parser.add_argument('cmd')
parser.add_argument('cmd_args', nargs=argparse.REMAINDER)
args = parser.parse_args()
bisect(args)