Внятные сообщения preflight и предел dzn на размер привязки

preflight печатал последнюю строку вывода упавшего прогона, а у паники Rust
последняя строка — «note: run with RUST_BACKTRACE=1», то есть ноль сведений о
причине. Теперь из вывода достаётся собственное сообщение решателя, а для паники —
то, что стоит ПОСЛЕ строки «panicked at». Вместо

  A10_turb_n2048_kbc   note: run with `RUST_BACKTRACE=1` ...

печатается

  A10_turb_n2048_kbc
      wgpu error: Validation Error | In Device::create_bind_group, label = 'level'
      | Buffer binding 0 range 150994944 exceeds `max_*_buffer_binding_size` limit 134217728

Заодно задокументировано само ограничение. dzn объявляет
max_storage_buffer_binding_size = 128 МиБ против гигабайтов у нативных драйверов,
при том что max_buffer_size у него 2047 МиБ: держать большой буфер можно, показать
шейдеру одной привязкой — нет. Потолок выходит 3.73 млн узлов (около 1920x1920),
и 14 прогонов кампании из 115 в него не влезают. На эти 14 приходится 70.7%
стоимости, так что для кампании ограничение решающее.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-31 18:35:07 +03:00
co-authored by Claude Opus 5
parent 81985b169e
commit 6344c7d205
2 changed files with 76 additions and 3 deletions
+37 -3
View File
@@ -27,6 +27,39 @@ DROP = {"--gif", "--xt", "--case-csv", "--gif-field", "--gif-downsample", "--gif
"--gif-every", "--gif-fps", "--series-every"}
# Строки, которые ничего не объясняют и только вытесняют полезные.
NOISE = (
"note: run with `RUST_BACKTRACE",
"note: Some details are omitted",
"WARNING: dzn is not a conformant",
"stack backtrace",
"Caused by:",
)
def explain(output):
"""Достать из вывода упавшего прогона то, ради чего его вообще читают.
Раньше бралась последняя строка вывода — а у паники Rust последняя строка это
«note: run with RUST_BACKTRACE=1», то есть ровно ноль сведений о причине.
Полезное лежит либо в собственном сообщении решателя, либо на строке ПОСЛЕ
«panicked at»: там текст самой паники.
"""
out = [l.rstrip() for l in output.splitlines() if l.strip()]
out = [l for l in out if not any(n in l for n in NOISE)]
if not out:
return "(без вывода)"
for l in out:
if l.lstrip().startswith("ОШИБКА"):
return l.strip()
for i, l in enumerate(out):
if "panicked at" in l:
rest = [x.strip() for x in out[i + 1:]]
return " | ".join(rest[:4]) if rest else l.strip()
return out[-1].strip()
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--group", help="только эта группа, например I")
@@ -64,14 +97,15 @@ def main():
ok = p.returncode == 0
print("." if ok else "X", end="", flush=True)
if not ok:
tail = (p.stdout + p.stderr).decode("utf-8", "replace").strip().splitlines()
bad.append((r["id"], tail[-1] if tail else "(без вывода)"))
out = (p.stdout + p.stderr).decode("utf-8", "replace")
bad.append((r["id"], explain(out)))
if i % 40 == 0:
print(f" {i}/{len(runs)}", flush=True)
print(f"\n\nпроверено сценариев: {len(runs)}, не запустились: {len(bad)}")
for id_, msg in bad:
print(f" {id_:<28} {msg}")
print(f" {id_}")
print(f" {msg}")
return 1 if bad else 0