193 lines
6.0 KiB
Python
193 lines
6.0 KiB
Python
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import os
|
|
import platform
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
from datetime import datetime, timezone
|
|
from importlib import metadata as importlib_metadata
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
try:
|
|
import tomllib
|
|
except ImportError: # pragma: no cover
|
|
try:
|
|
import tomli as tomllib # type: ignore[no-redef]
|
|
except ImportError: # pragma: no cover
|
|
tomllib = None # type: ignore[assignment]
|
|
|
|
|
|
_ROOT = Path(__file__).resolve().parent.parent
|
|
|
|
|
|
def _run_cmd(command: list[str]) -> str | None:
|
|
try:
|
|
return subprocess.check_output(
|
|
command,
|
|
text=True,
|
|
stderr=subprocess.DEVNULL,
|
|
).strip()
|
|
except Exception:
|
|
return None
|
|
|
|
|
|
def _read_toml(path: Path) -> dict[str, Any] | None:
|
|
if tomllib is None or not path.exists():
|
|
return None
|
|
try:
|
|
with path.open("rb") as handle:
|
|
return tomllib.load(handle)
|
|
except Exception:
|
|
return None
|
|
|
|
|
|
def _cpu_model() -> str | None:
|
|
if sys.platform == "darwin":
|
|
return (
|
|
_run_cmd(["sysctl", "-n", "machdep.cpu.brand_string"])
|
|
or _run_cmd(["sysctl", "-n", "hw.model"])
|
|
or platform.processor()
|
|
or None
|
|
)
|
|
if sys.platform.startswith("linux"):
|
|
cpuinfo = Path("/proc/cpuinfo")
|
|
if cpuinfo.exists():
|
|
text = cpuinfo.read_text(encoding="utf-8", errors="ignore")
|
|
for pattern in (r"model name\s+:\s+(.+)", r"Hardware\s+:\s+(.+)"):
|
|
match = re.search(pattern, text)
|
|
if match:
|
|
return match.group(1).strip()
|
|
return platform.processor() or None
|
|
if sys.platform.startswith("win"):
|
|
return os.environ.get("PROCESSOR_IDENTIFIER") or platform.processor() or None
|
|
return platform.processor() or None
|
|
|
|
|
|
def _total_memory_bytes() -> int | None:
|
|
if sys.platform == "darwin":
|
|
raw = _run_cmd(["sysctl", "-n", "hw.memsize"])
|
|
return int(raw) if raw and raw.isdigit() else None
|
|
|
|
if sys.platform.startswith("linux"):
|
|
meminfo = Path("/proc/meminfo")
|
|
if meminfo.exists():
|
|
text = meminfo.read_text(encoding="utf-8", errors="ignore")
|
|
match = re.search(r"MemTotal:\s+(\d+)\s+kB", text)
|
|
if match:
|
|
return int(match.group(1)) * 1024
|
|
return None
|
|
|
|
if sys.platform.startswith("win"): # pragma: no cover
|
|
try:
|
|
import ctypes
|
|
|
|
class MEMORYSTATUSEX(ctypes.Structure):
|
|
_fields_ = [
|
|
("dwLength", ctypes.c_ulong),
|
|
("dwMemoryLoad", ctypes.c_ulong),
|
|
("ullTotalPhys", ctypes.c_ulonglong),
|
|
("ullAvailPhys", ctypes.c_ulonglong),
|
|
("ullTotalPageFile", ctypes.c_ulonglong),
|
|
("ullAvailPageFile", ctypes.c_ulonglong),
|
|
("ullTotalVirtual", ctypes.c_ulonglong),
|
|
("ullAvailVirtual", ctypes.c_ulonglong),
|
|
("ullAvailExtendedVirtual", ctypes.c_ulonglong),
|
|
]
|
|
|
|
status = MEMORYSTATUSEX()
|
|
status.dwLength = ctypes.sizeof(MEMORYSTATUSEX)
|
|
ctypes.windll.kernel32.GlobalMemoryStatusEx(ctypes.byref(status))
|
|
return int(status.ullTotalPhys)
|
|
except Exception:
|
|
return None
|
|
|
|
return None
|
|
|
|
|
|
def _cargo_release_profile() -> dict[str, Any] | None:
|
|
cargo_toml = _read_toml(_ROOT / "Cargo.toml")
|
|
if not cargo_toml:
|
|
return None
|
|
profile = cargo_toml.get("profile", {}).get("release")
|
|
return profile if isinstance(profile, dict) else None
|
|
|
|
|
|
def git_info() -> dict[str, Any]:
|
|
"""Best-effort git metadata for reproducible benchmark artifacts."""
|
|
return {
|
|
"commit": _run_cmd(["git", "rev-parse", "HEAD"]),
|
|
"dirty": bool(_run_cmd(["git", "status", "--porcelain"]) or ""),
|
|
"branch": _run_cmd(["git", "rev-parse", "--abbrev-ref", "HEAD"]),
|
|
}
|
|
|
|
|
|
def runtime_info() -> dict[str, Any]:
|
|
return {
|
|
"generated_at_utc": datetime.now(timezone.utc).isoformat(),
|
|
"python_version": sys.version.split()[0],
|
|
"python_implementation": platform.python_implementation(),
|
|
"python_executable": sys.executable,
|
|
"platform": platform.platform(),
|
|
"system": platform.system(),
|
|
"release": platform.release(),
|
|
"machine": platform.machine(),
|
|
"processor": platform.processor() or None,
|
|
"cpu_model": _cpu_model(),
|
|
"cpu_count_logical": os.cpu_count(),
|
|
"total_memory_bytes": _total_memory_bytes(),
|
|
}
|
|
|
|
|
|
def build_info() -> dict[str, Any]:
|
|
return {
|
|
"rustc": _run_cmd(["rustc", "-Vv"]),
|
|
"cargo": _run_cmd(["cargo", "-VV"]) or _run_cmd(["cargo", "-V"]),
|
|
"cargo_release_profile": _cargo_release_profile(),
|
|
"rustflags": os.environ.get("RUSTFLAGS"),
|
|
"cargo_build_rustflags": os.environ.get("CARGO_BUILD_RUSTFLAGS"),
|
|
"maturin_flags": os.environ.get("MATURIN_EXTRA_ARGS"),
|
|
}
|
|
|
|
|
|
def package_versions(*names: str) -> dict[str, str | None]:
|
|
versions: dict[str, str | None] = {}
|
|
for name in names:
|
|
try:
|
|
versions[name] = importlib_metadata.version(name)
|
|
except importlib_metadata.PackageNotFoundError:
|
|
versions[name] = None
|
|
return versions
|
|
|
|
|
|
def file_info(path: str | Path) -> dict[str, Any]:
|
|
file_path = Path(path)
|
|
data = file_path.read_bytes()
|
|
return {
|
|
"path": str(file_path),
|
|
"size_bytes": file_path.stat().st_size,
|
|
"sha256": hashlib.sha256(data).hexdigest(),
|
|
}
|
|
|
|
|
|
def benchmark_metadata(
|
|
suite: str,
|
|
*,
|
|
fixtures: list[str | Path] | None = None,
|
|
extra: dict[str, Any] | None = None,
|
|
) -> dict[str, Any]:
|
|
metadata: dict[str, Any] = {
|
|
"suite": suite,
|
|
"runtime": runtime_info(),
|
|
"git": git_info(),
|
|
"build": build_info(),
|
|
"packages": package_versions("numpy", "ferro-ta"),
|
|
}
|
|
if fixtures:
|
|
metadata["fixtures"] = [file_info(path) for path in fixtures]
|
|
if extra:
|
|
metadata.update(extra)
|
|
return metadata
|