104 lines
3.1 KiB
Python
104 lines
3.1 KiB
Python
# DESCRIPTION: Verilator: CI script for 'rtlmeter.yml' PR results
|
|
#
|
|
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
|
|
###############################################################################
|
|
# This script runs with the venv of **RTLMeter**
|
|
###############################################################################
|
|
|
|
import sys
|
|
import json
|
|
import tabulate
|
|
from typing import Final, List
|
|
|
|
tabulate.PRESERVE_WHITESPACE = True
|
|
tabulate.MIN_PADDING = 0
|
|
|
|
_ASCII_TABLE_FORMAT: Final = tabulate.TableFormat(
|
|
lineabove=tabulate.Line("╒═", "═", "═╤═", "═╕"),
|
|
linebelowheader=tabulate.Line("╞═", "═", "═╪═", "═╡"),
|
|
linebelow=tabulate.Line("╘═", "═", "═╧═", "═╛"),
|
|
headerrow=tabulate.DataRow("│ ", " │ ", " │"),
|
|
datarow=tabulate.DataRow("│ ", " │ ", " │"),
|
|
linebetweenrows=None,
|
|
padding=0,
|
|
with_header_hide=None,
|
|
)
|
|
|
|
|
|
def printTable(table: List[List[str]], **kwargs) -> None:
|
|
print(tabulate.tabulate(table, tablefmt=_ASCII_TABLE_FORMAT, **kwargs))
|
|
|
|
|
|
# fmt: off
|
|
stepMetric = (
|
|
("verilate", "elapsed"),
|
|
("verilate", "memory"),
|
|
("verilate", "cpu"),
|
|
("cppbuild", "elapsed"),
|
|
("cppbuild", "memory"),
|
|
("cppbuild", "cpu"),
|
|
("cppbuild", "codeSize"),
|
|
("execute", "speed"),
|
|
("execute", "clocks"),
|
|
("execute", "memory"),
|
|
("execute", "cpu"),
|
|
)
|
|
# fmt: on
|
|
|
|
table = []
|
|
|
|
for ref, cmp in zip(sys.argv[1::2], sys.argv[2::2]):
|
|
with open(ref, "r", encoding="utf-8") as f:
|
|
ref_json = json.load(f)[0]
|
|
with open(cmp, "r", encoding="utf-8") as f:
|
|
cmp_json = json.load(f)
|
|
if table:
|
|
table.append(tabulate.SEPARATING_LINE)
|
|
runName = ref_json["runName"]
|
|
for step, metric in stepMetric:
|
|
if step not in cmp_json:
|
|
continue
|
|
data = cmp_json[step]
|
|
if metric not in data:
|
|
continue
|
|
data = data[metric]
|
|
minGain = float("inf")
|
|
maxGain = float("-inf")
|
|
meanGain = 1
|
|
count = 0
|
|
for _, _, _, _, _, g, _ in data["table"]:
|
|
minGain = min(minGain, g)
|
|
maxGain = max(maxGain, g)
|
|
meanGain *= g
|
|
count += 1
|
|
meanGain = meanGain**(1 / count)
|
|
|
|
if metric == "clocks":
|
|
# Clock cycles should match exactly
|
|
status = "❌" if minGain != 1 or maxGain != 1 else "✅"
|
|
else:
|
|
# Otherwise use some arbitrary brackets
|
|
status = "❌"
|
|
if (meanGain > 0.95):
|
|
status = "⚠️"
|
|
if (meanGain > 0.98):
|
|
status = "✅"
|
|
if (meanGain > 1.02):
|
|
status = "💡"
|
|
if (meanGain > 1.05):
|
|
status = "⭐"
|
|
|
|
table.append([
|
|
runName, step, ref_json["metrics"][metric]["header"], f"{meanGain:.2f}x {status} ",
|
|
f"{minGain:.2f}x", f"{maxGain:.2f}x"
|
|
])
|
|
|
|
printTable(
|
|
table,
|
|
headers=("Run", "Step", "Metric", "Improvement", "Min", "Max"),
|
|
colalign=("left", "left", "left", "right", "right", "right"),
|
|
disable_numparse=True,
|
|
)
|