Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions src/dvsim/job/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
from pathlib import Path
from typing import TYPE_CHECKING, ClassVar

from tabulate import tabulate

from dvsim.job.data import JobSpec, WorkspaceConfig
from dvsim.job.status import JobStatus
from dvsim.job.time import JobTime
Expand Down Expand Up @@ -817,7 +815,6 @@ def _set_attrs(self) -> None:

# Keep track of coverage results, once the job is finished.
self.cov_total = ""
self.cov_results = ""
self.cov_results_dict = {}

def post_finish(self) -> Callable[[JobStatus], None]:
Expand All @@ -838,10 +835,6 @@ def callback(status: JobStatus) -> None:
cov_report_path=self.cov_report_txt,
)

colalign = ("center",) * len(results[0])
self.cov_results = tabulate(
results, headers="firstrow", tablefmt="pipe", colalign=colalign
)
for tup in zip(*results, strict=False):
self.cov_results_dict[tup[0]] = tup[1]

Expand Down
8 changes: 7 additions & 1 deletion src/dvsim/sim/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ class SimFlowResults(BaseModel):
timestamp: datetime
"""Timestamp for when the test ran."""

build_seed: int | None
"""Build seed."""

stages: Mapping[str, TestStage]
"""Results per test stage."""
coverage: CoverageMetrics | None
Expand Down Expand Up @@ -244,7 +247,7 @@ class SimResultsSummary(BaseModel):

model_config = ConfigDict(frozen=True, extra="forbid")

top: IPMeta
top: IPMeta | None
"""Meta data for the top level config."""

version: str | None
Expand All @@ -253,6 +256,9 @@ class SimResultsSummary(BaseModel):
timestamp: datetime
"""Run time stamp."""

build_seed: int | None
"""Build seed."""

flow_results: Mapping[str, SimFlowResults]
"""Flow results."""

Expand Down
60 changes: 35 additions & 25 deletions src/dvsim/sim/flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,7 @@ def gen_results(self, results: Sequence[CompletedJobStatus]) -> None:
reports_dir = Path(self.scratch_base_path) / "reports"
commit = git_commit_hash(path=repo_root)
url = git_https_url_with_commit(path=repo_root)
build_seed = self.build_seed if not self.run_only else None

try:
dvsim_version = version("dvsim").strip()
Expand Down Expand Up @@ -641,35 +642,41 @@ def gen_results(self, results: Sequence[CompletedJobStatus]) -> None:

self.errors_seen |= item.errors_seen

# The timestamp for this run has been taken with `utcnow()` and is
# stored in a custom format. Store it in standard ISO format with
# explicit timezone annotation.
timestamp = (
datetime.strptime(self.timestamp, "%Y%m%d_%H%M%S")
.replace(tzinfo=timezone.utc)
.isoformat()
)

