mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
feat: refactor NMI interface and enhance performance logging
- Updated NMI interface references from to in multiple files for consistency. - Added a new script to convert UART performance records into structured JSON format. - Enhanced the README documentation to include details about the new performance log parser. - Implemented tests for the new performance log parser to ensure correct functionality. - Added new test cases for DMA error handling and SDRAM data integrity to improve coverage. - Updated existing test cases to accommodate changes in the NMI interface and added performance metrics. - Refactored bus fault testbench to include fault code checks and improved error handling. - Adjusted memory map generation and pin mapping tests to reflect recent changes in RTL structure.
This commit is contained in:
61 files changed
+2539
-433
No files matched your search
@@ -13,6 +13,11 @@ FatFs R0.16 archive. It verifies the archive, GitHub authentication, release
|
||||
absence, and the published asset checksum before reporting the checksum-pinned
|
||||
URL.
|
||||
|
||||
`parse_performance_log.py` converts the `APP=benchmark` UART `PERF` records
|
||||
into `meta/performance.json`. The parser requires the terminal
|
||||
`PERF_BENCHMARK_PASS` marker and deliberately does not alter the common
|
||||
simulation success-marker policy.
|
||||
|
||||
Update or add tests in [`../tests`](../tests) for script behavior. Run
|
||||
`ruff check .` and `python3 -m pytest -q`; build-flow changes also require the
|
||||
relevant dry-run or regression profile from [`AGENTS.md`](../AGENTS.md).
|
||||
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Parse reproducible SoC performance benchmark output into structured JSON."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
PERF_PREFIX = "PERF "
|
||||
PASS_MARKER = "PERF_BENCHMARK_PASS"
|
||||
FAIL_PREFIX = "PERF_FAIL"
|
||||
REQUIRED_FIELDS = {
|
||||
"region",
|
||||
"op",
|
||||
"words",
|
||||
"checksum",
|
||||
"mgmt_wait",
|
||||
"native_wait",
|
||||
"sdram_wait",
|
||||
"psram_wait",
|
||||
"flash_wait",
|
||||
"dma_wait",
|
||||
}
|
||||
TOKEN = re.compile(r"([a-z_]+)=([^\s]+)")
|
||||
|
||||
|
||||
def parse_number(value: str) -> int:
|
||||
return int(value, 0)
|
||||
|
||||
|
||||
def parse_log(content: str) -> dict[str, object]:
|
||||
samples: list[dict[str, object]] = []
|
||||
for line in content.splitlines():
|
||||
if not line.startswith(PERF_PREFIX):
|
||||
continue
|
||||
fields = {name: value for name, value in TOKEN.findall(line)}
|
||||
missing = REQUIRED_FIELDS.difference(fields)
|
||||
if missing:
|
||||
raise ValueError(f"performance sample is missing fields: {sorted(missing)}")
|
||||
sample: dict[str, object] = {
|
||||
"region": fields["region"],
|
||||
"operation": fields["op"],
|
||||
"words": parse_number(fields["words"]),
|
||||
"checksum": int(fields["checksum"], 16),
|
||||
}
|
||||
for counter in sorted(REQUIRED_FIELDS - {"region", "op", "words", "checksum"}):
|
||||
sample[counter] = parse_number(fields[counter])
|
||||
samples.append(sample)
|
||||
passed = PASS_MARKER in content
|
||||
failure_marker = any(line.startswith(FAIL_PREFIX) for line in content.splitlines())
|
||||
return {
|
||||
"schema_version": 1,
|
||||
"status": "passed" if passed and samples and not failure_marker else "failed",
|
||||
"failure_marker": failure_marker,
|
||||
"pass_marker": passed,
|
||||
"samples": samples,
|
||||
}
|
||||
|
||||
|
||||
def atomic_write(path: Path, content: str) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
temporary = path.with_suffix(path.suffix + ".tmp")
|
||||
temporary.write_text(content, encoding="utf-8")
|
||||
temporary.replace(path)
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--log", type=Path, required=True)
|
||||
parser.add_argument("--output", type=Path, required=True)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
args = parse_args()
|
||||
report = parse_log(args.log.read_text(encoding="utf-8", errors="replace"))
|
||||
atomic_write(args.output, json.dumps(report, indent=2, sort_keys=True) + "\n")
|
||||
if report["status"] != "passed":
|
||||
print("performance benchmark did not emit a complete passing report", file=sys.stderr)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in new issue
Block a user