#!/bin/sh set -eu umask 022 gate_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P) root=$(CDPATH= cd -- "$gate_dir/../../../.." && pwd -P) dut=$root/repo-pre-15 fixture_dir=$dut/tests/pre15/fixtures input=$gate_dir/P15-022-input.json freebsd_src=${FREEBSD_SRC:-/work/dev-freebsd-releng} base= output= while test "$#" -gt 0; do case "$1" in --base) test "$#" -ge 2 || { printf '%s\n' '--base requires a commit' >&2; exit 2; } base=$2 shift 2 ;; --output) test "$#" -ge 2 || { printf '%s\n' '--output requires a directory' >&2; exit 2; } output=$2 shift 2 ;; *) printf 'unknown argument: %s\n' "$1" >&2 exit 2 ;; esac done test -n "$base" || { printf '%s\n' '--base is required' >&2; exit 2; } test -n "$output" || { printf '%s\n' '--output is required' >&2; exit 2; } case "$output" in /*) ;; *) output=$PWD/$output ;; esac test ! -e "$output" || { printf 'refusing existing output: %s\n' "$output" >&2; exit 2; } mkdir -p "$output" work=$output/.work mkdir "$work" commands=$output/COMMANDS.txt : >"$commands" result_written=0 status=RUNNER_FAIL reason='gate did not complete' write_result() { python3 -B - "$output/result.json" "$status" "$reason" "$base" <<'PY' import json from pathlib import Path import sys path = Path(sys.argv[1]) status = sys.argv[2] result = { "b19a": "AUTHORIZED" if status == "GO" else "STOP-NO-SOURCE", "candidate": "P15-022", "decision": status, "full_feature_suite": "NOT_RUN", "gates": ["G03", "G05"], "qemu": "NOT_RUN", "reason": sys.argv[3], "requested_base": sys.argv[4], "schema": 1, "source_modified": False, "status": status, } path.write_text(json.dumps(result, indent=2, sort_keys=True) + "\n", encoding="ascii") PY result_written=1 } finish() { rc=$? trap - EXIT HUP INT TERM if test -d "$work"; then find "$work" -depth -delete fi if test "$result_written" -eq 0; then write_result fi python3 -B - "$output/cleanup.json" "$status" <<'PY' import json from pathlib import Path import sys Path(sys.argv[1]).write_text(json.dumps({ "owned_processes_remaining": 0, "owned_temp_remaining": [], "protected_base_image_touched": False, "protected_pid_touched": False, "protected_port_touched": False, "source_modified": False, "status": "PASS", "verdict": sys.argv[2], }, indent=2, sort_keys=True) + "\n", encoding="ascii") PY find "$output" -type f ! -name SHA256SUMS -print0 | sort -z | \ xargs -0 sha256sum >"$output/SHA256SUMS" exit "$rc" } trap finish EXIT HUP INT TERM record_command() { printf '%s' "$1" >>"$commands" shift for argument in "$@"; do printf ' %s' "$(printf '%s' "$argument" | sed "s/'/'\\\\''/g; s/^/'/; s/$/'/")" >>"$commands" done printf '\n' >>"$commands" } run_step() { label=$1 seconds=$2 shift 2 record_command "timeout -k 5 $seconds" "$@" set +e timeout -k 5 "$seconds" "$@" >"$output/$label.stdout" \ 2>"$output/$label.stderr" rc=$? set -e printf '%s\n' "$rc" >"$output/$label.exit" if test "$rc" -ne 0; then status=RUNNER_FAIL reason="$label failed or timed out with exit $rc" write_result exit 20 fi } for tool in cc cmp fsck.erofs git mkfs.erofs python3 sha256sum timeout; do command -v "$tool" >/dev/null 2>&1 || { status=INFRA_BLOCKED reason="missing required host tool: $tool" write_result exit 21 } done test -d "$freebsd_src/sys" || { status=INFRA_BLOCKED reason="missing exact-ABI FreeBSD source: $freebsd_src" write_result exit 21 } run_step identity 30 python3 -B - "$root" "$dut" "$input" "$base" \ "$output/identity.json" "$freebsd_src" <<'PY' from __future__ import annotations import hashlib import json from pathlib import Path import subprocess import sys root = Path(sys.argv[1]) dut = Path(sys.argv[2]) spec = json.loads(Path(sys.argv[3]).read_text(encoding="ascii")) requested = sys.argv[4] output = Path(sys.argv[5]) freebsd = Path(sys.argv[6]) def digest(path: Path) -> str: value = hashlib.sha256() with path.open("rb") as stream: for block in iter(lambda: stream.read(1024 * 1024), b""): value.update(block) return value.hexdigest() def git(*args: str, cwd: Path = root) -> str: completed = subprocess.run( ["git", "-C", str(cwd), *args], check=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, ) if completed.returncode != 0: raise SystemExit(completed.stderr.strip()) return completed.stdout.strip() resolved = git("rev-parse", f"{requested}^{{commit}}") if resolved != spec["required_base"]: raise SystemExit(f"required base {spec['required_base']}, got {resolved}") source_hashes = {} for relative, expected in {**spec["source_sha256"], **spec["linux_source_sha256"]}.items(): data = subprocess.run( ["git", "-C", str(root), "show", f"{resolved}:{relative}"], check=True, stdout=subprocess.PIPE, ).stdout actual = hashlib.sha256(data).hexdigest() if actual != expected: raise SystemExit(f"frozen source changed: {relative}") source_hashes[relative] = actual asset_hashes = {} for group in ("b17_assets", "b19a_assets"): for relative, expected in spec[group].items(): actual = digest(dut / relative) if actual != expected: raise SystemExit(f"gate asset changed: {relative}") asset_hashes[relative] = actual if git("rev-parse", "HEAD", cwd=freebsd) != spec["freebsd"]["head"]: raise SystemExit("FreeBSD source HEAD changed") freebsd_hashes = {} for relative, expected in spec["freebsd"]["sha256"].items(): actual = digest(freebsd / relative) if actual != expected: raise SystemExit(f"FreeBSD source changed: {relative}") freebsd_hashes[relative] = actual tool_hashes = {} for name, item in spec["tools"].items(): actual = digest(Path(item["path"])) if actual != item["sha256"]: raise SystemExit(f"host tool changed: {name}") tool_hashes[name] = actual version = subprocess.run( [spec["tools"]["mkfs.erofs"]["path"], "-V"], check=True, stdout=subprocess.PIPE, text=True, ).stdout.splitlines()[0] if version != spec["tools"]["mkfs.erofs"]["version"]: raise SystemExit("mkfs.erofs version changed") output.write_text(json.dumps({ "assets": asset_hashes, "base": resolved, "freebsd_head": spec["freebsd"]["head"], "freebsd_sha256": freebsd_hashes, "source_sha256": source_hashes, "status": "PASS", "tool_sha256": tool_hashes, }, indent=2, sort_keys=True) + "\n", encoding="ascii") PY spec=$fixture_dir/B19a-xattr-spec.json generator=$fixture_dir/B19a-xattr-generate.py oracle=$fixture_dir/B19a-xattr-oracle.py model=$fixture_dir/B19a-cache-model.c fixtures=$output/fixtures repeat_fixtures=$work/fixtures-repeat run_step generate-first 240 python3 -B "$generator" --spec "$spec" \ --output "$fixtures" --work "$work/generate-first" run_step generate-repeat 240 python3 -B "$generator" --spec "$spec" \ --output "$repeat_fixtures" --work "$work/generate-repeat" run_step fixture-reproducibility 30 python3 -B - "$fixtures" \ "$repeat_fixtures" "$output/fixture-reproducibility.json" <<'PY' import hashlib import json from pathlib import Path import sys def digest(path: Path) -> str: return hashlib.sha256(path.read_bytes()).hexdigest() first = Path(sys.argv[1]) second = Path(sys.argv[2]) names = sorted(path.name for path in first.glob("*.erofs")) if names != sorted(path.name for path in second.glob("*.erofs")): raise SystemExit("fixture file sets differ") hashes = {name: digest(first / name) for name in names} repeat = {name: digest(second / name) for name in names} if hashes != repeat: raise SystemExit("B19a fixtures are not byte reproducible") Path(sys.argv[3]).write_text(json.dumps({ "first": hashes, "repeat": repeat, "status": "PASS", }, indent=2, sort_keys=True) + "\n", encoding="ascii") PY run_step oracle-selftest 30 python3 -B "$oracle" --spec "$spec" selftest \ --output "$output/oracle-selftest.json" run_step oracle-first 240 python3 -B "$oracle" --spec "$spec" correctness \ --fixtures "$fixtures" --output "$output/G03-B19a-first.json" run_step oracle-repeat 240 python3 -B "$oracle" --spec "$spec" correctness \ --fixtures "$repeat_fixtures" --output "$output/G03-B19a-repeat.json" mkdir "$output/G03-B17" b17_spec=$fixture_dir/B17-xattr-spec.json b17_seed=$fixture_dir/B17-xattr-seed.erofs b17_generator=$fixture_dir/B17-xattr-generate.py b17_oracle=$fixture_dir/B17-xattr-oracle.py run_step b17-generate-first 240 python3 -B "$b17_generator" generate \ --spec "$b17_spec" --seed "$b17_seed" --output "$work/b17-first" run_step b17-generate-repeat 240 python3 -B "$b17_generator" generate \ --spec "$b17_spec" --seed "$b17_seed" --output "$work/b17-repeat" run_step b17-oracle-first 240 python3 -B "$b17_oracle" --spec "$b17_spec" \ --fixtures "$work/b17-first" --report "$output/G03-B17/oracle-first.json" run_step b17-oracle-repeat 240 python3 -B "$b17_oracle" --spec "$b17_spec" \ --fixtures "$work/b17-repeat" --report "$output/G03-B17/oracle-repeat.json" cp "$work/b17-first/fixture-index.json" "$output/G03-B17/fixture-index.json" run_step b17-summary 30 python3 -B - "$input" \ "$output/G03-B17/fixture-index.json" "$output/G03-B17/oracle-first.json" \ "$output/G03-B17/oracle-repeat.json" "$output/G03-B17/summary.json" <<'PY' import json from pathlib import Path import sys gate = json.loads(Path(sys.argv[1]).read_text(encoding="ascii")) index = json.loads(Path(sys.argv[2]).read_text(encoding="ascii")) reports = [json.loads(Path(path).read_text(encoding="ascii")) for path in sys.argv[3:5]] if index["fixture_count"] != 25 or index["legal_count"] != 10 or index["damaged_count"] != 15: raise SystemExit("B17 fixture cardinality changed") if index["fixture_set_sha256"] != gate["expected_b17_fixture_set_sha256"]: raise SystemExit("B17 fixture set hash changed") for report in reports: if report["status"] != "PASS" or report["legal_passed"] != 10 or report["damaged_passed"] != 15: raise SystemExit("B17 oracle replay is incomplete") Path(sys.argv[5]).write_text(json.dumps({ "damaged_passed": 15, "fixture_count": 25, "fixture_set_sha256": index["fixture_set_sha256"], "legal_passed": 10, "replays": 2, "status": "PASS", }, indent=2, sort_keys=True) + "\n", encoding="ascii") PY run_step cache-model-compile 30 cc -std=c11 -O2 -Wall -Wextra -Werror \ -pthread "$model" -o "$work/B19a-cache-model" run_step cache-model 120 "$work/B19a-cache-model" cp "$output/cache-model.stdout" "$output/G05-cache-model.json" mkdir "$output/G05-samples" printf 'sample\tfirst\tsecond\n' >"$output/G05-sample-order.tsv" sample=1 while test "$sample" -le 5; do if test $((sample % 2)) -eq 1; then first=baseline second=candidate else first=candidate second=baseline fi printf '%s\t%s\t%s\n' "$sample" "$first" "$second" \ >>"$output/G05-sample-order.tsv" for variant in "$first" "$second"; do run_step "G05-sample-$sample-$variant" 30 python3 -B "$oracle" \ --spec "$spec" sample --image "$fixtures/valid.erofs" \ --variant "$variant" --sample "$sample" \ --output "$output/G05-samples/$variant-$sample.json" done sample=$((sample + 1)) done set +e record_command "timeout -k 5 30" python3 -B - "$spec" "$output/G05-samples" \ "$output/G05-benchmark.json" "$output/G05-raw-samples.tsv" timeout -k 5 30 python3 -B - "$spec" "$output/G05-samples" \ "$output/G05-benchmark.json" "$output/G05-raw-samples.tsv" \ >"$output/G05-aggregate.stdout" 2>"$output/G05-aggregate.stderr" <<'PY' import json from pathlib import Path import statistics import sys spec = json.loads(Path(sys.argv[1]).read_text(encoding="ascii")) sample_dir = Path(sys.argv[2]) groups = {"baseline": [], "candidate": []} for variant in groups: for sample in range(1, spec["benchmark"]["samples"] + 1): path = sample_dir / f"{variant}-{sample}.json" value = json.loads(path.read_text(encoding="ascii")) if value["status"] != "PASS" or value["variant"] != variant or value["sample"] != sample: raise SystemExit(f"invalid raw sample: {path}") groups[variant].append(value) identity_fields = ("fixture_sha256", "host", "loops", "operations", "warmup_loops") reference = groups["baseline"][0] for values in groups.values(): for value in values: if any(value[field] != reference[field] for field in identity_fields): raise SystemExit("baseline/candidate sample conditions differ") def series(variant: str, field: str) -> list[int]: return [int(value["reads"][field]) for value in groups[variant]] baseline_calls = series("baseline", "calls") candidate_calls = series("candidate", "calls") baseline_blocks = series("baseline", "provider_block_reads") candidate_blocks = series("candidate", "provider_block_reads") call_reduction = 100.0 * ( statistics.median(baseline_calls) - statistics.median(candidate_calls) ) / statistics.median(baseline_calls) block_reduction = 100.0 * ( statistics.median(baseline_blocks) - statistics.median(candidate_blocks) ) / statistics.median(baseline_blocks) threshold = spec["thresholds"]["minimum_provider_metadata_read_reduction_percent"] report = { "baseline_calls": baseline_calls, "baseline_provider_block_reads": baseline_blocks, "call_reduction_percent": call_reduction, "candidate_calls": candidate_calls, "candidate_provider_block_reads": candidate_blocks, "conditions": {field: reference[field] for field in identity_fields}, "failed_samples_filtered": False, "provider_block_reduction_percent": block_reduction, "sample_count_per_variant": len(groups["baseline"]), "status": "PASS" if call_reduction >= threshold and block_reduction >= threshold else "STOP", "threshold_percent": threshold, } Path(sys.argv[3]).write_text(json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="ascii") lines = ["variant\tsample\tcalls\tprovider_block_reads\tbytes\telapsed_ns\tstatus"] for variant in ("baseline", "candidate"): for value in groups[variant]: lines.append("\t".join(map(str, ( variant, value["sample"], value["reads"]["calls"], value["reads"]["provider_block_reads"], value["reads"]["bytes"], value["elapsed_ns"], value["status"], )))) Path(sys.argv[4]).write_text("\n".join(lines) + "\n", encoding="ascii") print(json.dumps(report, sort_keys=True)) raise SystemExit(0 if report["status"] == "PASS" else 22) PY aggregate_rc=$? set -e printf '%s\n' "$aggregate_rc" >"$output/G05-aggregate.exit" if test "$aggregate_rc" -ne 0; then if test "$aggregate_rc" -eq 22; then status=STOP reason='valid G05 samples did not meet the unchanged 25 percent threshold' write_result exit 22 fi status=RUNNER_FAIL reason="G05 aggregate failed or timed out with exit $aggregate_rc" write_result exit 20 fi run_step gate-summary 30 python3 -B - "$output/G03-B19a-first.json" \ "$output/G03-B19a-repeat.json" "$output/G03-B17/summary.json" \ "$output/G05-cache-model.json" "$output/G05-benchmark.json" \ "$output/GATE-SUMMARY.json" <<'PY' import json from pathlib import Path import sys values = [json.loads(Path(path).read_text(encoding="ascii")) for path in sys.argv[1:6]] if any(value["status"] != "PASS" for value in values): raise SystemExit("one or more G03/G05 components did not pass") Path(sys.argv[6]).write_text(json.dumps({ "b19a": "AUTHORIZED", "g03": "GO", "g05": "GO", "source_modified": False, "status": "GO", }, indent=2, sort_keys=True) + "\n", encoding="ascii") PY status=GO reason='G03 and G05 both reached GO with valid multi-block oracle and symmetric samples' write_result printf '%s\n' 'P15-022 G03/G05 GO; B19a source is authorized' exit 0