Skip to content

Commit 8279cb0

Browse files
committed
feat: add Markdown summary report generation for CLI
If a link to a directory containing an output HTML report is provided, then the generated table will use Markdown links to the generated reports. This is using different logic to the original DVSim in OpenTitan, because that did not make sense, for two reasons: 1. Reports were relative to the generated Markdown file, but we no longer write a Markdown report to disk. 2. The report structure as a whole has changed. Instead, while we still provide the ability to customise the relative path to report paths, if unspecified (which it is currently), we just print CLI report links relative to the CWD. It might be the case that this doesn't have much value in current DVSim and so should just be removed altogether. Signed-off-by: Alex Jones <alex.jones@lowrisc.org>
1 parent 4376c72 commit 8279cb0

1 file changed

Lines changed: 61 additions & 4 deletions

File tree

src/dvsim/sim/report.py

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,18 @@ class MarkdownReportRenderer:
152152
MAX_TESTS_PER_BUCKET = 5
153153
MAX_RESEEDS_PER_BUCKETED_TEST = 2
154154

155+
def __init__(self, html_link_base: Path | None = None, relative_to: Path | None = None) -> None:
156+
"""Construct a Markdown report renderer.
157+
158+
Args:
159+
html_link_base: The path to the dir that HTML reports are written into, if using HTML
160+
links. If not provided, no HTML links will be generated in the summary report.
161+
relative_to: The path that HTML report links should be relative to.
162+
163+
"""
164+
self.html_link_base = html_link_base
165+
self.relative_to = relative_to
166+
155167
def render(self, summary: SimResultsSummary, outdir: Path | None = None) -> ReportArtifacts:
156168
"""Render a Markdown report of the sim flow results."""
157169
if outdir is not None:
@@ -363,8 +375,53 @@ def render_bucket_summary(self, results: SimFlowResults) -> str:
363375

364376
def render_summary(self, summary: SimResultsSummary) -> ReportArtifacts:
365377
"""Render a Markdown report of a summary of the sim flow results (overall)."""
366-
_summary = summary
367-
return {"report.md": "TODO: Markdown summary report"}
378+
# Generate result metadata information
379+
if summary.top is not None:
380+
report_md = self.render_metadata(
381+
summary.top,
382+
summary.timestamp,
383+
summary.build_seed,
384+
title="Simulation Results (Summary)",
385+
)
386+
else:
387+
report_md = ""
388+
389+
# Generate a table aggregating and mapping block-level reports
390+
table = []
391+
for name, flow_result in summary.flow_results.items():
392+
coverage = "--"
393+
if flow_result.coverage is not None:
394+
average = flow_result.coverage.average
395+
if average is not None:
396+
coverage = f"{average:.2f} %"
397+
file_name = flow_result.block.variant_name()
398+
399+
# Optionally display links to the block HTML reports, relative to the CWD
400+
if self.html_link_base is not None:
401+
relative = self.relative_to if self.relative_to is not None else Path(Path.cwd())
402+
block_report = self.html_link_base / f"{file_name}.html"
403+
html_report_path = block_report.relative_to(relative)
404+
name_link = f"[{name.upper()}]({html_report_path!s})"
405+
else:
406+
name_link = name.upper()
407+
408+
table.append(
409+
{
410+
"Name": name_link,
411+
"Passing": flow_result.passed,
412+
"Total": flow_result.total,
413+
"Pass Rate": f"{flow_result.percent:.2f} %",
414+
"Coverage": coverage,
415+
}
416+
)
417+
418+
if table:
419+
colalign = ("center",) * len(table[0])
420+
report_md += "\n\n" + tabulate(
421+
table, headers="keys", tablefmt="pipe", colalign=colalign
422+
)
423+
424+
return {"report.md": report_md}
368425

369426

370427
def write_report(files: ReportArtifacts, root: Path) -> None:
@@ -413,7 +470,7 @@ def gen_reports(summary: SimResultsSummary, path: Path) -> None:
413470
for renderer in (JsonReportRenderer(), HtmlReportRenderer()):
414471
renderer.render(summary, outdir=path)
415472

416-
renderer = MarkdownReportRenderer()
473+
renderer = MarkdownReportRenderer(path)
417474

418475
# Per-block CLI results are displayed to the `INFO` log
419476
if log.isEnabledFor(log.INFO):
@@ -422,7 +479,7 @@ def gen_reports(summary: SimResultsSummary, path: Path) -> None:
422479
log.info("[results]: [%s]", block_name)
423480
cli_block = renderer.render_block(flow_result)
424481
display_report(cli_block, sink=log.log_raw)
425-
log.log_raw("\n")
482+
log.log_raw("\n" if summary.top is None else "\n\n")
426483

427484
# Summary CLI results are displayed to stdout, so long as this is a primary cfg
428485
if summary.top is not None:

0 commit comments

Comments
 (0)