diff --git a/experiments/bare_metal/runs/doe-riscv64-20261107-224732.csv b/experiments/bare_metal/runs/doe-riscv64-20261107-224732.csv new file mode 100644 index 00000000..e69de29b diff --git a/logs/20261107-224732/riscv64/qemu-riscv64-20261107-224732.log b/logs/20261107-224732/riscv64/qemu-riscv64-20261107-224732.log new file mode 100644 index 00000000..659595e9 --- /dev/null +++ b/logs/20261107-224732/riscv64/qemu-riscv64-20261107-224732.log @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:08448453d06f8ce28ede962fda83eaff8a0fe3a24535d856f62ce2fcd09b7f4a +size 7993 diff --git a/scripts/qemu_session.py b/scripts/qemu_session.py index ec667e96..31867d9d 100755 --- a/scripts/qemu_session.py +++ b/scripts/qemu_session.py @@ -213,9 +213,33 @@ def wait_for(pat, secs, after=0): return False -def check(name, cond): +def excerpt(near=None, after=20, tail=40): + """The serial log where a failed check looked (#136): the lines after the first match of + `near`, else the log's last lines -- control characters shown as escapes, so a terminal's + sequences cannot garble the job's output.""" + lines = text().splitlines() + start = None + if near is not None: + start = next((i for i, l in enumerate(lines) if re.search(near, l)), None) + if start is None: + start, what = max(0, len(lines) - tail), f"the log's last {tail} lines" + stop = len(lines) + else: + stop, what = min(len(lines), start + 1 + after), f"after /{near}/, line {start + 1}" + print(f" --- serial log, {what} ({os.path.relpath(log, ROOT)}):", flush=True) + for i in range(start, stop): + shown = "".join(c if c.isprintable() else repr(c)[1:-1] for c in lines[i]) + print(f" {i + 1:6} | {shown}", flush=True) + print(" ---", flush=True) + + +def check(name, cond, near=None): + """PASS or FAIL; a FAIL also prints the serial log where the check looked: after the first + line matching `near` (a regex), when it is given, else the log's end.""" global ok print(f"{'PASS' if cond else 'FAIL'}: {name}", flush=True) + if not cond: + excerpt(near) ok = ok and cond @@ -328,7 +352,7 @@ if m == "headless": elif m == "zuse": check("Boot disk: not a StarshipOS stick (an ISO or ESP boot)", - re.search(r"Boot disk: not a StarshipOS stick", text()) is not None) + re.search(r"Boot disk: not a StarshipOS stick", text()) is not None, near=r"Boot successful!") check("Zuse: identity confirmed", wait_for(r"Zuse: identity confirmed from attached thumbdrive", 120)) check("[zuse@Hera] ok>", wait_for(PROMPT, 60)) n = count(PROMPT) @@ -343,7 +367,7 @@ elif m in ("stick_boot", "two_sticks"): if m == "stick_boot": # the PC stick: Artemis is the rest of 2 GiB (well over 1 million user blocks), its blank # identity 500 MiB (about 380000) - check("Boot disk: a StarshipOS stick", re.search(r"Boot disk: a StarshipOS stick", text()) is not None) + check("Boot disk: a StarshipOS stick", re.search(r"Boot disk: a StarshipOS stick", text()) is not None, near=r"Boot successful!") check("System: StarForth v4", re.search(r"System: StarForth v4", text()) is not None) check("Artemis: the stick's partition attached", wait_for(r"Artemis: the stick's partition attached", 120)) @@ -370,7 +394,7 @@ elif m in ("stick_boot", "two_sticks"): elif m in ("stick_artemis", "stick_zuse"): if m == "stick_zuse": - check("Boot disk: a StarshipOS stick", re.search(r"Boot disk: a StarshipOS stick", text()) is not None) + check("Boot disk: a StarshipOS stick", re.search(r"Boot disk: a StarshipOS stick", text()) is not None, near=r"Boot successful!") check("Artemis: the stick's partition attached", wait_for(r"Artemis: the stick's partition attached", 120)) check("Zuse: identity confirmed", wait_for(r"Zuse: identity confirmed from attached thumbdrive", 120)) check("[zuse@Hera] ok>", wait_for(PROMPT, 60))