mirror of
https://github.com/elwrcl/intel-hard-lab.git
synced 2026-10-31 15:48:02 +03:00
first commit
This commit is contained in:
54 files changed
+156785
No files matched your search
@@ -0,0 +1,240 @@
|
||||
#!/usr/bin/env python3
|
||||
import collections
|
||||
import glob
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def now_iso():
|
||||
return datetime.now().astimezone().isoformat(timespec="seconds")
|
||||
|
||||
|
||||
def wc_l(path):
|
||||
if not os.path.exists(path):
|
||||
return 0
|
||||
with open(path, "rb") as f:
|
||||
return sum(1 for _ in f)
|
||||
|
||||
|
||||
def read_lines(path):
|
||||
if not os.path.exists(path):
|
||||
return []
|
||||
with open(path) as f:
|
||||
return [l.rstrip("\n") for l in f if l.strip()]
|
||||
|
||||
|
||||
def write_lines(path, lines):
|
||||
with open(path, "w") as f:
|
||||
for l in lines:
|
||||
f.write(l + "\n")
|
||||
|
||||
|
||||
def begin_test_case_names(qpa_path):
|
||||
names = set()
|
||||
if not os.path.exists(qpa_path):
|
||||
return names
|
||||
txt = open(qpa_path, errors="replace").read()
|
||||
for line in txt.splitlines():
|
||||
if line.startswith("#beginTestCaseResult "):
|
||||
names.add(line[len("#beginTestCaseResult "):].strip())
|
||||
return names
|
||||
|
||||
|
||||
def main():
|
||||
lab_root = Path(os.environ.get("LAB_ROOT", Path(__file__).resolve().parent.parent))
|
||||
drivers_root = Path(os.environ.get("DRIVERS_ROOT", lab_root.parent))
|
||||
mesa_src = Path(os.environ.get("MESA_SRC", drivers_root / "intel-hard-graphics"))
|
||||
mesa_build = Path(os.environ.get("MESA_BUILD", mesa_src / "build"))
|
||||
cts_dir = Path(os.environ.get("CTS_DIR", mesa_src / "VK-GL-CTS/build-cts/external/vulkancts/modules/vulkan"))
|
||||
cts_mustpass = Path(os.environ.get("CTS_MUSTPASS", mesa_src / "VK-GL-CTS/external/vulkancts/mustpass/main/vk-default"))
|
||||
icd = Path(os.environ.get("VK_DRIVER_FILES", mesa_build / "src/intel/vulkan_hasvk/intel_hasvk13_devenv_icd.x86_64.json"))
|
||||
exclude = Path(os.environ.get("EXCLUDE", lab_root / "cts/cts-exclude-gen7.txt"))
|
||||
|
||||
scope = sys.argv[1] if len(sys.argv) > 1 else "mustpass"
|
||||
chunk_size = int(sys.argv[2]) if len(sys.argv) > 2 else 100000
|
||||
pause = int(sys.argv[3]) if len(sys.argv) > 3 else 30
|
||||
outdir = Path(os.environ.get("OUTDIR", Path.cwd() / "cts-chunked"))
|
||||
|
||||
stop_on_hang = os.environ.get("STOP_ON_HANG", "0") == "1"
|
||||
max_hangs = int(os.environ.get("MAX_HANGS", "3"))
|
||||
max_chunks = int(os.environ.get("MAX_CHUNKS", "3"))
|
||||
max_subruns = int(os.environ.get("MAX_SUBRUNS", "40"))
|
||||
hangs = 0
|
||||
|
||||
deqp = cts_dir / "deqp-vk"
|
||||
for p in (deqp, icd):
|
||||
if not p.exists():
|
||||
print(f"missing: {p}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
outdir.mkdir(parents=True, exist_ok=True)
|
||||
os.chdir(cts_dir)
|
||||
|
||||
src_txt = outdir / "src.txt"
|
||||
cases_txt = outdir / "cases.txt"
|
||||
if not (src_txt.exists() and src_txt.stat().st_size > 0):
|
||||
if scope == "all":
|
||||
out = subprocess.run([str(deqp), "--deqp-runmode=stdout-caselist"],
|
||||
capture_output=True, text=True).stdout
|
||||
lines = [l[len("TEST: "):] for l in out.splitlines() if l.startswith("TEST: ")]
|
||||
write_lines(src_txt, lines)
|
||||
else:
|
||||
lines = []
|
||||
for f in sorted(glob.glob(str(cts_mustpass / "*.txt"))):
|
||||
lines.extend(l for l in read_lines(f) if l.startswith("dEQP-VK"))
|
||||
write_lines(src_txt, lines)
|
||||
|
||||
if exclude.exists() and exclude.stat().st_size > 0:
|
||||
excl = set(read_lines(exclude))
|
||||
write_lines(cases_txt, [l for l in read_lines(src_txt) if l not in excl])
|
||||
else:
|
||||
write_lines(cases_txt, read_lines(src_txt))
|
||||
|
||||
todo_txt = outdir / "todo.txt"
|
||||
prev = sorted(glob.glob(str(outdir / "chunk-*.qpa")))
|
||||
if prev:
|
||||
done = set()
|
||||
for f in prev:
|
||||
done |= begin_test_case_names(f)
|
||||
done_txt = outdir / "done.txt"
|
||||
write_lines(done_txt, sorted(done))
|
||||
cases = read_lines(cases_txt)
|
||||
todo = [l for l in cases if l not in done]
|
||||
write_lines(todo_txt, todo)
|
||||
print(f"resume: {len(done)} recorded, {len(todo)} left")
|
||||
else:
|
||||
cases = read_lines(cases_txt)
|
||||
write_lines(todo_txt, cases)
|
||||
print(f"{len(cases)} cases to run")
|
||||
|
||||
if not (todo_txt.exists() and todo_txt.stat().st_size > 0):
|
||||
print("nothing left to run — summarising")
|
||||
|
||||
todo = read_lines(todo_txt)
|
||||
total = len(todo)
|
||||
n = 0
|
||||
start = 1
|
||||
ran = 0
|
||||
rc = 0
|
||||
sub = 0
|
||||
|
||||
while todo and start <= total:
|
||||
n += 1
|
||||
while glob.glob(str(outdir / f"chunk-{n}.*.qpa")):
|
||||
n += 1
|
||||
|
||||
list_path = outdir / f"chunk-{n}.txt"
|
||||
chunk_lines = todo[start - 1: start - 1 + chunk_size]
|
||||
write_lines(list_path, chunk_lines)
|
||||
if not chunk_lines:
|
||||
break
|
||||
|
||||
print(f"chunk {n}: {len(chunk_lines)} cases (from line {start} of {total})")
|
||||
want = len(chunk_lines)
|
||||
work_path = outdir / f"chunk-{n}.work"
|
||||
write_lines(work_path, chunk_lines)
|
||||
sub = 0
|
||||
|
||||
while work_path.exists() and work_path.stat().st_size > 0:
|
||||
sub += 1
|
||||
if sub > max_subruns:
|
||||
print(f" gave up after {max_subruns} subruns")
|
||||
break
|
||||
|
||||
qpa = outdir / f"chunk-{n}.{sub}.qpa"
|
||||
log = outdir / f"chunk-{n}.{sub}.log"
|
||||
env = dict(os.environ, VK_DRIVER_FILES=str(icd))
|
||||
with open(log, "w") as lf:
|
||||
proc = subprocess.run(
|
||||
[str(deqp), f"--deqp-caselist-file={work_path}",
|
||||
f"--deqp-log-filename={qpa}",
|
||||
"--deqp-log-images=disable", "--deqp-log-shader-sources=disable"],
|
||||
stdout=lf, stderr=subprocess.STDOUT, env=env)
|
||||
rc = proc.returncode
|
||||
|
||||
work_lines = read_lines(work_path)
|
||||
left = len(work_lines)
|
||||
got = sum(1 for l in open(qpa, errors="replace").read().splitlines()
|
||||
if l.startswith("#beginTestCaseResult")) if qpa.exists() else 0
|
||||
if got >= left:
|
||||
break
|
||||
|
||||
done_now = begin_test_case_names(qpa)
|
||||
next_lines = [l for l in work_lines if l not in done_now]
|
||||
if len(next_lines) == left:
|
||||
culprit = work_lines[0] if work_lines else ""
|
||||
with open(outdir / "crashers.txt", "a") as cf:
|
||||
cf.write(f"{now_iso()} crashed before recording: {culprit}\n")
|
||||
next_lines = work_lines[1:]
|
||||
write_lines(work_path, next_lines)
|
||||
print(f" subrun {sub}: rc={rc}, {got} done, {len(next_lines)} left — restarting")
|
||||
time.sleep(pause)
|
||||
|
||||
for suffix in (".work", ".work.done", ".work.next"):
|
||||
p = outdir / f"chunk-{n}{suffix}"
|
||||
if p.exists():
|
||||
p.unlink()
|
||||
|
||||
done_n = 0
|
||||
bad_log = False
|
||||
for f in sorted(glob.glob(str(outdir / f"chunk-{n}.*.qpa"))):
|
||||
done_n += sum(1 for l in open(f, errors="replace").read().splitlines()
|
||||
if l.startswith("#beginTestCaseResult"))
|
||||
for f in sorted(glob.glob(str(outdir / f"chunk-{n}.*.log"))):
|
||||
if "DeviceLost" in open(f, errors="replace").read():
|
||||
bad_log = True
|
||||
print(f" rc={rc}, {done_n}/{want} results ({sub} subrun)")
|
||||
|
||||
bad = done_n < want or bad_log
|
||||
wait_s = pause
|
||||
if bad:
|
||||
hangs += 1
|
||||
with open(outdir / "hangs.txt", "a") as hf:
|
||||
hf.write(f"{now_iso()} chunk {n} ended badly (rc={rc})\n")
|
||||
if stop_on_hang:
|
||||
print(" chunk ended badly — stopping (STOP_ON_HANG=1)")
|
||||
print(" rerun the same command to continue from here")
|
||||
break
|
||||
wait_s = pause * 4
|
||||
print(f" chunk ended badly (#{hangs}) — cooling down {wait_s}s")
|
||||
if max_hangs > 0 and hangs >= max_hangs:
|
||||
print(f" {hangs} bad chunks — stopping (MAX_HANGS={max_hangs})")
|
||||
break
|
||||
|
||||
start += chunk_size
|
||||
ran += 1
|
||||
if max_chunks > 0 and ran >= max_chunks and start <= total:
|
||||
print()
|
||||
print(f"{ran} chunks done this boot (MAX_CHUNKS={max_chunks}) — stopping here.")
|
||||
print(f"REBOOT, then rerun the same command to continue from case {start}.")
|
||||
break
|
||||
if start <= total:
|
||||
time.sleep(wait_s)
|
||||
|
||||
res = {}
|
||||
for f in sorted(glob.glob(str(outdir / "chunk-*.qpa"))):
|
||||
txt = open(f, errors="replace").read()
|
||||
for block in re.split(r"#beginTestCaseResult ", txt)[1:]:
|
||||
name = block.split("\n", 1)[0].strip()
|
||||
m = re.search(r'<Result StatusCode="(\w+)">', block)
|
||||
res[name] = m.group(1) if m else "Crash"
|
||||
|
||||
counts = collections.Counter(res.values())
|
||||
print(f"\n{sum(counts.values())} results")
|
||||
for k, v in counts.most_common():
|
||||
print(f" {k:16} {v}")
|
||||
|
||||
with open(outdir / "failures.txt", "w") as fh:
|
||||
for name, status in sorted(res.items()):
|
||||
if status not in ("Pass", "NotSupported"):
|
||||
fh.write(f"{status}\t{name}\n")
|
||||
print(f"\nfailures -> {outdir}/failures.txt")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user