Package portable Linux runtime and verify Google CPU search
This commit is contained in:
1 parent
e3558a0104
commit
0b56ab553c
22 files changed
+1585
-16
No files matched your search
@@ -0,0 +1,106 @@
|
||||
"""Exercise a real Linux distribution worker on CPU, outside its build directory.
|
||||
|
||||
This checks genuine Google inference and origin-relative runtime packaging.
|
||||
It does not certify GPU operation, older processors or a Linux desktop.
|
||||
"""
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import subprocess
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
|
||||
def sha256(path):
|
||||
with path.open("rb") as stream:
|
||||
return hashlib.file_digest(stream, "sha256").hexdigest()
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--worker", type=Path, required=True)
|
||||
parser.add_argument("--models", type=Path, required=True)
|
||||
parser.add_argument("--output", type=Path, required=True)
|
||||
parser.add_argument("--baseline", action="store_true")
|
||||
args = parser.parse_args()
|
||||
if os.name != "posix" or not Path("/proc/self/exe").exists():
|
||||
parser.error("Run this check natively on Linux")
|
||||
# Reuse exactly the staging verifier: hashes and bounded inventory names
|
||||
# must agree with what enters a distribution.
|
||||
from stage_runtime import verify_runtime
|
||||
dependencies = verify_runtime(args.worker.resolve(), True)
|
||||
manifest = json.loads(Path(__file__).with_name("model-manifest.json").read_text())
|
||||
model = args.models.resolve() / manifest["files"][0]["path"]
|
||||
if model.stat().st_size != manifest["files"][0]["bytes"] or sha256(model) != manifest["files"][0]["sha256"]:
|
||||
raise RuntimeError("Google model checksum mismatch")
|
||||
with tempfile.TemporaryDirectory(prefix="searchi-linux-smoke-") as temporary:
|
||||
target = Path(temporary)
|
||||
copied = []
|
||||
for source in [args.worker.resolve(), *dependencies]:
|
||||
# Only exact approved CPU module names are omitted. Core libraries
|
||||
# and GPU support remain present in the baseline extraction.
|
||||
if args.baseline and source.name.startswith("libggml-cpu-") and source.name != "libggml-cpu-x64.so":
|
||||
continue
|
||||
destination = target / source.name
|
||||
shutil.copy2(source, destination)
|
||||
if sha256(destination) != sha256(source):
|
||||
raise RuntimeError("Extracted runtime checksum mismatch")
|
||||
copied.append(source.name)
|
||||
worker = target / args.worker.name
|
||||
dynamic = subprocess.check_output(["readelf", "-d", str(worker)], text=True)
|
||||
if "libvulkan" in dynamic or "libggml-vulkan" in dynamic:
|
||||
raise RuntimeError("Worker requires Vulkan at process startup; CPU fallback cannot work without the loader")
|
||||
if "$ORIGIN" not in dynamic:
|
||||
raise RuntimeError("Worker lacks origin-relative runtime lookup")
|
||||
environment = dict(os.environ, SEARCHI_FORCE_CPU="1", GGML_DISABLE_VULKAN="1")
|
||||
environment.pop("LD_LIBRARY_PATH", None)
|
||||
environment.pop("GGML_BACKEND_PATH", None)
|
||||
started = time.perf_counter()
|
||||
process = subprocess.Popen([str(worker), "--model", str(model), "--threads", "1", "--device", "cpu"],
|
||||
cwd=target, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
text=True, encoding="utf-8", env=environment)
|
||||
try:
|
||||
stdout, stderr = process.communicate(json.dumps({"op": "code_query", "text": "retry failed requests with exponential backoff"}) + "\n", timeout=180)
|
||||
except BaseException:
|
||||
process.kill()
|
||||
process.wait(timeout=10)
|
||||
raise
|
||||
elapsed_ms = (time.perf_counter() - started) * 1000
|
||||
if process.returncode:
|
||||
raise RuntimeError(f"Worker failed ({process.returncode}): {stderr[-4096:]}")
|
||||
lines = [json.loads(line) for line in stdout.splitlines()]
|
||||
if len(lines) != 2:
|
||||
raise RuntimeError("Unexpected worker protocol output")
|
||||
hello, result = lines
|
||||
if not hello.get("ready") or hello.get("device") != "cpu" or not result.get("ok") or result.get("device") != "cpu":
|
||||
raise RuntimeError("Expected genuine ready CPU inference")
|
||||
if hello.get("vulkan_module_loaded"):
|
||||
raise RuntimeError("CPU check loaded a Vulkan provider")
|
||||
vectors = result.get("vectors")
|
||||
vector = vectors[0] if isinstance(vectors, list) and len(vectors) == 1 else None
|
||||
if not isinstance(vector, list) or len(vector) != 768 or not all(isinstance(value, (int, float)) and math.isfinite(value) for value in vector):
|
||||
raise RuntimeError("Invalid Google embedding vector")
|
||||
norm = math.sqrt(sum(value * value for value in vector))
|
||||
if abs(norm - 1) > 0.001:
|
||||
raise RuntimeError("Google vector is not normalized")
|
||||
module = hello.get("cpu_backend_module", "")
|
||||
if args.baseline and module != "libggml-cpu-x64.so":
|
||||
raise RuntimeError(f"Baseline extraction selected unexpected CPU module: {module}")
|
||||
evidence = {"platform": "linux", "cpu_only": True, "baseline_only_extraction": args.baseline,
|
||||
"worker_sha256": sha256(args.worker), "model_sha256": sha256(model),
|
||||
"files": sorted(copied), "hello": hello, "dimensions": len(vector), "norm": norm,
|
||||
"startup_query_exit_ms": elapsed_ms,
|
||||
"timing_scope": "single diagnostic smoke sample; not a performance benchmark",
|
||||
"worker_dynamic_section": dynamic,
|
||||
"limitations": ["GPU untested", "older physical CPUs untested", "desktop and installer untested", "system-loader absence not physically exercised"]}
|
||||
args.output.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.output.write_text(json.dumps(evidence, indent=2) + "\n", encoding="utf-8")
|
||||
print(json.dumps({"ready": True, "cpu_module": module, "dimensions": 768, "baseline": args.baseline}))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user