Replace Python numerical kernels with native C execution
This commit is contained in:
1 parent
48da6be21c
commit
3b38f73fe0
227 files changed
+16801
-75499
No files matched your search
@@ -0,0 +1,82 @@
|
||||
"""python -m app.simulation.native_codegen INPUT.xml|json --output-dir DIR"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from dataclasses import replace
|
||||
from hashlib import sha256
|
||||
import json
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
import statistics
|
||||
import time
|
||||
|
||||
from app.main import compile_system_xml_network
|
||||
from app.simulation.backends import simulation_config
|
||||
from .build import build_native
|
||||
from .compiler import compile_native_program
|
||||
from .input import load_input
|
||||
from .runner import execute_native
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("input", type=Path)
|
||||
parser.add_argument("--output-dir", type=Path, required=True)
|
||||
parser.add_argument("--method", choices=("RK45", "BDF"))
|
||||
parser.add_argument("--max-step", type=float)
|
||||
parser.add_argument("--rtol", type=float)
|
||||
parser.add_argument("--runs", type=int, default=3)
|
||||
parser.add_argument("--timeout", type=float, default=300)
|
||||
parser.add_argument("--solve-only", action="store_true")
|
||||
args = parser.parse_args()
|
||||
if args.runs < 1:
|
||||
parser.error("--runs must be positive")
|
||||
out = args.output_dir.resolve()
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
if (out / "summary.json").exists():
|
||||
parser.error("Output directory already contains a completed run; choose a new directory.")
|
||||
started = time.perf_counter()
|
||||
xml, document = load_input(args.input)
|
||||
program = compile_native_program(compile_system_xml_network(document))
|
||||
config = simulation_config(document.simulation)
|
||||
for name in ("method", "max_step", "rtol"):
|
||||
if getattr(args, name) is not None:
|
||||
config = replace(config, **{name: getattr(args, name)})
|
||||
preparation = time.perf_counter()-started
|
||||
(out / "input.xml").write_bytes(xml)
|
||||
build = build_native(program)
|
||||
package = out / "program"
|
||||
package.mkdir(exist_ok=True)
|
||||
for name in (*build.manifest["artifacts"], "manifest.json"):
|
||||
shutil.copy2(build.executable.parent / name, package / name)
|
||||
(out / "model-manifest.json").write_text(json.dumps(build.manifest, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||
rows = []
|
||||
for i in range(args.runs+1):
|
||||
data = execute_native(build, config, document.simulation.sample_step,
|
||||
run_dir=out / ("warmup" if i == 0 else f"run-{i}"),
|
||||
record_samples=not args.solve_only, timeout=args.timeout)
|
||||
row = {k: v for k, v in data.items() if k not in ("series", "final", "finalState")}
|
||||
row["run"] = "warmup" if i == 0 else i
|
||||
rows.append(row)
|
||||
print(json.dumps(row, ensure_ascii=False), flush=True)
|
||||
if not data["success"]:
|
||||
break
|
||||
measured = rows[1:]
|
||||
summary = {
|
||||
"source": str(args.input.resolve()), "sourceSha256": sha256(args.input.read_bytes()).hexdigest(),
|
||||
"xmlSha256": sha256(xml).hexdigest(), "executable": str(package / "model.exe"),
|
||||
"cachedExecutable": str(build.executable),
|
||||
"buildKey": build.manifest["buildKey"], "buildSeconds": build.seconds,
|
||||
"preparationSeconds": preparation, "cacheHit": build.cache_hit,
|
||||
"settings": vars(config), "sampleStep": document.simulation.sample_step,
|
||||
"recordSamples": not args.solve_only, "runs": rows,
|
||||
"success": len(measured) == args.runs and all(row["success"] for row in rows),
|
||||
"medianSolveSeconds": statistics.median(row["solveSeconds"] for row in measured) if measured else None,
|
||||
}
|
||||
(out / "summary.json").write_text(json.dumps(summary, ensure_ascii=False, indent=2), encoding="utf-8")
|
||||
print(json.dumps({k: v for k, v in summary.items() if k != "runs"}, ensure_ascii=False))
|
||||
return 0 if summary["success"] else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in new issue
Block a user