# If this is a primary config, attach the "top" information. Even if it isn't,
# we still want to potentially generate a summary to attach other metadata.
top = None
if self.is_primary_cfg:
# The timestamp for this run has been taken with `utcnow()` and is
# stored in a custom format. Store it in standard ISO format with
# explicit timezone annotation.
timestamp = (
datetime.strptime(self.timestamp, "%Y%m%d_%H%M%S")
.replace(tzinfo=timezone.utc)
.isoformat()
top = IPMeta(
name=self.name,
variant=self.variant,
commit=commit,
branch=self.branch,
url=url,
)

results_summary = SimResultsSummary(
top=IPMeta(
name=self.name,
variant=self.variant,
commit=commit,
branch=self.branch,
url=url,
),
version=dvsim_version,
timestamp=timestamp,
flow_results=all_flow_results,
report_path=reports_dir,
)
results_summary = SimResultsSummary(
top=top,
version=dvsim_version,
timestamp=timestamp,
build_seed=build_seed,
flow_results=all_flow_results,
report_path=reports_dir,
)

# Generate the summary JSON/HTML report to the report area.
gen_summary_report(
summary=results_summary,
path=reports_dir,
)
# Generate all the JSON/HTML reports to the report area.
gen_summary_report(
summary=results_summary,
path=reports_dir,
)

def _gen_json_results(
self,
Expand Down Expand Up @@ -704,6 +711,8 @@ def _gen_json_results(
)
tool = ToolMeta(name=self.tool.lower(), version="unknown")

build_seed = self.build_seed if not self.run_only else None

# --- Build stages only from testpoints that have at least one executed test ---
stage_to_tps: defaultdict[str, dict[str, Testpoint]] = defaultdict(dict)

Expand Down Expand Up @@ -803,6 +812,7 @@ def make_test_result(tr) -> TestResult | None:
block=block,
tool=tool,
timestamp=timestamp,
build_seed=build_seed,
stages=stages,
coverage=coverage_model,
failed_jobs=failures,
Expand Down
32 changes: 17 additions & 15 deletions src/dvsim/sim/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@ def gen_block_report(results: SimFlowResults, path: Path, version: str | None =
)


def make_static_html_report_content(path: Path) -> None:
"""Generate static style CSS/JS files for HTML reporting."""
for name in (
"css/style.css",
"css/bootstrap.min.css",
"js/bootstrap.bundle.min.js",
"js/htmx.min.js",
):
output = path / name
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(render_static(path=name))


def gen_summary_report(summary: SimResultsSummary, path: Path) -> None:
"""Generate a summary report.

Expand All @@ -60,22 +73,11 @@ def gen_summary_report(summary: SimResultsSummary, path: Path) -> None:
(path / "index.json").write_text(summary.model_dump_json())

# Generate style CSS
for name in (
"css/style.css",
"css/bootstrap.min.css",
"js/bootstrap.bundle.min.js",
"js/htmx.min.js",
):
output = path / name
make_static_html_report_content(path)

output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(render_static(path=name))

# HTMX wrapper
(path / "index.html").write_text(render_template(path="reports/wrapper.html"))

# Generate HTML report
(path / "summary.html").write_text(
# Generate HTML report. Regardless of whether we have a top or there is only
# one block, we always generate a summary page for now.
(path / "index.html").write_text(
render_template(
path="reports/summary_report.html",
data={
Expand Down
9 changes: 9 additions & 0 deletions src/dvsim/templates/reports/block_report.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
# SPDX-License-Identifier: Apache-2.0

-->
{% extends "reports/wrapper.html" %}
{% set block = results.block %}
{% set tool = results.tool %}
{% set build_seed = results.build_seed %}
{% set timestamp = results.timestamp %}
{% set stages = results.stages %}
{% set coverage = results.coverage %}
{% set failed_jobs = results.failed_jobs %}
{% block content %}
<div class="container-md">
<div class="row">
<div class="col">
Expand Down Expand Up @@ -56,6 +59,11 @@ <h2>Simulation Results: {{ block.variant_name(sep='/') }}</h2>
<span class="badge text-bg-secondary">
Tool: {{ tool.name }} [{{ tool.version }}]
</span>
{% if build_seed %}
<span class="badge text-bg-secondary">
Build seed: {{ build_seed }}
</span>
{% endif %}
</div>

{% macro coverage_stat(cov, kind, label) %}
Expand Down Expand Up @@ -235,3 +243,4 @@ <h3>Error Messages</h3>
</div>
{% endif %}
</div>
{% endblock %}
32 changes: 22 additions & 10 deletions src/dvsim/templates/reports/summary_report.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@
# SPDX-License-Identifier: Apache-2.0

-->
{% extends "reports/wrapper.html" %}
{% set top = summary.top %}
{% set first_result = summary.flow_results.values() | list | first %}
{% set meta_info = top if top is not none else first_result.block %}
{% set timestamp = summary.timestamp %}
{% set version = summary.version %}
{% set build_seed = summary.build_seed %}
{% set title = "Simulation Results: %s"|format(top.name) if top else "Simulation Results (Summary)" %}
{% block content %}
<div class="container-md">
<div class="row">
<div class="col">
Expand All @@ -27,7 +33,7 @@

<div class="row py-3">
<div class="col">
<h2>Simulation Results: {{ top.name }}</h2>
<h2>{{ title }}</h2>
</div>
</div>

Expand All @@ -44,14 +50,19 @@ <h2>Simulation Results: {{ top.name }}</h2>
</a>
{% endif %}
<a class="badge text-bg-secondary link-underline link-underline-opacity-0"
href="{{ top.url }}">
sha: {{ top.commit[:7] }}
href="{{ meta_info.url }}">
sha: {{ meta_info.commit[:7] }}
</a>
<a class="badge text-bg-secondary link-underline link-underline-opacity-0"
href="index.json">json</a>
<span class="badge text-bg-secondary">
Branch: {{ top.branch }}
Branch: {{ meta_info.branch }}
</span>
{% if build_seed %}
<span class="badge text-bg-secondary">
Build seed: {{ build_seed }}
</span>
{% endif %}
</div>
</div>

Expand Down Expand Up @@ -99,12 +110,12 @@ <h2>Simulation Results: {{ top.name }}</h2>
{% for block_name in summary.flow_results.keys()|sort %}
{% set flow = summary.flow_results[block_name] %}
<tr>
<td class="btn"
hx-get="{{ block_name }}.html"
hx-trigger="click"
hx-push-url="true"
hx-target="#report-content">
{{ flow.block.variant_name(sep='/') | upper }}
<td>
<a href="{{ block_name }}.html" style="text-decoration:none; color:black">
<div style="height:100%; width:100%">
{{ flow.block.variant_name(sep='/') | upper }}
</div>
</a>
</td>
<td>{{ flow.passed }}</td>
<td>{{ flow.total }}</td>
Expand Down Expand Up @@ -132,3 +143,4 @@ <h2>Simulation Results: {{ top.name }}</h2>
</div>
</div>
</div>
{% endblock %}
47 changes: 24 additions & 23 deletions src/dvsim/templates/reports/wrapper.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,31 @@
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Simulation Results</title>
<script src="js/htmx.min.js"></script>
<script>
htmx.config.selfRequestsOnly = false;
</script>
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
</head>
<body>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Simulation Results</title>
<script src="js/htmx.min.js"></script>
<script>
htmx.config.selfRequestsOnly = false;
</script>
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
</head>
<body>

<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="#">Nightly Reports</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</nav>
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
{# TODO: don't hardcode name, get it from a config file #}
<a class="navbar-brand" href="/">Nightly Reports</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</nav>

<div id="report-content" hx-get="summary.html" hx-trigger="load" hx-request='{"noHeaders": true}' hx-target="#report-content"></div>
{% block content %}{% endblock %}

<script src="js/bootstrap.bundle.min.js"></script>
</body>
<script src="js/bootstrap.bundle.min.js"></script>
</body>
</html>
Loading