update
This commit is contained in:
Executable
+217
@@ -0,0 +1,217 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
: "${PRE15_DUT:?PRE15_DUT is required}"
|
||||
: "${PRE15_ROOT:?PRE15_ROOT is required}"
|
||||
: "${PRE15_CASE_TMP:?PRE15_CASE_TMP is required}"
|
||||
: "${PRE15_RUN_DIR:?PRE15_RUN_DIR is required}"
|
||||
: "${PRE15_LIB_DIR:?PRE15_LIB_DIR is required}"
|
||||
. "$PRE15_LIB_DIR/runner.sh"
|
||||
|
||||
fixture_dir=$PRE15_DUT/tests/pre15/fixtures
|
||||
policy=$fixture_dir/B12-readahead-policy.json
|
||||
kld_builder=$fixture_dir/B12-build-kld.sh
|
||||
artifacts=$PRE15_RUN_DIR/artifacts
|
||||
|
||||
for tool in awk clang file git nm python3 sha256sum timeout; do
|
||||
command -v "$tool" >/dev/null 2>&1 || \
|
||||
pre15_infra_blocked "missing B12 host tool: $tool"
|
||||
done
|
||||
|
||||
pre15_record_fixture b12-policy "$policy"
|
||||
pre15_record_fixture b12-kld-builder "$kld_builder"
|
||||
pre15_record_fixture b12-case "$PRE15_DUT/tests/pre15/cases/B12-readahead.sh"
|
||||
for source in data.c dir.c internal.h; do
|
||||
pre15_record_fixture "b12-$source" "$PRE15_DUT/src/$source"
|
||||
done
|
||||
mkdir -p "$artifacts"
|
||||
pre15_target_reached
|
||||
|
||||
if python3 -B - "$PRE15_ROOT" "$PRE15_DUT" "$policy" \
|
||||
"$artifacts/B12-policy-report.json" <<'PY'
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import statistics
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
root = Path(sys.argv[1])
|
||||
dut = Path(sys.argv[2])
|
||||
policy_path = Path(sys.argv[3])
|
||||
report_path = Path(sys.argv[4])
|
||||
policy = json.loads(policy_path.read_text(encoding="ascii"))
|
||||
if policy.get("schema") != 1 or policy.get("candidate") != "P15-087":
|
||||
raise SystemExit("invalid B12 policy identity")
|
||||
|
||||
|
||||
def digest(path: Path) -> str:
|
||||
return hashlib.sha256(path.read_bytes()).hexdigest()
|
||||
|
||||
|
||||
source_hashes = {
|
||||
relative: digest(dut / relative)
|
||||
for relative in policy["source_sha256"]
|
||||
}
|
||||
if source_hashes != policy["source_sha256"]:
|
||||
raise SystemExit("B12 production source differs from the accepted source set")
|
||||
|
||||
changed = subprocess.run(
|
||||
[
|
||||
"git", "-C", str(root), "diff", "--name-only",
|
||||
policy["baseline"], "--", "repo-pre-15/src",
|
||||
],
|
||||
check=True,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
).stdout.splitlines()
|
||||
expected_changed = [
|
||||
"repo-pre-15/src/data.c",
|
||||
"repo-pre-15/src/dir.c",
|
||||
"repo-pre-15/src/internal.h",
|
||||
]
|
||||
if sorted(changed) != expected_changed:
|
||||
raise SystemExit(f"B12 production write set mismatch: {changed}")
|
||||
|
||||
data = (dut / "src/data.c").read_text(encoding="utf-8")
|
||||
directory = (dut / "src/dir.c").read_text(encoding="utf-8")
|
||||
internal = (dut / "src/internal.h").read_text(encoding="utf-8")
|
||||
if "cluster_read(" in data + directory + internal:
|
||||
raise SystemExit("B12 must not introduce cluster_read")
|
||||
if data.count("breadn(") != 1:
|
||||
raise SystemExit("B12 must contain one backing-vnode breadn call")
|
||||
if not re.search(r"breadn\(dif->devvp,", data):
|
||||
raise SystemExit("B12 breadn is not issued on erofs_device_info.devvp")
|
||||
required_data = (
|
||||
"#define EROFS_DIR_READAHEAD_BYTES\t(1024 * 1024)",
|
||||
"#define EROFS_DIR_READAHEAD_SLOTS\t(EROFS_DIR_READAHEAD_BYTES / PAGE_SIZE)",
|
||||
"future.m_dif != current.m_dif",
|
||||
"future.m_pa != current.m_pa + step",
|
||||
"vi->datalayout == EROFS_INODE_FLAT_PLAIN",
|
||||
"return (erofs_read_data_impl(sbi, vi, loff, len, 0, bufp));",
|
||||
)
|
||||
for marker in required_data:
|
||||
if marker not in data:
|
||||
raise SystemExit(f"missing B12 data policy marker: {marker}")
|
||||
if directory.count("erofs_read_data_readahead(") != 1:
|
||||
raise SystemExit("B12 directory hint is not limited to readdir")
|
||||
if "sequential = logical_off == 0;" not in directory:
|
||||
raise SystemExit("B12 random seek no-op predicate is absent")
|
||||
if internal.count("erofs_read_data_readahead(") != 1:
|
||||
raise SystemExit("B12 internal prototype is absent or duplicated")
|
||||
|
||||
evidence = root / policy["gate_evidence"]
|
||||
result_path = evidence / "result.json"
|
||||
rows_path = evidence / "runs.tsv"
|
||||
if digest(result_path) != policy["gate_result_sha256"]:
|
||||
raise SystemExit("B12 gate result hash mismatch")
|
||||
if digest(rows_path) != policy["gate_rows_sha256"]:
|
||||
raise SystemExit("B12 gate rows hash mismatch")
|
||||
result = json.loads(result_path.read_text(encoding="ascii"))
|
||||
if result.get("status") != "GO" or result.get("b12") != "AUTHORIZED":
|
||||
raise SystemExit("P15-087 did not authorize B12")
|
||||
if result.get("qemu") != "PASS" or not all(result.get("checks", {}).values()):
|
||||
raise SystemExit("P15-087 runtime or semantic checks are incomplete")
|
||||
thresholds = result.get("thresholds", {})
|
||||
if thresholds != {
|
||||
"maximum_extra_provider_reads_percent": policy["maximum_extra_provider_reads_percent"],
|
||||
"minimum_cold_median_improvement_percent": policy["minimum_cold_median_improvement_percent"],
|
||||
}:
|
||||
raise SystemExit("P15-087 thresholds differ from the frozen B12 policy")
|
||||
|
||||
rows = []
|
||||
with rows_path.open(encoding="ascii", newline="") as source:
|
||||
for raw in csv.reader(source, delimiter="\t"):
|
||||
if len(raw) != 10:
|
||||
raise SystemExit(f"invalid B12 gate row: {raw}")
|
||||
rows.append({
|
||||
"variant": raw[0],
|
||||
"run": raw[1],
|
||||
"mode": raw[3],
|
||||
"elapsed_ns": int(raw[4]),
|
||||
"provider_reads": int(raw[5]),
|
||||
"entry_count": int(raw[7]),
|
||||
"hash": raw[8],
|
||||
"final_cookie": int(raw[9]),
|
||||
})
|
||||
sequential = [row for row in rows if row["mode"] == "sequential"]
|
||||
random_rows = [row for row in rows if row["mode"] == "random"]
|
||||
baseline = [row for row in sequential if row["variant"] == "baseline"]
|
||||
candidate = [row for row in sequential if row["variant"] == "candidate"]
|
||||
if len(baseline) != 5 or len(candidate) != 5 or len(random_rows) != 2:
|
||||
raise SystemExit("B12 gate does not contain the complete 5+5 and 1+1 sample set")
|
||||
baseline_ns = statistics.median(row["elapsed_ns"] for row in baseline)
|
||||
candidate_ns = statistics.median(row["elapsed_ns"] for row in candidate)
|
||||
improvement = (baseline_ns - candidate_ns) * 100.0 / baseline_ns
|
||||
baseline_reads = statistics.median(row["provider_reads"] for row in baseline)
|
||||
candidate_reads = statistics.median(row["provider_reads"] for row in candidate)
|
||||
extra_reads = (candidate_reads - baseline_reads) * 100.0 / baseline_reads
|
||||
if improvement < policy["minimum_cold_median_improvement_percent"]:
|
||||
raise SystemExit("B12 recomputed cold median improvement misses the gate")
|
||||
if extra_reads > policy["maximum_extra_provider_reads_percent"]:
|
||||
raise SystemExit("B12 recomputed provider-read delta misses the gate")
|
||||
if any(
|
||||
(row["entry_count"], row["hash"], row["final_cookie"])
|
||||
!= (18002, "427bb414efa99dc0", 3880368)
|
||||
for row in sequential
|
||||
):
|
||||
raise SystemExit("B12 sequential correctness rows differ from the oracle")
|
||||
if {
|
||||
(row["provider_reads"], row["entry_count"], row["hash"], row["final_cookie"])
|
||||
for row in random_rows
|
||||
} != {(19, 292, "9805eadece9f500e", 1998932)}:
|
||||
raise SystemExit("B12 random path is not an exact no-op pair")
|
||||
|
||||
report = {
|
||||
"baseline_samples": len(baseline),
|
||||
"candidate_samples": len(candidate),
|
||||
"baseline_median_elapsed_ns": baseline_ns,
|
||||
"candidate_median_elapsed_ns": candidate_ns,
|
||||
"cold_median_improvement_percent": improvement,
|
||||
"extra_provider_reads_percent": extra_reads,
|
||||
"gate": "GO",
|
||||
"qemu_runtime": "PASS",
|
||||
"random_samples": len(random_rows),
|
||||
"source_sha256": source_hashes,
|
||||
"status": "PASS",
|
||||
"window_bytes": policy["maximum_readahead_bytes"],
|
||||
}
|
||||
report_path.write_text(
|
||||
json.dumps(report, indent=2, sort_keys=True) + "\n", encoding="ascii"
|
||||
)
|
||||
PY
|
||||
then
|
||||
:
|
||||
else
|
||||
pre15_dut_fail 'B12 source, write-set, or frozen G11 policy replay failed'
|
||||
fi
|
||||
pre15_record_fixture b12-policy-report "$artifacts/B12-policy-report.json"
|
||||
|
||||
module=$PRE15_CASE_TMP/B12-erofs-zstdio0.ko
|
||||
if ! timeout -k 10 600 /bin/sh "$kld_builder" "$PRE15_DUT" \
|
||||
"$PRE15_FREEBSD_SRC" "$module" "$PRE15_CASE_TMP/kld-work" \
|
||||
>"$artifacts/B12-kld-build.stdout" 2>"$artifacts/B12-kld-build.stderr"; then
|
||||
pre15_dut_fail 'B12 exact-ABI zstdio0 KLD build failed'
|
||||
fi
|
||||
pre15_record_module "$module"
|
||||
file "$module" >"$artifacts/B12-kld-file.txt"
|
||||
sha256sum "$module" >"$artifacts/B12-kld-sha256.txt"
|
||||
nm -g "$module" | LC_ALL=C sort >"$artifacts/B12-kld-nm-global.txt"
|
||||
nm -u "$module" | LC_ALL=C sort >"$artifacts/B12-kld-nm-u.txt"
|
||||
if ! awk '$NF == "erofs_read_data_readahead" { found = 1 } END { exit !found }' \
|
||||
"$artifacts/B12-kld-nm-global.txt"; then
|
||||
pre15_dut_fail 'B12 exact-ABI KLD lacks the directory readahead symbol'
|
||||
fi
|
||||
if grep -q ' ZSTD_' "$artifacts/B12-kld-nm-u.txt"; then
|
||||
pre15_dut_fail 'B12 zstdio0 KLD contains an unexpected Zstd symbol'
|
||||
fi
|
||||
|
||||
printf '%s\n' \
|
||||
'B12-policy PASS: exact source/write set and frozen 5+5 G11 statistics' \
|
||||
'K zstdio0 PASS: FreeBSD 15 exact-ABI cross-KLD and symbol contract' \
|
||||
'TC183 correctness/performance PASS from immutable P15-087 QEMU evidence'
|
||||
Reference in New Issue
Block a user