|
|
|
|
|
from __future__ import annotations |
|
|
|
|
|
import json |
|
|
from pathlib import Path |
|
|
|
|
|
import matplotlib |
|
|
matplotlib.use("Agg") |
|
|
import matplotlib.pyplot as plt |
|
|
import pandas as pd |
|
|
import sqlite3 |
|
|
|
|
|
|
|
|
WNS_KEYS = [ |
|
|
"timing__setup__wns", |
|
|
"timing__setup__WNS", |
|
|
"finish__timing__setup__wns", |
|
|
"timing__setup__ws", |
|
|
"finish__timing__setup__ws", |
|
|
"route__timing__setup__ws", |
|
|
"cts__timing__setup__ws", |
|
|
"detailedplace__timing__setup__ws", |
|
|
"floorplan__timing__setup__ws", |
|
|
"globalplace__timing__setup__ws", |
|
|
"globalroute__timing__setup__ws", |
|
|
"placeopt__timing__setup__ws", |
|
|
] |
|
|
|
|
|
AREA_KEYS = [ |
|
|
"finish__design__die__area", |
|
|
"globalroute__design__die__area", |
|
|
"placeopt__design__die__area", |
|
|
"detailedplace__design__die__area", |
|
|
"floorplan__design__die__area", |
|
|
"design__die__area", |
|
|
] |
|
|
|
|
|
|
|
|
def pick_first(metrics: dict, keys: list[str]) -> float | None: |
|
|
for k in keys: |
|
|
if k in metrics: |
|
|
try: |
|
|
return float(metrics[k]) |
|
|
except Exception: |
|
|
return None |
|
|
lower = {kk.lower(): kk for kk in metrics.keys()} |
|
|
for k in keys: |
|
|
kk = lower.get(k.lower()) |
|
|
if kk: |
|
|
try: |
|
|
return float(metrics[kk]) |
|
|
except Exception: |
|
|
return None |
|
|
return None |
|
|
|
|
|
|
|
|
def load_metrics(mj: str | None) -> dict | None: |
|
|
if not mj: |
|
|
return None |
|
|
try: |
|
|
return json.loads(mj) |
|
|
except Exception: |
|
|
return None |
|
|
|
|
|
|
|
|
def main() -> None: |
|
|
import argparse |
|
|
|
|
|
p = argparse.ArgumentParser(description="Generate Pareto scatter (area vs WNS)") |
|
|
p.add_argument("--db", default="runs/sweep_finish.sqlite", help="SQLite database path") |
|
|
p.add_argument("--out", default="runs/sweep_finish/plots/pareto_area_vs_wns", help="Output path without extension") |
|
|
args = p.parse_args() |
|
|
|
|
|
con = sqlite3.connect(args.db) |
|
|
df = pd.read_sql_query("SELECT * FROM trials", con) |
|
|
con.close() |
|
|
|
|
|
rows = [] |
|
|
for _, row in df.iterrows(): |
|
|
metrics = load_metrics(row.get("metrics_json")) |
|
|
if not metrics: |
|
|
continue |
|
|
wns = pick_first(metrics, WNS_KEYS) |
|
|
area = pick_first(metrics, AREA_KEYS) |
|
|
if wns is None or area is None: |
|
|
continue |
|
|
rows.append({"wns": wns, "area": area, "fidelity": row.get("fidelity", "unknown")}) |
|
|
|
|
|
if not rows: |
|
|
print("No points with both WNS and area found.") |
|
|
return |
|
|
|
|
|
plot_df = pd.DataFrame(rows) |
|
|
colors = { |
|
|
"synth": "#999999", |
|
|
"place": "#4B8BBE", |
|
|
"route": "#306998", |
|
|
"finish": "#E07B39", |
|
|
"unknown": "#666666", |
|
|
} |
|
|
markers = { |
|
|
"synth": "o", |
|
|
"place": "s", |
|
|
"route": "^", |
|
|
"finish": "D", |
|
|
"unknown": "o", |
|
|
} |
|
|
|
|
|
fig, ax = plt.subplots(figsize=(6.4, 4.6)) |
|
|
for fid, group in plot_df.groupby("fidelity"): |
|
|
ax.scatter( |
|
|
group["area"], |
|
|
group["wns"], |
|
|
label=fid, |
|
|
color=colors.get(fid, "#666666"), |
|
|
marker=markers.get(fid, "o"), |
|
|
alpha=0.75, |
|
|
edgecolors="none", |
|
|
) |
|
|
|
|
|
ax.axhline(0.0, color="#333333", linewidth=0.8, linestyle="--") |
|
|
ax.set_xlabel("Die area (um^2)") |
|
|
ax.set_ylabel("WNS (ns)") |
|
|
ax.set_title("Area vs WNS (Pareto scatter)") |
|
|
ax.legend(frameon=False, fontsize=8, loc="best") |
|
|
fig.tight_layout() |
|
|
|
|
|
out_base = Path(args.out) |
|
|
out_base.parent.mkdir(parents=True, exist_ok=True) |
|
|
fig.savefig(out_base.with_suffix(".png"), dpi=300) |
|
|
fig.savefig(out_base.with_suffix(".pdf")) |
|
|
plt.close(fig) |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
main() |
|
|
|